pushBatch method

  1. @override
Future<void> pushBatch(
  1. List<SyncEntry> entries
)
override

Push multiple records to the remote in optimized batches.

The default implementation falls back to individual push calls. Override in backend-specific subclasses (e.g. SupabaseRemoteStore) to use batch APIs for better performance.

Implementation

@override
Future<void> pushBatch(List<SyncEntry> entries) async {
  if (entries.isEmpty) return;

  // Group entries by table and operation
  final groups = <String, Map<SyncOperation, List<SyncEntry>>>{};
  for (final entry in entries) {
    final tableGroups = groups.putIfAbsent(entry.table, () => {});
    tableGroups.putIfAbsent(entry.operation, () => []).add(entry);
  }

  try {
    for (final tableEntry in groups.entries) {
      final tableName = tableEntry.key;
      final opsMap = tableEntry.value;

      // Batch Upserts
      final upserts = opsMap[SyncOperation.upsert];
      if (upserts != null && upserts.isNotEmpty) {
        final payloads = upserts.map((e) => e.payload).toList();
        await client.from(tableName).upsert(payloads);
      }

      // Batch Deletes
      final deletes = opsMap[SyncOperation.delete];
      if (deletes != null && deletes.isNotEmpty) {
        final ids = deletes.map((e) => e.recordId).toList();
        await client.from(tableName).delete().inFilter('id', ids);
      }

      // Batch Patches (individual updates — Supabase has no batch update)
      final patches = opsMap[SyncOperation.patch];
      if (patches != null && patches.isNotEmpty) {
        for (final entry in patches) {
          await client
              .from(tableName)
              .update(entry.payload)
              .eq('id', entry.recordId);
        }
      }
    }
  } on AuthException catch (e) {
    throw AuthExpiredException(e);
  } catch (e) {
    if (_isAuthError(e)) throw AuthExpiredException(e);
    rethrow;
  }
}