diff --git a/packages/core/src/__tests__/memdb.test.ts b/packages/core/src/__tests__/memdb.test.ts index e80d8642df..4e8bed31e4 100644 --- a/packages/core/src/__tests__/memdb.test.ts +++ b/packages/core/src/__tests__/memdb.test.ts @@ -29,7 +29,7 @@ import { SearchResult } from '../storage' import { Tx } from '../tx' -import { genMinModel, test, TestMixin } from './minmodel' +import { createDoc, deleteDoc, genMinModel, test, TestMixin, updateDoc } from './minmodel' const txes = genMinModel() @@ -59,17 +59,17 @@ class ClientModel extends ModelDb implements Client { async close (): Promise {} } -async function createModel (): Promise<{ model: ClientModel, hierarchy: Hierarchy, txDb: TxDb }> { +async function createModel (modelTxes: Tx[] = txes): Promise<{ model: ClientModel, hierarchy: Hierarchy, txDb: TxDb }> { const hierarchy = new Hierarchy() - for (const tx of txes) { + for (const tx of modelTxes) { hierarchy.tx(tx) } const model = new ClientModel(hierarchy) - for (const tx of txes) { + for (const tx of modelTxes) { await model.tx(tx) } const txDb = new TxDb(hierarchy) - for (const tx of txes) await txDb.tx(tx) + for (const tx of modelTxes) await txDb.tx(tx) return { model, hierarchy, txDb } } @@ -78,7 +78,7 @@ describe('memdb', () => { const { txDb } = await createModel() const result = await txDb.findAll(core.class.Tx, {}) - expect(result.length).toBe(txes.filter((tx) => tx._class === core.class.TxCreateDoc).length) + expect(result.length).toBe(txes.length) }) it('should create space', async () => { @@ -396,4 +396,41 @@ describe('memdb', () => { expect(e).toEqual(new Error('createDoc cannot be used for objects inherited from AttachedDoc')) } }) + + it('has correct accounts', async () => { + const modTxes = [...txes] + + modTxes.push( + createDoc(core.class.Account, { + email: 'system_admin', + role: AccountRole.Owner + }) + ) + + const system1Account = createDoc(core.class.Account, { + email: 'system1', + role: AccountRole.Maintainer + }) + modTxes.push(system1Account) + + const user1Account = createDoc(core.class.Account, { + email: 'user1', + role: AccountRole.User + }) + modTxes.push(user1Account) + + modTxes.push(updateDoc(core.class.Account, core.space.Model, system1Account.objectId, { email: 'user1' })) + + modTxes.push(deleteDoc(core.class.Account, core.space.Model, user1Account.objectId)) + + const { model } = await createModel(modTxes) + + expect(model.getAccountByEmail('system_admin')).not.toBeUndefined() + expect(model.getAccountByEmail('system_admin')?.role).toBe(AccountRole.Owner) + + expect(model.getAccountByEmail('system1')).toBeUndefined() + + expect(model.getAccountByEmail('user1')).not.toBeUndefined() + expect(model.getAccountByEmail('user1')?.role).toBe(AccountRole.Maintainer) + }) }) diff --git a/packages/core/src/__tests__/minmodel.ts b/packages/core/src/__tests__/minmodel.ts index 9b256fe029..33f3c04a5f 100644 --- a/packages/core/src/__tests__/minmodel.ts +++ b/packages/core/src/__tests__/minmodel.ts @@ -15,10 +15,10 @@ import type { IntlString, Plugin } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import type { Arr, Class, Data, Doc, Interface, Mixin, Obj, Ref } from '../classes' +import type { Arr, Class, Data, Doc, Interface, Mixin, Obj, Ref, Space } from '../classes' import { AttachedDoc, ClassifierKind, DOMAIN_MODEL } from '../classes' import core from '../component' -import type { TxCUD, TxCreateDoc } from '../tx' +import type { DocumentUpdate, TxCUD, TxCreateDoc, TxRemoveDoc, TxUpdateDoc } from '../tx' import { DOMAIN_TX, TxFactory } from '../tx' const txFactory = new TxFactory(core.account.System) @@ -31,10 +31,23 @@ function createInterface (_interface: Ref>, attributes: Data (_class: Ref>, attributes: Data): TxCreateDoc { +export function createDoc (_class: Ref>, attributes: Data): TxCreateDoc { return txFactory.createTxCreateDoc(_class, core.space.Model, attributes) } +export function updateDoc ( + _class: Ref>, + space: Ref, + objectId: Ref, + operations: DocumentUpdate +): TxUpdateDoc { + return txFactory.createTxUpdateDoc(_class, space, objectId, operations) +} + +export function deleteDoc (_class: Ref>, space: Ref, objectId: Ref): TxRemoveDoc { + return txFactory.createTxRemoveDoc(_class, space, objectId) +} + export interface TestMixin extends Doc { arr: Arr } diff --git a/packages/core/src/memdb.ts b/packages/core/src/memdb.ts index f131d6b0ca..e04b712caa 100644 --- a/packages/core/src/memdb.ts +++ b/packages/core/src/memdb.ts @@ -32,7 +32,7 @@ export abstract class MemDb extends TxProcessor implements Storage { private readonly objectById = new Map, Doc>() private readonly accountByPersonId = new Map, Account[]>() - private readonly accountByEmail = new Map() + private readonly accountByEmail = new Map() constructor (protected readonly hierarchy: Hierarchy) { super() @@ -83,7 +83,14 @@ export abstract class MemDb extends TxProcessor implements Storage { } getAccountByEmail (email: Account['email']): Account | undefined { - return this.accountByEmail.get(email) + const accounts = this.accountByEmail.get(email) + if (accounts === undefined || accounts.length === 0) { + return undefined + } + + if (accounts.length > 0) { + return accounts[accounts.length - 1][1] + } } findObject(_id: Ref): T | undefined { @@ -225,6 +232,14 @@ export abstract class MemDb extends TxProcessor implements Storage { ) } + addAccount (account: Account): void { + if (!this.accountByEmail.has(account.email)) { + this.accountByEmail.set(account.email, []) + } + + this.accountByEmail.get(account.email)?.push([account._id, account]) + } + addDoc (doc: Doc): void { this.hierarchy.getAncestors(doc._class).forEach((_class) => { const arr = this.getObjectsByClass(_class) @@ -232,7 +247,9 @@ export abstract class MemDb extends TxProcessor implements Storage { }) if (this.hierarchy.isDerived(doc._class, core.class.Account)) { const account = doc as Account - this.accountByEmail.set(account.email, account) + + this.addAccount(account) + if (account.person !== undefined) { this.accountByPersonId.set(account.person, [...(this.accountByPersonId.get(account.person) ?? []), account]) } @@ -240,6 +257,19 @@ export abstract class MemDb extends TxProcessor implements Storage { this.objectById.set(doc._id, doc) } + 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) + } + } + } + delDoc (_id: Ref): void { const doc = this.objectById.get(_id) if (doc === undefined) { @@ -251,7 +281,8 @@ export abstract class MemDb extends TxProcessor implements Storage { }) if (this.hierarchy.isDerived(doc._class, core.class.Account)) { const account = doc as Account - this.accountByEmail.delete(account.email) + this.delAccount(account) + if (account.person !== undefined) { const acc = this.accountByPersonId.get(account.person) ?? [] this.accountByPersonId.set( @@ -280,8 +311,8 @@ export abstract class MemDb extends TxProcessor implements Storage { } } else if (newEmail !== undefined) { const account = doc as Account - this.accountByEmail.delete(account.email) - this.accountByEmail.set(newEmail, account) + this.delAccount(account) + this.addAccount({ ...account, email: newEmail }) } } }