2021-08-03 16:55:52 +00:00
|
|
|
//
|
|
|
|
// Copyright © 2020 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.
|
|
|
|
//
|
|
|
|
|
2022-09-21 08:08:25 +00:00
|
|
|
import { PlatformError, Severity, Status } from '@hcengineering/platform'
|
2024-04-06 08:14:06 +00:00
|
|
|
import { Lookup, MeasureContext, ReverseLookups, getObjectValue } from '.'
|
2024-11-15 04:49:35 +00:00
|
|
|
import type { Account, Class, Doc, Ref } from './classes'
|
2021-08-03 16:55:52 +00:00
|
|
|
import core from './component'
|
2021-11-26 11:05:18 +00:00
|
|
|
import { Hierarchy } from './hierarchy'
|
2023-10-24 08:53:33 +00:00
|
|
|
import { checkMixinKey, matchQuery, resultSort } from './query'
|
2022-01-31 09:06:30 +00:00
|
|
|
import type { DocumentQuery, FindOptions, FindResult, LookupData, Storage, TxResult, WithLookup } from './storage'
|
2024-11-15 04:49:35 +00:00
|
|
|
import type { Tx, TxCreateDoc, TxMixin, TxRemoveDoc, TxUpdateDoc } from './tx'
|
2021-08-03 16:55:52 +00:00
|
|
|
import { TxProcessor } from './tx'
|
2022-04-08 03:06:38 +00:00
|
|
|
import { toFindResult } from './utils'
|
2021-08-03 16:55:52 +00:00
|
|
|
|
2021-08-04 20:24:30 +00:00
|
|
|
/**
|
|
|
|
* @public
|
|
|
|
*/
|
2023-03-22 15:40:47 +00:00
|
|
|
export abstract class MemDb extends TxProcessor implements Storage {
|
2024-04-06 08:14:06 +00:00
|
|
|
private readonly objectsByClass = new Map<Ref<Class<Doc>>, Map<Ref<Doc>, Doc>>()
|
2021-08-03 16:55:52 +00:00
|
|
|
private readonly objectById = new Map<Ref<Doc>, Doc>()
|
|
|
|
|
2024-08-19 05:41:31 +00:00
|
|
|
private readonly accountByPersonId = new Map<Ref<Doc>, Account[]>()
|
2024-10-27 09:49:50 +00:00
|
|
|
private readonly accountByEmail = new Map<string, [string, Account][]>()
|
2024-08-19 05:41:31 +00:00
|
|
|
|
2022-01-13 09:06:50 +00:00
|
|
|
constructor (protected readonly hierarchy: Hierarchy) {
|
2021-08-03 16:55:52 +00:00
|
|
|
super()
|
|
|
|
}
|
|
|
|
|
2024-04-06 08:14:06 +00:00
|
|
|
private getObjectsByClass (_class: Ref<Class<Doc>>): Map<Ref<Doc>, Doc> {
|
2021-08-03 16:55:52 +00:00
|
|
|
const result = this.objectsByClass.get(_class)
|
|
|
|
if (result === undefined) {
|
2024-04-06 08:14:06 +00:00
|
|
|
const result = new Map<Ref<Doc>, Doc>()
|
2021-08-03 16:55:52 +00:00
|
|
|
this.objectsByClass.set(_class, result)
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
private cleanObjectByClass (_class: Ref<Class<Doc>>, _id: Ref<Doc>): void {
|
2024-04-06 08:14:06 +00:00
|
|
|
const result = this.objectsByClass.get(_class)
|
2021-08-03 16:55:52 +00:00
|
|
|
if (result !== undefined) {
|
2024-04-06 08:14:06 +00:00
|
|
|
result.delete(_id)
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private getByIdQuery<T extends Doc>(query: DocumentQuery<T>, _class: Ref<Class<T>>): T[] {
|
|
|
|
const result: T[] = []
|
|
|
|
if (typeof query._id === 'string') {
|
|
|
|
const obj = this.objectById.get(query._id) as T
|
2022-05-06 07:48:02 +00:00
|
|
|
if (obj !== undefined && this.hierarchy.isDerived(obj._class, _class)) result.push(obj)
|
2021-08-03 16:55:52 +00:00
|
|
|
} else if (query._id?.$in !== undefined) {
|
2024-05-10 15:16:07 +00:00
|
|
|
const ids = new Set(query._id.$in)
|
2021-08-03 16:55:52 +00:00
|
|
|
for (const id of ids) {
|
|
|
|
const obj = this.objectById.get(id) as T
|
2022-05-06 07:48:02 +00:00
|
|
|
if (obj !== undefined && this.hierarchy.isDerived(obj._class, _class)) result.push(obj)
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
getObject<T extends Doc>(_id: Ref<T>): T {
|
|
|
|
const doc = this.objectById.get(_id)
|
|
|
|
if (doc === undefined) {
|
|
|
|
throw new PlatformError(new Status(Severity.ERROR, core.status.ObjectNotFound, { _id }))
|
|
|
|
}
|
|
|
|
return doc as T
|
|
|
|
}
|
|
|
|
|
2024-08-19 05:41:31 +00:00
|
|
|
getAccountByPersonId (ref: Ref<Doc>): Account[] {
|
|
|
|
return this.accountByPersonId.get(ref) ?? []
|
|
|
|
}
|
|
|
|
|
2024-09-12 07:04:03 +00:00
|
|
|
getAccountByEmail (email: Account['email']): Account | undefined {
|
2024-10-27 09:49:50 +00:00
|
|
|
const accounts = this.accountByEmail.get(email)
|
|
|
|
if (accounts === undefined || accounts.length === 0) {
|
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
if (accounts.length > 0) {
|
|
|
|
return accounts[accounts.length - 1][1]
|
|
|
|
}
|
2024-09-12 07:04:03 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 16:45:11 +00:00
|
|
|
findObject<T extends Doc>(_id: Ref<T>): T | undefined {
|
|
|
|
const doc = this.objectById.get(_id)
|
|
|
|
return doc as T
|
|
|
|
}
|
|
|
|
|
2022-06-20 04:24:08 +00:00
|
|
|
private async getLookupValue<T extends Doc>(
|
|
|
|
_class: Ref<Class<T>>,
|
|
|
|
doc: T,
|
|
|
|
lookup: Lookup<T>,
|
|
|
|
result: LookupData<T>
|
|
|
|
): Promise<void> {
|
2022-01-31 09:06:30 +00:00
|
|
|
for (const key in lookup) {
|
|
|
|
if (key === '_id') {
|
|
|
|
await this.getReverseLookupValue(doc, lookup, result)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const value = (lookup as any)[key]
|
2022-06-20 04:24:08 +00:00
|
|
|
const tkey = checkMixinKey(key, _class, this.hierarchy)
|
2022-01-31 09:06:30 +00:00
|
|
|
if (Array.isArray(value)) {
|
|
|
|
const [_class, nested] = value
|
2022-06-20 04:24:08 +00:00
|
|
|
const objects = await this.findAll(_class, { _id: getObjectValue(tkey, doc) })
|
2022-01-31 09:06:30 +00:00
|
|
|
;(result as any)[key] = objects[0]
|
|
|
|
const nestedResult = {}
|
|
|
|
const parent = (result as any)[key]
|
2022-06-20 04:24:08 +00:00
|
|
|
await this.getLookupValue(_class, parent, nested, nestedResult)
|
2022-01-31 09:06:30 +00:00
|
|
|
Object.assign(parent, {
|
|
|
|
$lookup: nestedResult
|
|
|
|
})
|
|
|
|
} else {
|
2022-06-20 04:24:08 +00:00
|
|
|
const objects = await this.findAll(value, { _id: getObjectValue(tkey, doc) })
|
2022-01-31 09:06:30 +00:00
|
|
|
;(result as any)[key] = objects[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-08 03:06:38 +00:00
|
|
|
private async getReverseLookupValue<T extends Doc>(
|
|
|
|
doc: T,
|
|
|
|
lookup: ReverseLookups,
|
|
|
|
result: LookupData<T>
|
|
|
|
): Promise<void> {
|
2022-01-31 09:06:30 +00:00
|
|
|
for (const key in lookup._id) {
|
|
|
|
const value = lookup._id[key]
|
2022-03-04 09:01:46 +00:00
|
|
|
if (Array.isArray(value)) {
|
|
|
|
const objects = await this.findAll(value[0], { [value[1]]: doc._id })
|
|
|
|
;(result as any)[key] = objects
|
|
|
|
} else {
|
|
|
|
const objects = await this.findAll(value, { attachedTo: doc._id })
|
|
|
|
;(result as any)[key] = objects
|
|
|
|
}
|
2022-01-31 09:06:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-20 04:24:08 +00:00
|
|
|
private async lookup<T extends Doc>(_class: Ref<Class<T>>, docs: T[], lookup: Lookup<T>): Promise<WithLookup<T>[]> {
|
2021-08-03 16:55:52 +00:00
|
|
|
const withLookup: WithLookup<T>[] = []
|
|
|
|
for (const doc of docs) {
|
|
|
|
const result: LookupData<T> = {}
|
2022-06-20 04:24:08 +00:00
|
|
|
await this.getLookupValue(_class, doc, lookup, result)
|
2021-08-03 16:55:52 +00:00
|
|
|
withLookup.push(Object.assign({}, doc, { $lookup: result }))
|
|
|
|
}
|
|
|
|
return withLookup
|
|
|
|
}
|
|
|
|
|
|
|
|
async findAll<T extends Doc>(
|
|
|
|
_class: Ref<Class<T>>,
|
|
|
|
query: DocumentQuery<T>,
|
|
|
|
options?: FindOptions<T>
|
|
|
|
): Promise<FindResult<T>> {
|
2022-04-08 03:06:38 +00:00
|
|
|
let result: WithLookup<Doc>[]
|
2021-12-30 09:04:32 +00:00
|
|
|
const baseClass = this.hierarchy.getBaseClass(_class)
|
2021-08-03 16:55:52 +00:00
|
|
|
if (
|
|
|
|
Object.prototype.hasOwnProperty.call(query, '_id') &&
|
2021-09-09 10:51:10 +00:00
|
|
|
(typeof query._id === 'string' || query._id?.$in !== undefined || query._id === undefined || query._id === null)
|
2021-08-03 16:55:52 +00:00
|
|
|
) {
|
2021-12-30 09:04:32 +00:00
|
|
|
result = this.getByIdQuery(query, baseClass)
|
2021-08-03 16:55:52 +00:00
|
|
|
} else {
|
2024-04-06 08:14:06 +00:00
|
|
|
result = Array.from(this.getObjectsByClass(baseClass).values())
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
|
2022-05-16 15:39:44 +00:00
|
|
|
result = matchQuery(result, query, _class, this.hierarchy, true)
|
2021-08-03 16:55:52 +00:00
|
|
|
|
2021-12-30 09:04:32 +00:00
|
|
|
if (baseClass !== _class) {
|
|
|
|
// We need to filter instances without mixin was set
|
2022-04-08 03:06:38 +00:00
|
|
|
result = result.filter((r) => (r as any)[_class] !== undefined)
|
2021-12-30 09:04:32 +00:00
|
|
|
}
|
|
|
|
|
2022-05-19 06:38:12 +00:00
|
|
|
if (options?.lookup !== undefined) {
|
2022-06-20 04:24:08 +00:00
|
|
|
result = await this.lookup(_class, result as T[], options.lookup)
|
2022-05-19 06:38:12 +00:00
|
|
|
result = matchQuery(result, query, _class, this.hierarchy)
|
|
|
|
}
|
2021-08-03 16:55:52 +00:00
|
|
|
|
2023-03-22 15:40:47 +00:00
|
|
|
if (options?.sort !== undefined) await resultSort(result, options?.sort, _class, this.hierarchy, this)
|
2022-04-08 03:06:38 +00:00
|
|
|
const total = result.length
|
2021-08-03 16:55:52 +00:00
|
|
|
result = result.slice(0, options?.limit)
|
2022-05-04 14:54:32 +00:00
|
|
|
const tresult = this.hierarchy.clone(result) as WithLookup<T>[]
|
2022-04-08 03:06:38 +00:00
|
|
|
const res = tresult.map((it) => this.hierarchy.updateLookupMixin(_class, it, options))
|
|
|
|
return toFindResult(res, total)
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
|
2023-12-11 11:54:36 +00:00
|
|
|
async findOne<T extends Doc>(
|
|
|
|
_class: Ref<Class<T>>,
|
|
|
|
query: DocumentQuery<T>,
|
|
|
|
options?: FindOptions<T>
|
|
|
|
): Promise<WithLookup<T> | undefined> {
|
|
|
|
return (await this.findAll(_class, query, { ...options, limit: 1 }))[0]
|
|
|
|
}
|
|
|
|
|
2023-10-24 08:53:33 +00:00
|
|
|
/**
|
|
|
|
* Only in model find without lookups and sorting.
|
2024-08-20 12:39:12 +00:00
|
|
|
* Do not clone results, so be aware modifications are not allowed.
|
2023-10-24 08:53:33 +00:00
|
|
|
*/
|
|
|
|
findAllSync<T extends Doc>(_class: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T>): FindResult<T> {
|
|
|
|
let result: WithLookup<Doc>[]
|
|
|
|
const baseClass = this.hierarchy.getBaseClass(_class)
|
|
|
|
if (
|
|
|
|
Object.prototype.hasOwnProperty.call(query, '_id') &&
|
|
|
|
(typeof query._id === 'string' || query._id?.$in !== undefined || query._id === undefined || query._id === null)
|
|
|
|
) {
|
|
|
|
result = this.getByIdQuery(query, baseClass)
|
|
|
|
} else {
|
2024-04-06 08:14:06 +00:00
|
|
|
result = Array.from(this.getObjectsByClass(baseClass).values())
|
2023-10-24 08:53:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = matchQuery(result, query, _class, this.hierarchy, true)
|
|
|
|
|
|
|
|
if (baseClass !== _class) {
|
|
|
|
// We need to filter instances without mixin was set
|
|
|
|
result = result.filter((r) => (r as any)[_class] !== undefined)
|
|
|
|
}
|
|
|
|
const total = result.length
|
|
|
|
result = result.slice(0, options?.limit)
|
2024-08-20 12:39:12 +00:00
|
|
|
|
|
|
|
return toFindResult(
|
|
|
|
result.map((it) => {
|
|
|
|
return baseClass !== _class ? this.hierarchy.as(it, _class) : it
|
|
|
|
}) as WithLookup<T>[],
|
|
|
|
total
|
|
|
|
)
|
2023-10-24 08:53:33 +00:00
|
|
|
}
|
|
|
|
|
2024-10-27 09:49:50 +00:00
|
|
|
addAccount (account: Account): void {
|
|
|
|
if (!this.accountByEmail.has(account.email)) {
|
|
|
|
this.accountByEmail.set(account.email, [])
|
|
|
|
}
|
|
|
|
|
|
|
|
this.accountByEmail.get(account.email)?.push([account._id, account])
|
|
|
|
}
|
|
|
|
|
2021-08-03 16:55:52 +00:00
|
|
|
addDoc (doc: Doc): void {
|
|
|
|
this.hierarchy.getAncestors(doc._class).forEach((_class) => {
|
2023-06-07 17:46:27 +00:00
|
|
|
const arr = this.getObjectsByClass(_class)
|
2024-04-06 08:14:06 +00:00
|
|
|
arr.set(doc._id, doc)
|
2021-08-03 16:55:52 +00:00
|
|
|
})
|
2024-08-19 05:41:31 +00:00
|
|
|
if (this.hierarchy.isDerived(doc._class, core.class.Account)) {
|
|
|
|
const account = doc as Account
|
2024-10-27 09:49:50 +00:00
|
|
|
|
|
|
|
this.addAccount(account)
|
|
|
|
|
2024-08-19 05:41:31 +00:00
|
|
|
if (account.person !== undefined) {
|
|
|
|
this.accountByPersonId.set(account.person, [...(this.accountByPersonId.get(account.person) ?? []), account])
|
|
|
|
}
|
|
|
|
}
|
2021-08-03 16:55:52 +00:00
|
|
|
this.objectById.set(doc._id, doc)
|
|
|
|
}
|
|
|
|
|
2024-10-27 09:49:50 +00:00
|
|
|
delAccount (account: Account): void {
|
|
|
|
const accounts = this.accountByEmail.get(account.email)
|
|
|
|
if (accounts !== undefined) {
|
|
|
|
const newAccounts = accounts.filter((it) => it[0] !== account._id)
|
|
|
|
|
|
|
|
if (newAccounts.length === 0) {
|
|
|
|
this.accountByEmail.delete(account.email)
|
|
|
|
} else {
|
|
|
|
this.accountByEmail.set(account.email, newAccounts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-03 16:55:52 +00:00
|
|
|
delDoc (_id: Ref<Doc>): void {
|
|
|
|
const doc = this.objectById.get(_id)
|
|
|
|
if (doc === undefined) {
|
|
|
|
throw new PlatformError(new Status(Severity.ERROR, core.status.ObjectNotFound, { _id }))
|
|
|
|
}
|
|
|
|
this.objectById.delete(_id)
|
|
|
|
this.hierarchy.getAncestors(doc._class).forEach((_class) => {
|
|
|
|
this.cleanObjectByClass(_class, _id)
|
|
|
|
})
|
2024-08-19 05:41:31 +00:00
|
|
|
if (this.hierarchy.isDerived(doc._class, core.class.Account)) {
|
|
|
|
const account = doc as Account
|
2024-10-27 09:49:50 +00:00
|
|
|
this.delAccount(account)
|
|
|
|
|
2024-08-19 05:41:31 +00:00
|
|
|
if (account.person !== undefined) {
|
|
|
|
const acc = this.accountByPersonId.get(account.person) ?? []
|
|
|
|
this.accountByPersonId.set(
|
|
|
|
account.person,
|
|
|
|
acc.filter((it) => it._id !== _id)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateDoc (_id: Ref<Doc>, doc: Doc, update: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): void {
|
2024-09-13 09:38:59 +00:00
|
|
|
if (this.hierarchy.isDerived(doc._class, core.class.Account) && update._class === core.class.TxUpdateDoc) {
|
|
|
|
const newEmail = (update as TxUpdateDoc<Account>).operations.email
|
|
|
|
if ((update as TxUpdateDoc<Account>).operations.person !== undefined) {
|
|
|
|
const account = doc as Account
|
|
|
|
if (account.person !== undefined) {
|
|
|
|
const acc = this.accountByPersonId.get(account.person) ?? []
|
|
|
|
this.accountByPersonId.set(
|
|
|
|
account.person,
|
|
|
|
acc.filter((it) => it._id !== _id)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
const newPerson = (update as TxUpdateDoc<Account>).operations.person
|
|
|
|
if (newPerson !== undefined) {
|
|
|
|
this.accountByPersonId.set(newPerson, [...(this.accountByPersonId.get(newPerson) ?? []), account])
|
|
|
|
}
|
|
|
|
} else if (newEmail !== undefined) {
|
|
|
|
const account = doc as Account
|
2024-10-27 09:49:50 +00:00
|
|
|
this.delAccount(account)
|
|
|
|
this.addAccount({ ...account, email: newEmail })
|
2024-08-19 05:41:31 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hold transactions
|
2021-08-04 20:24:30 +00:00
|
|
|
*
|
2021-08-04 18:11:33 +00:00
|
|
|
* @public
|
2021-08-03 16:55:52 +00:00
|
|
|
*/
|
2023-03-22 15:40:47 +00:00
|
|
|
export class TxDb extends MemDb {
|
2021-10-13 16:46:48 +00:00
|
|
|
protected txCreateDoc (tx: TxCreateDoc<Doc>): Promise<TxResult> {
|
2021-09-15 10:53:11 +00:00
|
|
|
throw new Error('Method not implemented.')
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:46:48 +00:00
|
|
|
protected txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<TxResult> {
|
2021-09-15 10:53:11 +00:00
|
|
|
throw new Error('Method not implemented.')
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:46:48 +00:00
|
|
|
protected txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<TxResult> {
|
2021-09-15 10:53:11 +00:00
|
|
|
throw new Error('Method not implemented.')
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:46:48 +00:00
|
|
|
protected txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult> {
|
2021-09-15 10:53:11 +00:00
|
|
|
throw new Error('Method not implemented.')
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:55:03 +00:00
|
|
|
async tx (tx: Tx): Promise<TxResult[]> {
|
2021-08-03 16:55:52 +00:00
|
|
|
this.addDoc(tx)
|
2024-02-09 15:55:03 +00:00
|
|
|
return []
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hold model objects and classes
|
2021-08-04 20:24:30 +00:00
|
|
|
*
|
2021-08-04 18:11:33 +00:00
|
|
|
* @public
|
2021-08-03 16:55:52 +00:00
|
|
|
*/
|
2023-03-22 15:40:47 +00:00
|
|
|
export class ModelDb extends MemDb {
|
2021-10-13 16:46:48 +00:00
|
|
|
protected override async txCreateDoc (tx: TxCreateDoc<Doc>): Promise<TxResult> {
|
2021-08-03 16:55:52 +00:00
|
|
|
this.addDoc(TxProcessor.createDoc2Doc(tx))
|
2021-10-13 16:46:48 +00:00
|
|
|
return {}
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
|
2024-04-06 08:14:06 +00:00
|
|
|
addTxes (ctx: MeasureContext, txes: Tx[], clone: boolean): void {
|
|
|
|
for (const tx of txes) {
|
|
|
|
switch (tx._class) {
|
|
|
|
case core.class.TxCreateDoc:
|
|
|
|
this.addDoc(TxProcessor.createDoc2Doc(tx as TxCreateDoc<Doc>, clone))
|
|
|
|
break
|
|
|
|
case core.class.TxUpdateDoc: {
|
|
|
|
const cud = tx as TxUpdateDoc<Doc>
|
|
|
|
const doc = this.findObject(cud.objectId)
|
|
|
|
if (doc !== undefined) {
|
2024-08-19 05:41:31 +00:00
|
|
|
this.updateDoc(cud.objectId, doc, cud)
|
2024-04-06 08:14:06 +00:00
|
|
|
TxProcessor.updateDoc2Doc(doc, cud)
|
|
|
|
} else {
|
2024-04-25 15:15:11 +00:00
|
|
|
ctx.error('no document found, failed to apply model transaction, skipping', {
|
2024-04-06 08:14:06 +00:00
|
|
|
_id: tx._id,
|
|
|
|
_class: tx._class,
|
|
|
|
objectId: cud.objectId
|
|
|
|
})
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
case core.class.TxRemoveDoc:
|
|
|
|
try {
|
|
|
|
this.delDoc((tx as TxRemoveDoc<Doc>).objectId)
|
|
|
|
} catch (err: any) {
|
2024-04-25 15:15:11 +00:00
|
|
|
ctx.error('no document found, failed to apply model transaction, skipping', {
|
2024-04-06 08:14:06 +00:00
|
|
|
_id: tx._id,
|
|
|
|
_class: tx._class,
|
|
|
|
objectId: (tx as TxRemoveDoc<Doc>).objectId
|
|
|
|
})
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case core.class.TxMixin: {
|
|
|
|
const mix = tx as TxMixin<Doc, Doc>
|
2024-08-19 05:41:31 +00:00
|
|
|
const doc = this.findObject(mix.objectId)
|
|
|
|
if (doc !== undefined) {
|
|
|
|
this.updateDoc(mix.objectId, doc, mix)
|
|
|
|
TxProcessor.updateMixin4Doc(doc, mix)
|
2024-04-06 08:14:06 +00:00
|
|
|
} else {
|
2024-04-25 15:15:11 +00:00
|
|
|
ctx.error('no document found, failed to apply model transaction, skipping', {
|
2024-04-06 08:14:06 +00:00
|
|
|
_id: tx._id,
|
|
|
|
_class: tx._class,
|
|
|
|
objectId: mix.objectId
|
|
|
|
})
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 16:46:48 +00:00
|
|
|
protected async txUpdateDoc (tx: TxUpdateDoc<Doc>): Promise<TxResult> {
|
2024-08-07 06:40:50 +00:00
|
|
|
try {
|
|
|
|
const doc = this.getObject(tx.objectId) as any
|
2024-08-19 05:41:31 +00:00
|
|
|
this.updateDoc(tx.objectId, doc, tx)
|
2024-08-07 06:40:50 +00:00
|
|
|
TxProcessor.updateDoc2Doc(doc, tx)
|
|
|
|
return tx.retrieve === true ? { object: doc } : {}
|
|
|
|
} catch (err: any) {}
|
|
|
|
return {}
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
|
2021-10-13 16:46:48 +00:00
|
|
|
protected async txRemoveDoc (tx: TxRemoveDoc<Doc>): Promise<TxResult> {
|
2024-08-07 06:40:50 +00:00
|
|
|
try {
|
|
|
|
this.delDoc(tx.objectId)
|
|
|
|
} catch (err: any) {}
|
2021-10-13 16:46:48 +00:00
|
|
|
return {}
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: process ancessor mixins
|
2021-10-13 16:46:48 +00:00
|
|
|
protected async txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult> {
|
2024-08-19 05:41:31 +00:00
|
|
|
const doc = this.getObject(tx.objectId) as any
|
|
|
|
this.updateDoc(tx.objectId, doc, tx)
|
|
|
|
TxProcessor.updateMixin4Doc(doc, tx)
|
2021-10-13 16:46:48 +00:00
|
|
|
return {}
|
2021-08-03 16:55:52 +00:00
|
|
|
}
|
|
|
|
}
|