diff --git a/models/request/src/index.ts b/models/request/src/index.ts index 81442953ad..6d19fd6de4 100644 --- a/models/request/src/index.ts +++ b/models/request/src/index.ts @@ -17,7 +17,7 @@ import activity from '@hcengineering/activity' import chunter from '@hcengineering/chunter' import type { EmployeeAccount } from '@hcengineering/contact' import contact from '@hcengineering/contact' -import { Doc, Domain, IndexKind, Ref, TxCUD } from '@hcengineering/core' +import { Domain, IndexKind, Ref, Tx } from '@hcengineering/core' import { ArrOf, Builder, @@ -33,12 +33,12 @@ import { } from '@hcengineering/model' import { TComment } from '@hcengineering/model-chunter' import core, { TAttachedDoc, TClass } from '@hcengineering/model-core' +import { generateClassNotificationTypes } from '@hcengineering/model-notification' import view from '@hcengineering/model-view' +import notification from '@hcengineering/notification' import { Request, RequestDecisionComment, RequestPresenter, RequestStatus } from '@hcengineering/request' import { AnyComponent } from '@hcengineering/ui' import request from './plugin' -import notification from '@hcengineering/notification' -import { generateClassNotificationTypes } from '@hcengineering/model-notification' export { requestId } from '@hcengineering/request' export { default } from './plugin' @@ -62,7 +62,7 @@ export class TRequest extends TAttachedDoc implements Request { @Index(IndexKind.Indexed) status!: RequestStatus - tx!: TxCUD + tx!: Tx @Prop(TypeRef(contact.class.EmployeeAccount), request.string.Rejected) @ReadOnly() diff --git a/plugins/request/src/index.ts b/plugins/request/src/index.ts index 5b05ad2b8a..f6c888ad01 100644 --- a/plugins/request/src/index.ts +++ b/plugins/request/src/index.ts @@ -13,12 +13,12 @@ // limitations under the License. // +import { Comment } from '@hcengineering/chunter' import { EmployeeAccount } from '@hcengineering/contact' -import type { AttachedDoc, Class, Doc, Mixin, Ref, TxCUD } from '@hcengineering/core' +import type { AttachedDoc, Class, Doc, Mixin, Ref, Tx } from '@hcengineering/core' import type { Asset, IntlString, Plugin } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import { AnyComponent } from '@hcengineering/ui' -import { Comment } from '@hcengineering/chunter' /** * @public @@ -29,7 +29,7 @@ export interface Request extends AttachedDoc { requiredApprovesCount: number rejected?: Ref status: RequestStatus - tx: TxCUD + tx: Tx comments?: number } diff --git a/server/core/src/storage.ts b/server/core/src/storage.ts index 1352e040b1..6b60217dde 100644 --- a/server/core/src/storage.ts +++ b/server/core/src/storage.ts @@ -606,110 +606,99 @@ class TServerStorage implements ServerStorage { return { passed, onEnd } } - async apply (ctx: MeasureContext, tx: Tx[], broadcast: boolean): Promise { - const triggerFx = new Effects() - const _findAll = createFindAll(this) + async apply (ctx: MeasureContext, txes: Tx[], broadcast: boolean): Promise { + const result = await this.processTxes(ctx, txes) + let derived: Tx[] = [] - const txToStore = tx.filter( - (it) => it.space !== core.space.DerivedTx && !this.hierarchy.isDerived(it._class, core.class.TxApplyIf) - ) - await ctx.with('domain-tx', {}, async () => await this.getAdapter(DOMAIN_TX).tx(...txToStore)) + derived = result[1] - const removedMap = new Map, Doc>() - await ctx.with('apply', {}, (ctx) => this.routeTx(ctx, removedMap, ...tx)) - - // send transactions if (broadcast) { - this.options?.broadcast?.(tx) - } - // invoke triggers and store derived objects - const derived = await this.processDerived(ctx, tx, triggerFx, _findAll, removedMap) - - // index object - for (const _tx of tx) { - await ctx.with('fulltext', {}, (ctx) => this.fulltext.tx(ctx, _tx)) - } - - // index derived objects - for (const tx of derived) { - await ctx.with('derived-processor', { _class: txClass(tx) }, (ctx) => this.fulltext.tx(ctx, tx)) - } - - for (const fx of triggerFx.effects) { - await fx() - } - if (broadcast && derived.length > 0) { + this.options?.broadcast?.(txes) this.options?.broadcast?.(derived) } - return [...tx, ...derived] + + return [...txes, ...derived] } - async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> { - // store tx - const _class = txClass(tx) - const _findAll = createFindAll(this) - const objClass = txObjectClass(tx) - const removedDocs = new Map, Doc>() - return await ctx.with('tx', { _class, objClass }, async (ctx) => { - if (tx.space !== core.space.DerivedTx && !this.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) { - await ctx.with('domain-tx', { _class, objClass }, async () => await this.getAdapter(DOMAIN_TX).tx(tx)) + fillTxes (txes: Tx[], txToStore: Tx[], modelTx: Tx[], txToProcess: Tx[], applyTxes: Tx[]): void { + for (const tx of txes) { + if (!this.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) { + if (tx.space !== core.space.DerivedTx) { + txToStore.push(tx) + } + if (tx.objectSpace === core.space.Model) { + modelTx.push(tx) + } + txToProcess.push(tx) + } else { + applyTxes.push(tx) } + } + } - if (tx.objectSpace === core.space.Model) { + async processTxes (ctx: MeasureContext, txes: Tx[]): Promise<[TxResult, Tx[]]> { + // store tx + const _findAll = createFindAll(this) + const txToStore: Tx[] = [] + const modelTx: Tx[] = [] + const applyTxes: Tx[] = [] + const txToProcess: Tx[] = [] + const triggerFx = new Effects() + const removedMap = new Map, Doc>() + const onEnds: (() => void)[] = [] + let result: TxResult = {} + let derived: Tx[] = [] + + try { + this.fillTxes(txes, txToStore, modelTx, txToProcess, applyTxes) + for (const tx of applyTxes) { + const applyIf = tx as TxApplyIf + // Wait for scope promise if found + const passed = await this.verifyApplyIf(ctx, applyIf, _findAll) + onEnds.push(passed.onEnd) + if (passed.passed) { + this.fillTxes(applyIf.txes, txToStore, modelTx, txToProcess, applyTxes) + derived = [...applyIf.txes] + } + } + for (const tx of modelTx) { // maintain hierarchy and triggers this.hierarchy.tx(tx) await this.triggers.tx(tx) await this.modelDb.tx(tx) this.model.push(tx) } + await ctx.with('domain-tx', {}, async () => await this.getAdapter(DOMAIN_TX).tx(...txToStore)) + result = await ctx.with('apply', {}, (ctx) => this.routeTx(ctx, removedMap, ...txToProcess)) - const triggerFx = new Effects() + // invoke triggers and store derived objects + derived = derived.concat(await this.processDerived(ctx, txToProcess, triggerFx, _findAll, removedMap)) - let result: TxResult = {} - let derived: Tx[] = [] - let onEnd = (): void => {} - - try { - if (this.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) { - const applyIf = tx as TxApplyIf - // Wait for scope promise if found - let passed: boolean - ;({ passed, onEnd } = await this.verifyApplyIf(ctx, applyIf, _findAll)) - result = passed - if (passed) { - // Store apply if transaction's if required - await ctx.with('domain-tx', { _class, objClass }, async () => { - const atx = await this.getAdapter(DOMAIN_TX) - await atx.tx(...applyIf.txes) - }) - derived = await this.processDerivedTxes(applyIf.txes, ctx, triggerFx, _findAll, removedDocs) - } - } else { - // store object - result = await ctx.with('route-tx', { _class, objClass }, (ctx) => this.routeTx(ctx, removedDocs, tx)) - // invoke triggers and store derived objects - derived = await this.processDerived(ctx, [tx], triggerFx, _findAll, removedDocs) - } - - // index object - await ctx.with('fulltext', { _class, objClass }, (ctx) => this.fulltext.tx(ctx, tx)) - // index derived objects - for (const tx of derived) { - await ctx.with('derived-fulltext', { _class: txClass(tx) }, (ctx) => this.fulltext.tx(ctx, tx)) - } - - for (const fx of triggerFx.effects) { - await fx() - } - } catch (err: any) { - console.log(err) - throw err - } finally { - onEnd() + // index object + for (const _tx of txToProcess) { + await ctx.with('fulltext', {}, (ctx) => this.fulltext.tx(ctx, _tx)) } - return [result, derived] - }) + // index derived objects + for (const tx of derived) { + await ctx.with('derived-processor', { _class: txClass(tx) }, (ctx) => this.fulltext.tx(ctx, tx)) + } + + for (const fx of triggerFx.effects) { + await fx() + } + } catch (err: any) { + console.log(err) + throw err + } finally { + onEnds.forEach((p) => p()) + } + + return [result, derived] + } + + async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> { + return await this.processTxes(ctx, [tx]) } find (domain: Domain): StorageIterator { @@ -742,12 +731,6 @@ class Effects { } } -function txObjectClass (tx: Tx): string { - return tx._class === core.class.TxCollectionCUD - ? (tx as TxCollectionCUD).tx.objectClass - : (tx as TxCUD).objectClass -} - function txClass (tx: Tx): Ref> { return tx._class === core.class.TxCollectionCUD ? (tx as TxCollectionCUD).tx._class : tx._class }