import core, { Client, DOMAIN_MIGRATION, Data, Doc, DocumentQuery, Domain, FindOptions, Hierarchy, IncOptions, MigrationState, ModelDb, ObjQueryType, PushOptions, Ref, TxOperations, UnsetOptions, generateId } from '@hcengineering/core' import { ModelLogger } from './utils' /** * @public */ export type MigrateUpdate = Partial & Omit, '$move'> & IncOptions & UnsetOptions & Record /** * @public */ export interface MigrationResult { matched: number updated: number } /** * @public */ export type MigrationDocumentQuery = { [P in keyof T]?: ObjQueryType | null } & { $search?: string // support nested queries e.g. 'user.friends.name' // this will mark all unrecognized properties as any (including nested queries) [key: string]: any } /** * @public */ export interface MigrationIterator { next: (count: number) => Promise close: () => Promise } /** * @public * Client to perform model upgrades */ export interface MigrationClient { // Raw collection operations // Raw FIND, allow to find documents inside domain. find: ( domain: Domain, query: MigrationDocumentQuery, options?: Omit, 'lookup'> ) => Promise // Traverse documents traverse: ( domain: Domain, query: MigrationDocumentQuery, options?: Omit, 'lookup'> ) => Promise> // Allow to raw update documents inside domain. update: ( domain: Domain, query: MigrationDocumentQuery, operations: MigrateUpdate ) => Promise bulk: ( domain: Domain, operations: { filter: MigrationDocumentQuery, update: MigrateUpdate }[] ) => Promise // Move documents per domain move: (sourceDomain: Domain, query: DocumentQuery, targetDomain: Domain) => Promise create: (domain: Domain, doc: T | T[]) => Promise delete: (domain: Domain, _id: Ref) => Promise deleteMany: (domain: Domain, query: DocumentQuery) => Promise hierarchy: Hierarchy model: ModelDb } /** * @public */ export type MigrationUpgradeClient = Client /** * @public */ export interface MigrateOperation { // Perform low level migration migrate: (client: MigrationClient, logger: ModelLogger) => Promise // Perform high level upgrade operations. upgrade: (client: MigrationUpgradeClient, logger: ModelLogger) => Promise } /** * @public */ export interface Migrations { state: string func: (client: MigrationClient) => Promise } /** * @public */ export interface UpgradeOperations { state: string func: (client: MigrationUpgradeClient) => Promise } /** * @public */ export async function tryMigrate (client: MigrationClient, plugin: string, migrations: Migrations[]): Promise { const states = new Set( (await client.find(DOMAIN_MIGRATION, { _class: core.class.MigrationState, plugin })).map( (p) => p.state ) ) for (const migration of migrations) { if (states.has(migration.state)) continue await migration.func(client) const st: MigrationState = { plugin, state: migration.state, space: core.space.Configuration, modifiedBy: core.account.System, modifiedOn: Date.now(), _class: core.class.MigrationState, _id: generateId() } await client.create(DOMAIN_MIGRATION, st) } } /** * @public */ export async function tryUpgrade ( client: MigrationUpgradeClient, plugin: string, migrations: UpgradeOperations[] ): Promise { const states = new Set((await client.findAll(core.class.MigrationState, { plugin })).map((p) => p.state)) for (const migration of migrations) { if (states.has(migration.state)) continue await migration.func(client) const st: Data = { plugin, state: migration.state } const tx = new TxOperations(client, core.account.System) await tx.createDoc(core.class.MigrationState, core.space.Configuration, st) } }