diff --git a/packages/core/src/operations.ts b/packages/core/src/operations.ts index 60fb77eb5c..75daac4b3f 100644 --- a/packages/core/src/operations.ts +++ b/packages/core/src/operations.ts @@ -219,7 +219,7 @@ export class TxOperations implements Omit { return this.client.tx(tx) } - update( + async update( doc: T, update: DocumentUpdate, retrieve?: boolean, @@ -229,13 +229,22 @@ export class TxOperations implements Omit { const hierarchy = this.client.getHierarchy() const mixClass = Hierarchy.mixinOrClass(doc) if (hierarchy.isMixin(mixClass)) { - // TODO: Rework it is wrong, we need to split values to mixin update and original document update if mixed. const baseClass = hierarchy.getBaseClass(doc._class) - return this.updateMixin(doc._id, baseClass, doc.space, mixClass, update, modifiedOn, modifiedBy) + + const byClass = this.splitMixinUpdate(update, mixClass, baseClass) + const ops = this.apply(doc._id) + for (const it of byClass) { + if (hierarchy.isMixin(it[0])) { + await ops.updateMixin(doc._id, baseClass, doc.space, it[0], it[1], modifiedOn, modifiedBy) + } else { + await ops.updateDoc(it[0], doc.space, doc._id, it[1], retrieve, modifiedOn, modifiedBy) + } + } + return await ops.commit() } if (hierarchy.isDerived(doc._class, core.class.AttachedDoc)) { const adoc = doc as unknown as AttachedDoc - return this.updateCollection( + return await this.updateCollection( doc._class, doc.space, adoc._id, @@ -248,7 +257,7 @@ export class TxOperations implements Omit { modifiedBy ) } - return this.updateDoc(doc._class, doc.space, doc._id, update, retrieve, modifiedOn, modifiedBy) + return await this.updateDoc(doc._class, doc.space, doc._id, update, retrieve, modifiedOn, modifiedBy) } remove(doc: T, modifiedOn?: Timestamp, modifiedBy?: Ref): Promise { @@ -322,6 +331,56 @@ export class TxOperations implements Omit { } return doc } + + private splitMixinUpdate( + update: DocumentUpdate, + mixClass: Ref>, + baseClass: Ref> + ): Map>, DocumentUpdate> { + const hierarchy = this.getHierarchy() + const attributes = hierarchy.getAllAttributes(mixClass) + + const updateAttrs = Object.fromEntries( + Object.entries(update).filter((it) => !it[0].startsWith('$')) + ) as DocumentUpdate + const updateOps = Object.fromEntries( + Object.entries(update).filter((it) => it[0].startsWith('$')) + ) as DocumentUpdate + + const result: Map>, DocumentUpdate> = this.splitObjectAttributes( + updateAttrs, + baseClass, + attributes + ) + + for (const [key, value] of Object.entries(updateOps)) { + const updates = this.splitObjectAttributes(value as object, baseClass, attributes) + + for (const [opsClass, opsUpdate] of updates) { + const upd: DocumentUpdate = result.get(opsClass) ?? {} + result.set(opsClass, { ...upd, [key]: opsUpdate }) + } + } + + return result + } + + private splitObjectAttributes( + obj: T, + objClass: Ref>, + attributes: Map + ): Map>, object> { + const hierarchy = this.getHierarchy() + + const result: Map>, any> = new Map() + for (const [key, value] of Object.entries(obj)) { + const attributeOf = attributes.get(key)?.attributeOf + const clazz = attributeOf !== undefined && hierarchy.isMixin(attributeOf) ? attributeOf : objClass + result.set(clazz, { ...(result.get(clazz) ?? {}), [key]: value }) + } + + return result + } } /** diff --git a/packages/platform-rig/profiles/default/tsconfig.json b/packages/platform-rig/profiles/default/tsconfig.json index 7eba506e7b..f951726449 100644 --- a/packages/platform-rig/profiles/default/tsconfig.json +++ b/packages/platform-rig/profiles/default/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2017", + "target": "ES2019", "module": "commonjs", "declaration": true, "strict": true,