DatumSyncMetadata.fromMap constructor

DatumSyncMetadata.fromMap(
  1. Map<String, dynamic> json
)

Creates SyncMetadata from JSON. Supports both camelCase (Dart convention) and snake_case (database convention) keys.

Implementation

factory DatumSyncMetadata.fromMap(Map<String, dynamic> json) {
  try {
    // Helper function to get value with fallback from camelCase to snake_case
    dynamic getValue(String camelKey, String snakeKey, {bool required = false}) {
      var value = json[camelKey] ?? json[snakeKey];
      if (required && value == null) {
        throw FormatException('Required field "$camelKey" is missing from sync metadata');
      }
      return value;
    }

    // Parse DateTime with error handling
    DateTime? parseDateTime(dynamic value) {
      if (value == null) return null;
      if (value is String) {
        try {
          return DateTime.parse(value);
        } catch (e) {
          throw FormatException('Invalid date format for field: $value');
        }
      }
      throw FormatException('Date field must be a string, got: ${value.runtimeType}');
    }

    // Parse devices map
    Map<String, DateTime>? parseDevices(dynamic devicesValue) {
      if (devicesValue == null) return null;
      if (devicesValue is Map<String, dynamic>) {
        return devicesValue.map((key, value) {
          try {
            return MapEntry(key, DateTime.parse(value as String));
          } catch (e) {
            throw FormatException('Invalid date format in devices map for key "$key": $value');
          }
        });
      }
      throw FormatException('Devices field must be a map, got: ${devicesValue.runtimeType}');
    }

    // Parse entity counts
    Map<String, DatumEntitySyncDetails>? parseEntityCounts(dynamic entityCountsValue) {
      if (entityCountsValue == null) return null;
      if (entityCountsValue is Map<String, dynamic>) {
        return entityCountsValue.map((key, value) {
          try {
            return MapEntry(key, DatumEntitySyncDetails.fromJson(value as Map<String, dynamic>));
          } catch (e) {
            throw FormatException('Invalid entity counts format for key "$key": $e');
          }
        });
      }
      throw FormatException('Entity counts field must be a map, got: ${entityCountsValue.runtimeType}');
    }

    // Parse sync status
    SyncStatus parseSyncStatus(dynamic statusValue) {
      if (statusValue == null) return SyncStatus.neverSynced;
      if (statusValue is String) {
        return SyncStatus.values.firstWhere(
          (e) => e.toString() == 'SyncStatus.$statusValue',
          orElse: () => SyncStatus.neverSynced,
        );
      }
      throw FormatException('Sync status must be a string, got: ${statusValue.runtimeType}');
    }

    return DatumSyncMetadata(
      userId: getValue('userId', 'user_id', required: true) as String,
      lastSyncTime: parseDateTime(getValue('lastSyncTime', 'last_sync_time')),
      lastSuccessfulSyncTime: parseDateTime(getValue('lastSuccessfulSyncTime', 'last_successful_sync_time')),
      dataHash: getValue('dataHash', 'data_hash') as String?,
      deviceId: getValue('deviceId', 'device_id') as String?,
      devices: parseDevices(getValue('devices', 'devices')),
      customMetadata: getValue('customMetadata', 'custom_metadata') as Map<String, dynamic>?,
      entityCounts: parseEntityCounts(getValue('entityCounts', 'entity_counts')),
      syncStatus: parseSyncStatus(getValue('syncStatus', 'sync_status')),
      syncVersion: getValue('syncVersion', 'sync_version') as int? ?? 1,
      serverTimestamp: parseDateTime(getValue('serverTimestamp', 'server_timestamp')),
      conflictCount: getValue('conflictCount', 'conflict_count') as int? ?? 0,
      errorMessage: getValue('errorMessage', 'error_message') as String?,
      retryCount: getValue('retryCount', 'retry_count') as int? ?? 0,
      syncDuration: getValue('syncDuration', 'sync_duration') as int?,
    );
  } catch (e) {
    throw FormatException('Failed to parse DatumSyncMetadata: $e');
  }
}