UNPKG

@nozbe/watermelondb

Version:

Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast

114 lines (96 loc) 4.27 kB
// @flow import type { Database } from '../..' import { invariant, logError, logger } from '../../utils/common' import type { Timestamp, SyncLog } from '../index' import type { SchemaVersion } from '../../Schema' import getSyncChanges, { type MigrationSyncChanges } from '../../Schema/migrations/getSyncChanges' export { default as applyRemoteChanges } from './applyRemote' export { default as fetchLocalChanges, hasUnsyncedChanges } from './fetchLocal' export { default as markLocalChangesAsSynced } from './markAsSynced' const lastPulledAtKey = '__watermelon_last_pulled_at' const lastPulledSchemaVersionKey = '__watermelon_last_pulled_schema_version' export async function getLastPulledAt(database: Database): Promise<?Timestamp> { return parseInt(await database.adapter.getLocal(lastPulledAtKey), 10) || null } export async function setLastPulledAt(database: Database, timestamp: Timestamp): Promise<void> { const previousTimestamp = (await getLastPulledAt(database)) || 0 if (timestamp < previousTimestamp) { logError( `[Sync] Pull has finished and received server time ${timestamp} — but previous pulled-at time was greater - ${previousTimestamp}. This is most likely server bug.`, ) } await database.adapter.setLocal(lastPulledAtKey, `${timestamp}`) } export async function getLastPulledSchemaVersion(database: Database): Promise<?SchemaVersion> { return parseInt(await database.adapter.getLocal(lastPulledSchemaVersionKey), 10) || null } export async function setLastPulledSchemaVersion( database: Database, version: SchemaVersion, ): Promise<void> { await database.adapter.setLocal(lastPulledSchemaVersionKey, `${version}`) } type MigrationInfo = $Exact<{ schemaVersion: SchemaVersion, migration: MigrationSyncChanges, shouldSaveSchemaVersion: boolean, }> export async function getMigrationInfo( database: Database, log: ?SyncLog, lastPulledAt: ?Timestamp, migrationsEnabledAtVersion: ?SchemaVersion, ): Promise<MigrationInfo> { const isFirstSync = !lastPulledAt const schemaVersion = database.schema.version const lastPulledSchemaVersion = await getLastPulledSchemaVersion(database) log && (log.lastPulledSchemaVersion = lastPulledSchemaVersion) const areMigrationsEnabled = !!migrationsEnabledAtVersion const { migrations } = database.adapter if (lastPulledSchemaVersion && isFirstSync) { logError( '[Sync] lastPulledSchemaVersion is set, but this is the first sync. This most likely means that the backend does not return a correct timestamp', ) } if (areMigrationsEnabled) { invariant( typeof migrationsEnabledAtVersion === 'number' && migrationsEnabledAtVersion >= 1, '[Sync] Invalid migrationsEnabledAtVersion', ) invariant( migrationsEnabledAtVersion <= schemaVersion, '[Sync] migrationsEnabledAtVersion must not be greater than current schema version', ) invariant( migrations, '[Sync] Migration syncs cannot be enabled on a database that does not support migrations', ) invariant( migrationsEnabledAtVersion >= migrations.minVersion, `[Sync] migrationsEnabledAtVersion is too low - not possible to migrate from schema version ${migrationsEnabledAtVersion}`, ) lastPulledSchemaVersion && invariant( lastPulledSchemaVersion <= schemaVersion, `[Sync] Last synced schema version (${lastPulledSchemaVersion}) is greater than current schema version (${schemaVersion}). This indicates programmer error`, ) } const migrateFrom = lastPulledSchemaVersion || migrationsEnabledAtVersion || 0 const shouldMigrate = areMigrationsEnabled && migrateFrom < schemaVersion && !isFirstSync const migration = migrations && shouldMigrate ? getSyncChanges(migrations, migrateFrom, schemaVersion) : null log && (log.migration = migration) if (migration) { logger.log(`[Sync] Performing migration sync from ${migrateFrom} to ${schemaVersion}`) if (!lastPulledSchemaVersion) { logger.warn( `[Sync] Using fallback initial schema version. The migration sync might not contain all necessary migrations`, ) } } return { schemaVersion, migration, shouldSaveSchemaVersion: shouldMigrate || isFirstSync, } }