For applications with specific requirements, PocketSync allows implementing custom conflict resolution logic:

  • Set the conflict strategy to ConflictResolutionStrategy.custom
  • Provide a custom resolver function that implements the ConflictResolver type
  • The resolver receives both conflicting changes and must return the winning change

To use a custom conflict resolver, you must:

  • Set the conflictResolutionStrategy to ConflictResolutionStrategy.custom in PocketSyncOptions
  • Provide your custom resolver function in the customResolver parameter

Example configuration:

final pocketSync = await PocketSync.initialize(
  options: PocketSyncOptions(
    conflictStrategy: ConflictResolutionStrategy.custom,
    conflictResolver: (localChange, remoteChange) async {
      // Custom logic to determine the winning change
      if (localChange.tableName == 'priorities') {
        return localChange; // Local changes always win for the 'priorities' table
      } else {
        return remoteChange; // Server changes win for other tables
      }
    },
  ),
  // ... other configuration options
);

Custom Conflict Resolver

The custom conflict resolver function receives two parameters:

ParameterDescription
localChangeThe local change that conflicts with the remote change
remoteChangeThe remote change that conflicts with the local change

The resolver must return the winning change.

Example

final pocketSync = await PocketSync.initialize(
  options: PocketSyncOptions(
    conflictStrategy: ConflictResolutionStrategy.custom,
    conflictResolver: (localChange, remoteChange) async {
      // Custom logic to determine the winning change
      if (localChange.tableName == 'priorities') {
        return localChange; // Local changes always win for the 'priorities' table
      } else {
        return remoteChange; // Server changes win for other tables
      }
    },
  ),
  // ... other configuration options
);

The change object has the following properties:

PropertyTypeDescription
idStringUnique identifier for the change
tableNameStringName of the table being modified
recordIdStringID of the record being modified
operationChangeTypeType of operation (insert, update, delete)
timestampintWhen the change occurred (milliseconds since epoch)
versionintVersion number of the change
syncedboolWhether the change has been synced to the server
dataMap<String, dynamic>The actual data changes for the record

Import note: The data property should always contain a “old” and “new” key. This is needed to maintain consistency with the default conflict resolution strategy.

Conflict Resolution Process