@rikishi/watermelondb
Version:
Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast
101 lines (85 loc) • 3.79 kB
JavaScript
// @flow
import type { Database, RecordId, TableName, Model } from '..'
import { type DirtyRaw } from '../RawRecord'
import type { SchemaVersion } from '../Schema'
import { type MigrationSyncChanges } from '../Schema/migrations/getSyncChanges'
export type Timestamp = number
export type SyncTableChangeSet = $Exact<{
created: DirtyRaw[],
updated: DirtyRaw[],
deleted: RecordId[],
}>
export type SyncDatabaseChangeSet = { [TableName<any>]: SyncTableChangeSet }
export type SyncLocalChanges = $Exact<{ changes: SyncDatabaseChangeSet, affectedRecords: Model[] }>
export type SyncPullArgs = $Exact<{
lastPulledAt: ?Timestamp,
schemaVersion: SchemaVersion,
migration: MigrationSyncChanges,
}>
export type SyncPullResult =
| $Exact<{ changes: SyncDatabaseChangeSet, timestamp: Timestamp }>
| $Exact<{ syncJson: string }>
| $Exact<{ syncJsonId: number }>
export type SyncRejectedIds = { [TableName<any>]: RecordId[] }
export type SyncPushArgs = $Exact<{ changes: SyncDatabaseChangeSet, lastPulledAt: Timestamp }>
export type SyncPushResult = $Exact<{ experimentalRejectedIds?: SyncRejectedIds }>
type SyncConflict = $Exact<{ local: DirtyRaw, remote: DirtyRaw, resolved: DirtyRaw }>
export type SyncLog = {
startedAt?: Date,
lastPulledAt?: ?number,
lastPulledSchemaVersion?: ?SchemaVersion,
migration?: ?MigrationSyncChanges,
newLastPulledAt?: number,
resolvedConflicts?: SyncConflict[],
rejectedIds?: SyncRejectedIds,
finishedAt?: Date,
remoteChangeCount?: number,
localChangeCount?: number,
phase?: string, // NOTE: an textual information, not a stable API!
error?: Error,
}
export type SyncConflictResolver = (
table: TableName<any>,
local: DirtyRaw,
remote: DirtyRaw,
resolved: DirtyRaw,
) => DirtyRaw
export type SyncArgs = $Exact<{
database: Database,
pullChanges: (SyncPullArgs) => Promise<SyncPullResult>,
pushChanges?: (SyncPushArgs) => Promise<?SyncPushResult>,
// version at which support for migration syncs was added - the version BEFORE first syncable migration
migrationsEnabledAtVersion?: SchemaVersion,
sendCreatedAsUpdated?: boolean,
log?: SyncLog,
// 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.
// If you don't want to change default behavior for a given record, return `resolved` as is
// Note that it's safe to mutate `resolved` object, so you can skip copying it for performance.
conflictResolver?: SyncConflictResolver,
// commits changes in multiple batches, and not one - temporary workaround for memory issue
_unsafeBatchPerCollection?: boolean,
// Advanced optimization - pullChanges must return syncJson or syncJsonId to be processed by native code.
// This can only be used on initial (login) sync, not for incremental syncs.
// This can only be used with SQLiteAdapter with JSI enabled.
// The exact API may change between versions of WatermelonDB.
// See documentation for more details.
unsafeTurbo?: boolean,
// Called after pullChanges with whatever was returned by pullChanges, minus `changes`. Useful
// when using turbo mode
onDidPullChanges?: (Object) => Promise<void>,
}>
// See Sync docs for usage details
export async function synchronize(args: SyncArgs): Promise<void> {
try {
const synchronizeImpl = require('./impl/synchronize').default
await synchronizeImpl(args)
} catch (error) {
args.log && (args.log.error = error)
throw error
}
}
export function hasUnsyncedChanges({ database }: $Exact<{ database: Database }>): Promise<boolean> {
return require('./impl').hasUnsyncedChanges(database)
}