recursive derived data (#2252)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-08-21 13:03:32 +06:00 committed by GitHub
parent 4581bb34cc
commit 854331ae5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 69 deletions

View File

@ -143,6 +143,10 @@ export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise<
return [] return []
} }
if ((actualTx as TxCUD<Doc>).objectClass === notification.class.LastView) {
return []
}
const result: Tx[] = [] const result: Tx[] = []
switch (actualTx._class) { switch (actualTx._class) {

View File

@ -197,7 +197,7 @@ class TServerStorage implements ServerStorage {
return [...(oldTx !== null ? [oldTx] : []), ...(newTx !== null ? [newTx] : [])] return [...(oldTx !== null ? [oldTx] : []), ...(newTx !== null ? [newTx] : [])]
} }
async processCollection (ctx: MeasureContext, tx: Tx): Promise<Tx[]> { private async processCollection (ctx: MeasureContext, tx: Tx): Promise<Tx[]> {
if (tx._class === core.class.TxCollectionCUD) { if (tx._class === core.class.TxCollectionCUD) {
const colTx = tx as TxCollectionCUD<Doc, AttachedDoc> const colTx = tx as TxCollectionCUD<Doc, AttachedDoc>
const _id = colTx.objectId const _id = colTx.objectId
@ -212,11 +212,11 @@ class TServerStorage implements ServerStorage {
const isCreateTx = colTx.tx._class === core.class.TxCreateDoc const isCreateTx = colTx.tx._class === core.class.TxCreateDoc
const isDeleteTx = colTx.tx._class === core.class.TxRemoveDoc const isDeleteTx = colTx.tx._class === core.class.TxRemoveDoc
const isUpdateTx = colTx.tx._class === core.class.TxUpdateDoc const isUpdateTx = colTx.tx._class === core.class.TxUpdateDoc
if (isCreateTx || isDeleteTx || isUpdateTx) {
if (isUpdateTx) { if (isUpdateTx) {
return await this.updateCollection(ctx, tx) return await this.updateCollection(ctx, tx)
} else { }
if (isCreateTx || isDeleteTx) {
const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0] const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0]
if (attachedTo !== undefined) { if (attachedTo !== undefined) {
return [ return [
@ -227,7 +227,6 @@ class TServerStorage implements ServerStorage {
} }
} }
} }
}
return [] return []
} }
@ -248,7 +247,7 @@ class TServerStorage implements ServerStorage {
}) })
} }
getParentClass (_class: Ref<Class<Doc>>): Ref<Class<Doc>> { private getParentClass (_class: Ref<Class<Doc>>): Ref<Class<Doc>> {
const baseDomain = this.hierarchy.getDomain(_class) const baseDomain = this.hierarchy.getDomain(_class)
const ancestors = this.hierarchy.getAncestors(_class) const ancestors = this.hierarchy.getAncestors(_class)
let result: Ref<Class<Doc>> = _class let result: Ref<Class<Doc>> = _class
@ -263,7 +262,7 @@ class TServerStorage implements ServerStorage {
return result return result
} }
getMixins (_class: Ref<Class<Doc>>, object: Doc): Array<Ref<Mixin<Doc>>> { private getMixins (_class: Ref<Class<Doc>>, object: Doc): Array<Ref<Mixin<Doc>>> {
const parentClass = this.getParentClass(_class) const parentClass = this.getParentClass(_class)
const descendants = this.hierarchy.getDescendants(parentClass) const descendants = this.hierarchy.getDescendants(parentClass)
return descendants.filter( return descendants.filter(
@ -271,7 +270,7 @@ class TServerStorage implements ServerStorage {
) )
} }
async buildRemovedDoc (ctx: MeasureContext, tx: TxRemoveDoc<Doc>): Promise<Doc | undefined> { private async buildRemovedDoc (ctx: MeasureContext, tx: TxRemoveDoc<Doc>): Promise<Doc | undefined> {
const txes = await this.findAll(ctx, core.class.TxCUD, { objectId: tx.objectId }, { sort: { modifiedOn: 1 } }) const txes = await this.findAll(ctx, core.class.TxCUD, { objectId: tx.objectId }, { sort: { modifiedOn: 1 } })
let doc: Doc let doc: Doc
let createTx = txes.find((tx) => tx._class === core.class.TxCreateDoc) let createTx = txes.find((tx) => tx._class === core.class.TxCreateDoc)
@ -296,7 +295,7 @@ class TServerStorage implements ServerStorage {
return doc return doc
} }
async processRemove (ctx: MeasureContext, tx: Tx): Promise<Tx[]> { private async processRemove (ctx: MeasureContext, tx: Tx): Promise<Tx[]> {
const actualTx = TxProcessor.extractTx(tx) const actualTx = TxProcessor.extractTx(tx)
if (!this.hierarchy.isDerived(actualTx._class, core.class.TxRemoveDoc)) return [] if (!this.hierarchy.isDerived(actualTx._class, core.class.TxRemoveDoc)) return []
const rtx = actualTx as TxRemoveDoc<Doc> const rtx = actualTx as TxRemoveDoc<Doc>
@ -306,14 +305,19 @@ class TServerStorage implements ServerStorage {
result.push(...(await this.deleteClassCollections(ctx, object._class, rtx.objectId))) result.push(...(await this.deleteClassCollections(ctx, object._class, rtx.objectId)))
const mixins = this.getMixins(object._class, object) const mixins = this.getMixins(object._class, object)
for (const mixin of mixins) { 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))) result.push(...(await this.deleteRelatedDocuments(ctx, object)))
return result return result
} }
async deleteClassCollections (ctx: MeasureContext, _class: Ref<Class<Doc>>, objectId: Ref<Doc>): Promise<Tx[]> { private async deleteClassCollections (
const attributes = this.hierarchy.getAllAttributes(_class) ctx: MeasureContext,
_class: Ref<Class<Doc>>,
objectId: Ref<Doc>,
to?: Ref<Class<Doc>>
): Promise<Tx[]> {
const attributes = this.hierarchy.getAllAttributes(_class, to)
const result: Tx[] = [] const result: Tx[] = []
for (const attribute of attributes) { for (const attribute of attributes) {
if (this.hierarchy.isDerived(attribute[1].type._class, core.class.Collection)) { if (this.hierarchy.isDerived(attribute[1].type._class, core.class.Collection)) {
@ -327,7 +331,7 @@ class TServerStorage implements ServerStorage {
return result return result
} }
async deleteObject (ctx: MeasureContext, object: Doc): Promise<Tx[]> { private async deleteObject (ctx: MeasureContext, object: Doc): Promise<Tx[]> {
const result: Tx[] = [] const result: Tx[] = []
const factory = new TxFactory(core.account.System) const factory = new TxFactory(core.account.System)
if (this.hierarchy.isDerived(object._class, core.class.AttachedDoc)) { if (this.hierarchy.isDerived(object._class, core.class.AttachedDoc)) {
@ -341,20 +345,13 @@ class TServerStorage implements ServerStorage {
nestedTx nestedTx
) )
result.push(tx) result.push(tx)
result.push(...(await this.processCollection(ctx, tx)))
} else { } else {
result.push(factory.createTxRemoveDoc(object._class, object.space, object._id)) 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 return result
} }
async deleteRelatedDocuments (ctx: MeasureContext, object: Doc): Promise<Tx[]> { private async deleteRelatedDocuments (ctx: MeasureContext, object: Doc): Promise<Tx[]> {
const result: Tx[] = [] const result: Tx[] = []
const objectClass = this.hierarchy.getClass(object._class) const objectClass = this.hierarchy.getClass(object._class)
if (this.hierarchy.hasMixin(objectClass, serverCore.mixin.ObjectDDParticipant)) { if (this.hierarchy.hasMixin(objectClass, serverCore.mixin.ObjectDDParticipant)) {
@ -373,7 +370,7 @@ class TServerStorage implements ServerStorage {
return result return result
} }
async processMove (ctx: MeasureContext, tx: Tx): Promise<Tx[]> { private async processMove (ctx: MeasureContext, tx: Tx): Promise<Tx[]> {
const actualTx = TxProcessor.extractTx(tx) const actualTx = TxProcessor.extractTx(tx)
if (!this.hierarchy.isDerived(actualTx._class, core.class.TxUpdateDoc)) return [] if (!this.hierarchy.isDerived(actualTx._class, core.class.TxUpdateDoc)) return []
const rtx = actualTx as TxUpdateDoc<Doc> const rtx = actualTx as TxUpdateDoc<Doc>
@ -392,22 +389,12 @@ class TServerStorage implements ServerStorage {
return result return result
} }
async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> { private async proccessDerived (
// store tx ctx: MeasureContext,
const _class = txClass(tx) tx: Tx,
const objClass = txObjectClass(tx) _class: Ref<Class<Tx>>,
return await ctx.with('tx', { _class, objClass }, async (ctx) => { triggerFx: Effects
if (tx.space !== core.space.DerivedTx) { ): Promise<Tx[]> {
await ctx.with('domain-tx', { _class, objClass }, async () => await this.getAdapter(DOMAIN_TX).tx(tx))
}
if (tx.objectSpace === core.space.Model) {
// maintain hiearachy and triggers
this.hierarchy.tx(tx)
await this.triggers.tx(tx)
await this.modelDb.tx(tx)
}
const fAll = const fAll =
(mctx: MeasureContext) => (mctx: MeasureContext) =>
<T extends Doc>( <T extends Doc>(
@ -416,13 +403,7 @@ class TServerStorage implements ServerStorage {
options?: FindOptions<T> options?: FindOptions<T>
): Promise<FindResult<T>> => ): Promise<FindResult<T>> =>
this.findAll(mctx, clazz, query, options) this.findAll(mctx, clazz, query, options)
const derived = [
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-collection', { _class }, () => this.processCollection(ctx, tx))),
...(await ctx.with('process-remove', { _class }, () => this.processRemove(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-move', { _class }, () => this.processMove(ctx, tx))),
@ -451,6 +432,40 @@ class TServerStorage implements ServerStorage {
await ctx.with('derived-route-tx', { _class: txClass(tx) }, (ctx) => this.routeTx(ctx, tx)) 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)
const objClass = txObjectClass(tx)
return await ctx.with('tx', { _class, objClass }, async (ctx) => {
if (tx.space !== core.space.DerivedTx) {
await ctx.with('domain-tx', { _class, objClass }, async () => await this.getAdapter(DOMAIN_TX).tx(tx))
}
if (tx.objectSpace === core.space.Model) {
// maintain hiearachy and triggers
this.hierarchy.tx(tx)
await this.triggers.tx(tx)
await this.modelDb.tx(tx)
}
const triggerFx = new Effects()
// store object
const result = await ctx.with('route-tx', { _class, objClass }, (ctx) => this.routeTx(ctx, tx))
// invoke triggers and store derived objects
const derived = await this.proccessDerived(ctx, tx, _class, triggerFx)
// index object // index object
await ctx.with('fulltext', { _class, objClass }, (ctx) => this.fulltext.tx(ctx, tx)) await ctx.with('fulltext', { _class, objClass }, (ctx) => this.fulltext.tx(ctx, tx))
// index derived objects // index derived objects
@ -502,7 +517,7 @@ function txObjectClass (tx: Tx): string {
: (tx as TxCUD<Doc>).objectClass : (tx as TxCUD<Doc>).objectClass
} }
function txClass (tx: Tx): string { function txClass (tx: Tx): Ref<Class<Tx>> {
return tx._class === core.class.TxCollectionCUD ? (tx as TxCollectionCUD<Doc, AttachedDoc>).tx._class : tx._class return tx._class === core.class.TxCollectionCUD ? (tx as TxCollectionCUD<Doc, AttachedDoc>).tx._class : tx._class
} }