From 854331ae5f67da198e563fdfce5691913691c2b7 Mon Sep 17 00:00:00 2001 From: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> Date: Sun, 21 Aug 2022 13:03:32 +0600 Subject: [PATCH] recursive derived data (#2252) Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> --- .../notification-resources/src/index.ts | 4 + server/core/src/storage.ts | 153 ++++++++++-------- 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts index bc1b8425a8..8882eabcd0 100644 --- a/server-plugins/notification-resources/src/index.ts +++ b/server-plugins/notification-resources/src/index.ts @@ -143,6 +143,10 @@ export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise< return [] } + if ((actualTx as TxCUD).objectClass === notification.class.LastView) { + return [] + } + const result: Tx[] = [] switch (actualTx._class) { diff --git a/server/core/src/storage.ts b/server/core/src/storage.ts index d9580888a7..eb1269468a 100644 --- a/server/core/src/storage.ts +++ b/server/core/src/storage.ts @@ -197,7 +197,7 @@ class TServerStorage implements ServerStorage { return [...(oldTx !== null ? [oldTx] : []), ...(newTx !== null ? [newTx] : [])] } - async processCollection (ctx: MeasureContext, tx: Tx): Promise { + private async processCollection (ctx: MeasureContext, tx: Tx): Promise { if (tx._class === core.class.TxCollectionCUD) { const colTx = tx as TxCollectionCUD const _id = colTx.objectId @@ -212,19 +212,18 @@ class TServerStorage implements ServerStorage { const isCreateTx = colTx.tx._class === core.class.TxCreateDoc const isDeleteTx = colTx.tx._class === core.class.TxRemoveDoc const isUpdateTx = colTx.tx._class === core.class.TxUpdateDoc + if (isUpdateTx) { + return await this.updateCollection(ctx, tx) + } - if (isCreateTx || isDeleteTx || isUpdateTx) { - if (isUpdateTx) { - return await this.updateCollection(ctx, tx) - } else { - const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0] - if (attachedTo !== undefined) { - return [ - await this.getCollectionUpdateTx(_id, _class, tx.modifiedBy, colTx.modifiedOn, attachedTo, { - $inc: { [colTx.collection]: isCreateTx ? 1 : -1 } - }) - ] - } + if (isCreateTx || isDeleteTx) { + const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0] + if (attachedTo !== undefined) { + return [ + await this.getCollectionUpdateTx(_id, _class, tx.modifiedBy, colTx.modifiedOn, attachedTo, { + $inc: { [colTx.collection]: isCreateTx ? 1 : -1 } + }) + ] } } } @@ -248,7 +247,7 @@ class TServerStorage implements ServerStorage { }) } - getParentClass (_class: Ref>): Ref> { + private getParentClass (_class: Ref>): Ref> { const baseDomain = this.hierarchy.getDomain(_class) const ancestors = this.hierarchy.getAncestors(_class) let result: Ref> = _class @@ -263,7 +262,7 @@ class TServerStorage implements ServerStorage { return result } - getMixins (_class: Ref>, object: Doc): Array>> { + private getMixins (_class: Ref>, object: Doc): Array>> { const parentClass = this.getParentClass(_class) const descendants = this.hierarchy.getDescendants(parentClass) return descendants.filter( @@ -271,7 +270,7 @@ class TServerStorage implements ServerStorage { ) } - async buildRemovedDoc (ctx: MeasureContext, tx: TxRemoveDoc): Promise { + private async buildRemovedDoc (ctx: MeasureContext, tx: TxRemoveDoc): Promise { const txes = await this.findAll(ctx, core.class.TxCUD, { objectId: tx.objectId }, { sort: { modifiedOn: 1 } }) let doc: Doc let createTx = txes.find((tx) => tx._class === core.class.TxCreateDoc) @@ -296,7 +295,7 @@ class TServerStorage implements ServerStorage { return doc } - async processRemove (ctx: MeasureContext, tx: Tx): Promise { + private async processRemove (ctx: MeasureContext, tx: Tx): Promise { const actualTx = TxProcessor.extractTx(tx) if (!this.hierarchy.isDerived(actualTx._class, core.class.TxRemoveDoc)) return [] const rtx = actualTx as TxRemoveDoc @@ -306,14 +305,19 @@ class TServerStorage implements ServerStorage { result.push(...(await this.deleteClassCollections(ctx, object._class, rtx.objectId))) const mixins = this.getMixins(object._class, object) for (const mixin of mixins) { - result.push(...(await this.deleteClassCollections(ctx, mixin, rtx.objectId))) + result.push(...(await this.deleteClassCollections(ctx, mixin, rtx.objectId, object._class))) } result.push(...(await this.deleteRelatedDocuments(ctx, object))) return result } - async deleteClassCollections (ctx: MeasureContext, _class: Ref>, objectId: Ref): Promise { - const attributes = this.hierarchy.getAllAttributes(_class) + private async deleteClassCollections ( + ctx: MeasureContext, + _class: Ref>, + objectId: Ref, + to?: Ref> + ): Promise { + const attributes = this.hierarchy.getAllAttributes(_class, to) const result: Tx[] = [] for (const attribute of attributes) { if (this.hierarchy.isDerived(attribute[1].type._class, core.class.Collection)) { @@ -327,7 +331,7 @@ class TServerStorage implements ServerStorage { return result } - async deleteObject (ctx: MeasureContext, object: Doc): Promise { + private async deleteObject (ctx: MeasureContext, object: Doc): Promise { const result: Tx[] = [] const factory = new TxFactory(core.account.System) if (this.hierarchy.isDerived(object._class, core.class.AttachedDoc)) { @@ -341,20 +345,13 @@ class TServerStorage implements ServerStorage { nestedTx ) result.push(tx) - result.push(...(await this.processCollection(ctx, tx))) } else { result.push(factory.createTxRemoveDoc(object._class, object.space, object._id)) } - result.push(...(await this.deleteClassCollections(ctx, object._class, object._id))) - const mixins = this.getMixins(object._class, object) - for (const mixin of mixins) { - result.push(...(await this.deleteClassCollections(ctx, mixin, object._id))) - } - result.push(...(await this.deleteRelatedDocuments(ctx, object))) return result } - async deleteRelatedDocuments (ctx: MeasureContext, object: Doc): Promise { + private async deleteRelatedDocuments (ctx: MeasureContext, object: Doc): Promise { const result: Tx[] = [] const objectClass = this.hierarchy.getClass(object._class) if (this.hierarchy.hasMixin(objectClass, serverCore.mixin.ObjectDDParticipant)) { @@ -373,7 +370,7 @@ class TServerStorage implements ServerStorage { return result } - async processMove (ctx: MeasureContext, tx: Tx): Promise { + private async processMove (ctx: MeasureContext, tx: Tx): Promise { const actualTx = TxProcessor.extractTx(tx) if (!this.hierarchy.isDerived(actualTx._class, core.class.TxUpdateDoc)) return [] const rtx = actualTx as TxUpdateDoc @@ -392,6 +389,60 @@ class TServerStorage implements ServerStorage { return result } + private async proccessDerived ( + ctx: MeasureContext, + tx: Tx, + _class: Ref>, + triggerFx: Effects + ): Promise { + const fAll = + (mctx: MeasureContext) => + ( + clazz: Ref>, + query: DocumentQuery, + options?: FindOptions + ): Promise> => + this.findAll(mctx, clazz, query, options) + const derived = [ + ...(await ctx.with('process-collection', { _class }, () => this.processCollection(ctx, tx))), + ...(await ctx.with('process-remove', { _class }, () => this.processRemove(ctx, tx))), + ...(await ctx.with('process-move', { _class }, () => this.processMove(ctx, tx))), + ...(await ctx.with('process-triggers', {}, (ctx) => + this.triggers.apply(tx.modifiedBy, tx, { + fx: triggerFx.fx, + fulltextFx: (f) => triggerFx.fx(() => f(this.fulltextAdapter)), + storageFx: (f) => { + const adapter = this.storageAdapter + if (adapter === undefined) { + return + } + + triggerFx.fx(() => f(adapter, this.workspace)) + }, + findAll: fAll(ctx), + modelDb: this.modelDb, + hierarchy: this.hierarchy + }) + )) + ] + + derived.sort((a, b) => a.modifiedOn - b.modifiedOn) + + for (const tx of derived) { + await ctx.with('derived-route-tx', { _class: txClass(tx) }, (ctx) => this.routeTx(ctx, tx)) + } + + const nestedTxes: Tx[] = [] + for (const tx of derived) { + const _class = txClass(tx) + nestedTxes.push(...(await this.proccessDerived(ctx, tx, _class, triggerFx))) + } + + const res = [...derived, ...nestedTxes] + + return res + } + async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> { // store tx const _class = txClass(tx) @@ -408,48 +459,12 @@ class TServerStorage implements ServerStorage { await this.modelDb.tx(tx) } - const fAll = - (mctx: MeasureContext) => - ( - clazz: Ref>, - query: DocumentQuery, - options?: FindOptions - ): Promise> => - this.findAll(mctx, clazz, query, options) - const triggerFx = new Effects() - let derived: Tx[] = [] + // store object const result = await ctx.with('route-tx', { _class, objClass }, (ctx) => this.routeTx(ctx, tx)) // invoke triggers and store derived objects - derived = [ - ...(await ctx.with('process-collection', { _class }, () => this.processCollection(ctx, tx))), - ...(await ctx.with('process-remove', { _class }, () => this.processRemove(ctx, tx))), - ...(await ctx.with('process-move', { _class }, () => this.processMove(ctx, tx))), - ...(await ctx.with('process-triggers', {}, (ctx) => - this.triggers.apply(tx.modifiedBy, tx, { - fx: triggerFx.fx, - fulltextFx: (f) => triggerFx.fx(() => f(this.fulltextAdapter)), - storageFx: (f) => { - const adapter = this.storageAdapter - if (adapter === undefined) { - return - } - - triggerFx.fx(() => f(adapter, this.workspace)) - }, - findAll: fAll(ctx), - modelDb: this.modelDb, - hierarchy: this.hierarchy - }) - )) - ] - - derived.sort((a, b) => a.modifiedOn - b.modifiedOn) - - for (const tx of derived) { - await ctx.with('derived-route-tx', { _class: txClass(tx) }, (ctx) => this.routeTx(ctx, tx)) - } + const derived = await this.proccessDerived(ctx, tx, _class, triggerFx) // index object await ctx.with('fulltext', { _class, objClass }, (ctx) => this.fulltext.tx(ctx, tx)) @@ -502,7 +517,7 @@ function txObjectClass (tx: Tx): string { : (tx as TxCUD).objectClass } -function txClass (tx: Tx): string { +function txClass (tx: Tx): Ref> { return tx._class === core.class.TxCollectionCUD ? (tx as TxCollectionCUD).tx._class : tx._class }