mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 21:50:34 +03:00
recursive derived data (#2252)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
4581bb34cc
commit
854331ae5f
@ -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) {
|
||||||
|
@ -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,19 +212,18 @@ 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 (isUpdateTx) {
|
||||||
|
return await this.updateCollection(ctx, tx)
|
||||||
|
}
|
||||||
|
|
||||||
if (isCreateTx || isDeleteTx || isUpdateTx) {
|
if (isCreateTx || isDeleteTx) {
|
||||||
if (isUpdateTx) {
|
const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0]
|
||||||
return await this.updateCollection(ctx, tx)
|
if (attachedTo !== undefined) {
|
||||||
} else {
|
return [
|
||||||
const attachedTo = (await this.findAll(ctx, _class, { _id }, { limit: 1 }))[0]
|
await this.getCollectionUpdateTx(_id, _class, tx.modifiedBy, colTx.modifiedOn, attachedTo, {
|
||||||
if (attachedTo !== undefined) {
|
$inc: { [colTx.collection]: isCreateTx ? 1 : -1 }
|
||||||
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<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,6 +389,60 @@ class TServerStorage implements ServerStorage {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async proccessDerived (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
tx: Tx,
|
||||||
|
_class: Ref<Class<Tx>>,
|
||||||
|
triggerFx: Effects
|
||||||
|
): Promise<Tx[]> {
|
||||||
|
const fAll =
|
||||||
|
(mctx: MeasureContext) =>
|
||||||
|
<T extends Doc>(
|
||||||
|
clazz: Ref<Class<T>>,
|
||||||
|
query: DocumentQuery<T>,
|
||||||
|
options?: FindOptions<T>
|
||||||
|
): Promise<FindResult<T>> =>
|
||||||
|
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[]]> {
|
async tx (ctx: MeasureContext, tx: Tx): Promise<[TxResult, Tx[]]> {
|
||||||
// store tx
|
// store tx
|
||||||
const _class = txClass(tx)
|
const _class = txClass(tx)
|
||||||
@ -408,48 +459,12 @@ class TServerStorage implements ServerStorage {
|
|||||||
await this.modelDb.tx(tx)
|
await this.modelDb.tx(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fAll =
|
|
||||||
(mctx: MeasureContext) =>
|
|
||||||
<T extends Doc>(
|
|
||||||
clazz: Ref<Class<T>>,
|
|
||||||
query: DocumentQuery<T>,
|
|
||||||
options?: FindOptions<T>
|
|
||||||
): Promise<FindResult<T>> =>
|
|
||||||
this.findAll(mctx, clazz, query, options)
|
|
||||||
|
|
||||||
const triggerFx = new Effects()
|
const triggerFx = new Effects()
|
||||||
let derived: Tx[] = []
|
|
||||||
// store object
|
// store object
|
||||||
const result = await ctx.with('route-tx', { _class, objClass }, (ctx) => this.routeTx(ctx, tx))
|
const result = await ctx.with('route-tx', { _class, objClass }, (ctx) => this.routeTx(ctx, tx))
|
||||||
// invoke triggers and store derived objects
|
// invoke triggers and store derived objects
|
||||||
derived = [
|
const derived = await this.proccessDerived(ctx, tx, _class, triggerFx)
|
||||||
...(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))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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))
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user