UNPKG

@webdocgroup/realm-migrations

Version:
121 lines (120 loc) 4.5 kB
import Realm from 'realm'; import { shouldRunMigrationsHook } from '../HookPipelines/shouldRunMigrationsHook'; import { enabled } from '../Hooks/Enabled'; export class RealmMigrationService { constructor({ databaseName, migrations, hooks = {}, enabled = true, }) { this.migrations = []; this.databaseName = databaseName; this.migrations = migrations; this.hooks = hooks; this.enabled = enabled; } currentSchemaVersion() { const dbPath = `${this.databaseName}.realm`; const currentSchemaVersion = Realm.schemaVersion(dbPath); return currentSchemaVersion; } latestMigrationVersion() { return this.migrations.length; } nextSchemaVersion() { const currentSchemaVersion = this.currentSchemaVersion(); const nextSchemaVersion = currentSchemaVersion + 1; if (this.migrations[nextSchemaVersion]) { return nextSchemaVersion; } return currentSchemaVersion; } shouldRun({ currentVersion, latestMigrationVersion, }) { return shouldRunMigrationsHook({ props: { currentVersion, latestMigrationVersion, }, hooks: [ enabled({ enabled: this.enabled }), ...(this.hooks.shouldRunMigrations ? this.hooks.shouldRunMigrations : []), ], callback: () => { return currentVersion < latestMigrationVersion; }, }); } /** * Derives the schemas for a given version by combining all migrations * up to that version. * * @param version The version to derive schemas for. * * @returns An array of schemas that represent the state of the database * at the specified version. */ derriveSchemas(version) { const migrationsForVersion = this.migrations.slice(0, version); const schemasByName = migrationsForVersion.reduce((schemasByName, migration) => { const schemasByNameInMigration = migration.schemas.reduce((acc, schema) => { return { ...acc, [schema.name]: schema }; }, {}); return { ...schemasByName, ...schemasByNameInMigration }; }, {}); return Object.values(schemasByName); } migrationsToRun() { const currentSchemaVersion = Math.max(0, this.currentSchemaVersion() - 1); return this.migrations .map((migration, index) => ({ ...migration, version: index + 1, })) .slice(currentSchemaVersion, this.migrations.length); } run() { const currentVersion = this.currentSchemaVersion(); const latestMigrationVersion = this.latestMigrationVersion(); if (!this.shouldRun({ currentVersion, latestMigrationVersion })) { console.info('No migrations to run', { currentVersion, latestMigrationVersion, }); return { schema: this.derriveSchemas(currentVersion), schemaVersion: currentVersion, }; } const migrations = this.migrationsToRun(); let latestMigratedSchemas = []; let schemaVersion = -1; console.info(`Running ${migrations.length} migrations`, { currentVersion, latestMigrationVersion, }); migrations.forEach((migration) => { console.info(`Running migration: ${migration.description}`, { migrationVersion: migration.version, schemaCount: migration.schemas.length, }); const derivedSchema = this.derriveSchemas(migration.version); console.info('Derived schemas for migration', { count: derivedSchema.length, }); const migrated = new Realm({ path: `${this.databaseName}.realm`, onMigration: migration.migrate, schema: derivedSchema, schemaVersion: migration.version, }); migrated.close(); latestMigratedSchemas = derivedSchema; schemaVersion = migration.version; }); console.info('Migrations completed', { currentSchemaVersion: this.currentSchemaVersion(), }); return { schema: latestMigratedSchemas, schemaVersion, }; } }