Skip to content

Commit

Permalink
renamed syncUpdateCondition to shouldUpdateRecord and moved it before…
Browse files Browse the repository at this point in the history
… conflictResolver where appropriate, added tests
  • Loading branch information
primus11 committed Mar 1, 2023
1 parent 8032fdb commit 6470faf
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 21 deletions.
82 changes: 82 additions & 0 deletions src/sync/impl/__tests__/applyRemote.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,86 @@ describe('applyRemoteChanges', () => {
// Record ID mock_tasks#tSynced was sent over the bridge, but it's not cached
await database.get('mock_tasks').find('tSynced')
})
describe('shouldUpdateRecord', () => {
it('can ignore record', async () => {
const { database, tasks } = makeDatabase()

await makeLocalChanges(database)
await testApplyRemoteChanges(database, {
mock_tasks: {
updated: [
// update / updated - will be ignored when any local change
{ id: 'tUpdated', name: 'remote', description: 'remote' },
],
},
}, {
shouldUpdateRecord: (_table, local, _remote) => {
return local._status !== 'updated'
},
})

await expectSyncedAndMatches(tasks, 'tUpdated', {
_status: 'updated',
_changed: 'name,position',
name: 'local', // local change preserved
position: 100,
description: 'orig', // orig should be preserved
project_id: 'orig', // unchanged
})
})
it('can still update', async () => {
const { database, tasks } = makeDatabase()

await makeLocalChanges(database)
await testApplyRemoteChanges(database, {
mock_tasks: {
updated: [
// update / updated - should not be ignored when local wasn't changed
{ id: 'tSynced', name: 'remote', description: 'remote' },
],
},
}, {
shouldUpdateRecord: (_table, local, _remote) => {
return local._status !== 'updated'
},
})

await expectSyncedAndMatches(tasks, 'tSynced', {
_status: 'synced',
name: 'remote', // remote change
description: 'remote', // remote change
})
})
})
describe('conflictResolver', () => {
it('can account for conflictResolver', async () => {
const { database, tasks } = makeDatabase()

await makeLocalChanges(database)
await testApplyRemoteChanges(database, {
mock_tasks: {
updated: [
// update / updated - resolve and update (description is concat of local/remote on change)
{ id: 'tUpdated', name: 'remote', description: 'remote' },
],
},
}, {
conflictResolver: (_table, local, remote, resolved) => {
if (local.name !== remote.name) {
resolved.name = `${remote.name} ${local.name}`
}
return resolved
},
})

await expectSyncedAndMatches(tasks, 'tUpdated', {
_status: 'updated',
_changed: 'name,position',
name: 'remote local', // concat of remote and local change
position: 100,
description: 'remote', // remote change
project_id: 'orig', // unchanged
})
})
})
})
4 changes: 2 additions & 2 deletions src/sync/impl/applyRemote.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import type {
SyncDatabaseChangeSet,
SyncLog,
SyncConflictResolver,
SyncUpdateCondition,
SyncShouldUpdateRecord,
} from '../index'

export default function applyRemoteChanges(
db: Database,
remoteChanges: SyncDatabaseChangeSet,
sendCreatedAsUpdated: boolean,
log?: SyncLog,
shouldUpdateRecord?: SyncShouldUpdateRecord,
conflictResolver?: SyncConflictResolver,
_unsafeBatchPerCollection?: boolean,
syncUpdateCondition?: SyncUpdateCondition,
): Promise<void>
10 changes: 5 additions & 5 deletions src/sync/impl/applyRemote.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type {
SyncDatabaseChangeSet,
SyncLog,
SyncConflictResolver,
SyncUpdateCondition,
SyncShouldUpdateRecord,
SyncPullStrategy,
} from '../index'
import { prepareCreateFromRaw, prepareUpdateFromRaw, recordFromRaw } from './helpers'
Expand All @@ -33,9 +33,9 @@ type ApplyRemoteChangesContext = $Exact<{
strategy?: ?SyncPullStrategy,
sendCreatedAsUpdated?: boolean,
log?: SyncLog,
shouldUpdateRecord?: SyncShouldUpdateRecord,
conflictResolver?: SyncConflictResolver,
_unsafeBatchPerCollection?: boolean,
syncUpdateCondition?: SyncUpdateCondition,
}>

// NOTE: Creating JS models is expensive/memory-intensive, so we want to avoid it if possible
Expand Down Expand Up @@ -265,7 +265,7 @@ function prepareApplyRemoteChangesToCollection<T: Model>(
collection: Collection<T>,
context: ApplyRemoteChangesContext,
): Array<?T> {
const { db, sendCreatedAsUpdated, log, conflictResolver, syncUpdateCondition } = context
const { db, sendCreatedAsUpdated, log, conflictResolver, shouldUpdateRecord } = context
const { table } = collection
const {
created,
Expand Down Expand Up @@ -299,8 +299,8 @@ function prepareApplyRemoteChangesToCollection<T: Model>(
raw,
collection,
log,
shouldUpdateRecord,
conflictResolver,
syncUpdateCondition,
),
)
} else if (locallyDeletedIds.includes(raw.id)) {
Expand All @@ -326,8 +326,8 @@ function prepareApplyRemoteChangesToCollection<T: Model>(
raw,
collection,
log,
shouldUpdateRecord,
conflictResolver,
syncUpdateCondition,
),
)
} else if (locallyDeletedIds.includes(raw.id)) {
Expand Down
4 changes: 2 additions & 2 deletions src/sync/impl/helpers.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
SyncLog,
SyncDatabaseChangeSet,
SyncConflictResolver,
SyncUpdateCondition,
SyncShouldUpdateRecord,
} from '../index'

// Returns raw record with naive solution to a conflict based on local `_changed` field
Expand All @@ -21,8 +21,8 @@ export function prepareUpdateFromRaw<T extends Model = Model>(
record: T,
updatedDirtyRaw: DirtyRaw,
log?: SyncLog,
shouldUpdateRecord?: SyncShouldUpdateRecord,
conflictResolver?: SyncConflictResolver,
syncUpdateCondition?: SyncUpdateCondition,
): T

export function prepareMarkAsSynced<T extends Model = Model>(record: T): T
Expand Down
12 changes: 6 additions & 6 deletions src/sync/impl/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { type RawRecord, type DirtyRaw, sanitizedRaw } from '../../RawRecord'
import type {
SyncLog,
SyncDatabaseChangeSet,
SyncShouldUpdateRecord,
SyncConflictResolver,
SyncUpdateCondition,
} from '../index'

// Returns raw record with naive solution to a conflict based on local `_changed` field
Expand Down Expand Up @@ -64,10 +64,10 @@ export function requiresUpdate<T: Model>(
collection: Collection<T>,
local: RawRecord,
dirtyRemote: DirtyRaw,
syncUpdateCondition?: SyncUpdateCondition,
shouldUpdateRecord?: SyncShouldUpdateRecord,
): boolean {
if (syncUpdateCondition) {
return syncUpdateCondition(collection.table, local, dirtyRemote)
if (shouldUpdateRecord) {
return shouldUpdateRecord(collection.table, local, dirtyRemote)
}

if (local._status !== 'synced') {
Expand All @@ -89,10 +89,10 @@ export function prepareUpdateFromRaw<T: Model>(
remoteDirtyRaw: DirtyRaw,
collection: Collection<T>,
log: ?SyncLog,
shouldUpdateRecord?: SyncShouldUpdateRecord,
conflictResolver?: SyncConflictResolver,
syncUpdateCondition?: SyncUpdateCondition,
): ?T {
if (!requiresUpdate(collection, localRaw, remoteDirtyRaw, syncUpdateCondition)) {
if (!requiresUpdate(collection, localRaw, remoteDirtyRaw, shouldUpdateRecord)) {
return null
}

Expand Down
1 change: 1 addition & 0 deletions src/sync/impl/synchronize.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default function synchronize({
sendCreatedAsUpdated,
migrationsEnabledAtVersion,
log,
shouldUpdateRecord,
conflictResolver,
_unsafeBatchPerCollection,
unsafeTurbo,
Expand Down
4 changes: 2 additions & 2 deletions src/sync/impl/synchronize.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ export default async function synchronize({
sendCreatedAsUpdated = false,
migrationsEnabledAtVersion,
log,
shouldUpdateRecord,
conflictResolver,
_unsafeBatchPerCollection,
unsafeTurbo,
syncUpdateCondition,
}: SyncArgs): Promise<void> {
const resetCount = database._resetCount
log && (log.startedAt = new Date())
Expand Down Expand Up @@ -106,9 +106,9 @@ export default async function synchronize({
strategy: ((pullResult: any).experimentalStrategy: ?SyncPullStrategy),
sendCreatedAsUpdated,
log,
shouldUpdateRecord,
conflictResolver,
_unsafeBatchPerCollection,
syncUpdateCondition,
})
onDidPullChanges && onDidPullChanges(resultRest)
}
Expand Down
4 changes: 2 additions & 2 deletions src/sync/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export type SyncLog = {
error?: Error;
}

export type SyncUpdateCondition = (
export type SyncShouldUpdateRecord = (
table: TableName<any>,
local: DirtyRaw,
remote: DirtyRaw,
Expand All @@ -72,7 +72,7 @@ export type SyncArgs = $Exact<{
log?: SyncLog;
// Advanced (unsafe) customization point. Useful when doing per record conflict resolution and can
// determine directly from remote and local if we can keep local.
syncUpdateCondition?: SyncUpdateCondition;
shouldUpdateRecord?: SyncShouldUpdateRecord;
// Advanced (unsafe) customization point. Useful when you have subtle invariants between multiple
// columns and want to have them updated consistently, or to implement partial sync
// It's called for every record being updated locally, so be sure that this function is FAST.
Expand Down
4 changes: 2 additions & 2 deletions src/sync/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export type SyncLog = {
error?: Error,
}

export type SyncUpdateCondition = (
export type SyncShouldUpdateRecord = (
table: TableName<any>,
local: DirtyRaw,
remote: DirtyRaw,
Expand All @@ -99,7 +99,7 @@ export type SyncArgs = $Exact<{
log?: SyncLog,
// Advanced (unsafe) customization point. Useful when doing per record conflict resolution and can
// determine directly from remote and local if we can keep local.
syncUpdateCondition?: SyncUpdateCondition,
shouldUpdateRecord?: SyncShouldUpdateRecord,
// Advanced (unsafe) customization point. Useful when you have subtle invariants between multiple
// columns and want to have them updated consistently, or to implement partial sync
// It's called for every record being updated locally, so be sure that this function is FAST.
Expand Down

0 comments on commit 6470faf

Please sign in to comment.