// // Copyright © 2020, 2021 Anticrm Platform Contributors. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // limitations under the License. // import type { KeysByType } from 'simplytyped' import type { Class, Data, Doc, Domain, Ref, Account, Space, Arr, Mixin } from './classes' import { DocumentQuery, FindOptions, FindResult, Storage } from './storage' import core from './component' import { generateId } from './utils' /** * @public */ export interface Tx extends Doc { objectId: Ref objectClass: Ref> objectSpace: Ref } /** * @public */ export interface TxCreateDoc extends Tx { attributes: Data } /** * @public */ export type ExtendedAttributes = Omit /** * @public */ export interface TxMixin extends Tx { mixin: Ref> attributes: ExtendedAttributes } /** * @public */ export type ArrayAsElement = { [P in keyof T]: T[P] extends Arr ? X : never } /** * @public */ export type OmitNever = Omit> /** * @public */ export interface PushOptions { $push?: Partial>> } /** * @public */ export type DocumentUpdate = Partial> & PushOptions /** * @public */ export interface TxUpdateDoc extends Tx { operations: DocumentUpdate } /** * @public */ export interface TxRemoveDoc extends Tx { } /** * @public */ export const DOMAIN_TX = 'tx' as Domain /** * @public */ export interface WithTx { tx: (tx: Tx) => Promise } /** * @public */ export class TxProcessor implements WithTx { async tx (tx: Tx): Promise { switch (tx._class) { case core.class.TxCreateDoc: return await this.txCreateDoc(tx as TxCreateDoc) case core.class.TxUpdateDoc: return await this.txUpdateDoc(tx as TxUpdateDoc) case core.class.TxRemoveDoc: return await this.txRemoveDoc(tx as TxRemoveDoc) case core.class.TxMixin: return await this.txMixin(tx as TxMixin) } } static createDoc2Doc (tx: TxCreateDoc): T { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions return { _id: tx.objectId, _class: tx.objectClass, space: tx.objectSpace, modifiedBy: tx.modifiedBy, modifiedOn: tx.modifiedOn, ...tx.attributes } as T } protected async txCreateDoc (tx: TxCreateDoc): Promise {} protected async txUpdateDoc (tx: TxUpdateDoc): Promise {} protected async txRemoveDoc (tx: TxRemoveDoc): Promise {} protected async txMixin (tx: TxMixin): Promise {} } /** * @public */ export class TxOperations implements Storage { private readonly txFactory: TxFactory constructor (private readonly storage: Storage, user: Ref) { this.txFactory = new TxFactory(user) } findAll (_class: Ref>, query: DocumentQuery, options?: FindOptions | undefined): Promise> { return this.storage.findAll(_class, query, options) } tx (tx: Tx): Promise { return this.storage.tx(tx) } async createDoc ( _class: Ref>, space: Ref, attributes: Data ): Promise> { const tx = this.txFactory.createTxCreateDoc(_class, space, attributes) await this.storage.tx(tx) return tx.objectId } updateDoc ( _class: Ref>, space: Ref, objectId: Ref, operations: DocumentUpdate ): Promise { const tx = this.txFactory.createTxUpdateDoc(_class, space, objectId, operations) return this.storage.tx(tx) } removeDoc ( _class: Ref>, space: Ref, objectId: Ref ): Promise { const tx = this.txFactory.createTxRemoveDoc(_class, space, objectId) return this.storage.tx(tx) } } /** * @public */ export class TxFactory { constructor (readonly account: Ref) {} createTxCreateDoc(_class: Ref>, space: Ref, attributes: Data, objectId?: Ref): TxCreateDoc { return { _id: generateId(), _class: core.class.TxCreateDoc, space: core.space.Tx, objectId: objectId ?? generateId(), objectClass: _class, objectSpace: space, modifiedOn: Date.now(), modifiedBy: this.account, attributes } } createTxUpdateDoc ( _class: Ref>, space: Ref, objectId: Ref, operations: DocumentUpdate ): TxUpdateDoc { return { _id: generateId(), _class: core.class.TxUpdateDoc, space: core.space.Tx, modifiedBy: this.account, modifiedOn: Date.now(), objectId, objectClass: _class, objectSpace: space, operations } } createTxRemoveDoc ( _class: Ref>, space: Ref, objectId: Ref ): TxRemoveDoc { return { _id: generateId(), _class: core.class.TxRemoveDoc, space: core.space.Tx, modifiedBy: this.account, modifiedOn: Date.now(), objectId, objectClass: _class, objectSpace: space } } createTxMixin(objectId: Ref, objectClass: Ref>, mixin: Ref>, attributes: ExtendedAttributes): TxMixin { return { _id: generateId(), _class: core.class.TxMixin, space: core.space.Tx, modifiedBy: this.account, modifiedOn: Date.now(), objectId, objectClass, objectSpace: core.space.Model, mixin, attributes } } }