// // 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, Tx, TxCreateDoc, TxFactory, TxMixin, ExtendedAttributes } from './classes' import core from './component' import { generateId } from './utils' /** * @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 interface TxOperations { createDoc: (_class: Ref>, space: Ref, attributes: Data) => Promise updateDoc: ( _class: Ref>, space: Ref, objectId: Ref, operations: DocumentUpdate ) => Promise removeDoc: (_class: Ref>, space: Ref, objectId: Ref) => Promise } /** * @public */ export function withOperations (user: Ref, storage: T): T & TxOperations { const result = storage as T & TxOperations result.createDoc = async ( _class: Ref>, space: Ref, attributes: Data ): Promise => { const tx: TxCreateDoc = { _id: generateId(), _class: core.class.TxCreateDoc, space: core.space.Tx, modifiedBy: user, modifiedOn: Date.now(), objectId: generateId(), objectClass: _class, objectSpace: space, attributes } await storage.tx(tx) return TxProcessor.createDoc2Doc(tx) } result.updateDoc = async ( _class: Ref>, space: Ref, objectId: Ref, operations: DocumentUpdate ): Promise => { const tx: TxUpdateDoc = { _id: generateId(), _class: core.class.TxUpdateDoc, space: core.space.Tx, modifiedBy: user, modifiedOn: Date.now(), objectId, objectClass: _class, objectSpace: space, operations } await storage.tx(tx) } result.removeDoc = async ( _class: Ref>, space: Ref, objectId: Ref ): Promise => { const tx: TxRemoveDoc = { _id: generateId(), _class: core.class.TxRemoveDoc, space: core.space.Tx, modifiedBy: user, modifiedOn: Date.now(), objectId, objectClass: _class, objectSpace: space } await storage.tx(tx) } return result } /** * @public */ export class DefaultTxFactory implements 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 } } 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 } } }