getUnifiedSyncMetadata method
Gets unified sync metadata across all entities for the specified user.
This method aggregates sync metadata from all registered entity managers into a single, comprehensive view. This provides a complete picture of the user's sync state across all entity types, addressing the issue of fragmented per-entity metadata.
The returned metadata includes:
- Global sync status and timestamps
- Entity-specific counts, hashes, and pending changes
- Device information and conflict tracking
Example:
final metadata = await Datum.instance.getUnifiedSyncMetadata('user123');
if (metadata != null) {
print('Last sync: ${metadata.lastSyncTime}');
print('Total pending changes: ${metadata.totalPendingChanges}');
print('Entity counts: ${metadata.entityCounts}');
}
Implementation
Future<DatumSyncMetadata?> getUnifiedSyncMetadata(String userId) async {
if (_managers.isEmpty) return null;
// Get metadata from all managers
final allMetadata = <DatumSyncMetadata>[];
for (final manager in _managers.allManagers) {
try {
final metadata = await manager.localAdapter.getSyncMetadata(userId);
if (metadata != null) {
allMetadata.add(metadata);
}
} catch (e) {
logger.debug('Failed to get sync metadata from ${manager.runtimeType}: $e');
}
}
if (allMetadata.isEmpty) return null;
// Find the most recent metadata as the base
allMetadata.sort((a, b) {
final aTime = a.lastSyncTime ?? DateTime.fromMillisecondsSinceEpoch(0);
final bTime = b.lastSyncTime ?? DateTime.fromMillisecondsSinceEpoch(0);
return bTime.compareTo(aTime);
});
final baseMetadata = allMetadata.first;
// Aggregate entity counts from all metadata
final aggregatedEntityCounts = <String, DatumEntitySyncDetails>{};
for (final metadata in allMetadata) {
if (metadata.entityCounts != null) {
aggregatedEntityCounts.addAll(metadata.entityCounts!);
}
}
// Aggregate device information
final allDevices = <String, DateTime>{};
for (final metadata in allMetadata) {
if (metadata.devices != null) {
allDevices.addAll(metadata.devices!);
}
}
// Determine overall sync status
final hasAnyFailed = allMetadata.any((m) => m.syncStatus == SyncStatus.failed);
final hasAnySyncing = allMetadata.any((m) => m.syncStatus == SyncStatus.syncing);
final hasAnyConflicts = allMetadata.any((m) => m.hasConflicts);
final hasAnyPending = allMetadata.any((m) => m.totalPendingChanges > 0);
SyncStatus overallStatus;
if (hasAnyFailed) {
overallStatus = SyncStatus.failed;
} else if (hasAnySyncing) {
overallStatus = SyncStatus.syncing;
} else if (hasAnyConflicts) {
overallStatus = SyncStatus.conflict;
} else if (hasAnyPending) {
overallStatus = SyncStatus.pending;
} else if (baseMetadata.isNeverSynced) {
overallStatus = SyncStatus.neverSynced;
} else {
overallStatus = SyncStatus.synced;
}
// Aggregate conflict count
final totalConflicts = allMetadata.fold<int>(0, (sum, m) => sum + m.conflictCount);
return baseMetadata.copyWith(
entityCounts: aggregatedEntityCounts.isNotEmpty ? aggregatedEntityCounts : null,
devices: allDevices.isNotEmpty ? allDevices : null,
syncStatus: overallStatus,
conflictCount: totalConflicts,
);
}