import { Doc, DocumentQuery, Domain, FindOptions, isOperator, Ref, SortingOrder } from '@anticrm/core' import { MigrationClient, MigrateUpdate, MigrationResult } from '@anticrm/model' import { Db, Document, Filter, Sort, UpdateFilter } from 'mongodb' /** * Upgrade client implementation. */ export class MigrateClientImpl implements MigrationClient { constructor (readonly db: Db) { } private translateQuery(query: DocumentQuery): Filter { const translated: any = {} for (const key in query) { const value = (query as any)[key] if (value !== null && typeof value === 'object') { const keys = Object.keys(value) if (keys[0] === '$like') { const pattern = value.$like as string translated[key] = { $regex: `^${pattern.split('%').join('.*')}$`, $options: 'i' } continue } } translated[key] = value } return translated } async find( domain: Domain, query: DocumentQuery, options?: FindOptions | undefined ): Promise { let cursor = this.db.collection(domain).find(this.translateQuery(query)) if (options?.limit !== undefined) { cursor = cursor.limit(options.limit) } if (options !== null && options !== undefined) { if (options.sort !== undefined) { const sort: Sort = {} for (const key in options.sort) { const order = options.sort[key] === SortingOrder.Ascending ? 1 : -1 sort[key] = order } cursor = cursor.sort(sort) } } return await cursor.toArray() } async update(domain: Domain, query: DocumentQuery, operations: MigrateUpdate): Promise { if (isOperator(operations)) { const result = await this.db .collection(domain) .updateMany(this.translateQuery(query), { ...operations } as unknown as UpdateFilter) return { matched: result.matchedCount, updated: result.modifiedCount } } else { const result = await this.db.collection(domain).updateMany(this.translateQuery(query), { $set: operations }) return { matched: result.matchedCount, updated: result.modifiedCount } } } async move (sourceDomain: Domain, query: DocumentQuery, targetDomain: Domain): Promise { const q = this.translateQuery(query) const cursor = this.db.collection(sourceDomain).find(q) const target = this.db.collection(targetDomain) const result: MigrationResult = { matched: 0, updated: 0 } let doc: Document | null while ((doc = await cursor.next()) != null) { await target.insertOne(doc) result.matched++ result.updated++ } await this.db.collection(sourceDomain).deleteMany(q) return result } async create (domain: Domain, doc: T): Promise { await this.db.collection(domain).insertOne(doc as Document) } async delete (domain: Domain, _id: Ref): Promise { await this.db.collection(domain).deleteOne({ _id }) } }