Skip to content

Commit

Permalink
uberf-8544: improve memdb account handling (#7047)
Browse files Browse the repository at this point in the history
Signed-off-by: Alexey Zinoviev <[email protected]>
  • Loading branch information
lexiv0re authored Oct 27, 2024
1 parent 3b52779 commit db4e6e1
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 15 deletions.
49 changes: 43 additions & 6 deletions packages/core/src/__tests__/memdb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -59,17 +59,17 @@ class ClientModel extends ModelDb implements Client {
async close (): Promise<void> {}
}

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 }
}

Expand All @@ -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 () => {
Expand Down Expand Up @@ -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)
})
})
19 changes: 16 additions & 3 deletions packages/core/src/__tests__/minmodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -31,10 +31,23 @@ function createInterface (_interface: Ref<Interface<Doc>>, attributes: Data<Inte
return txFactory.createTxCreateDoc(core.class.Interface, core.space.Model, attributes, _interface)
}

export function createDoc<T extends Doc> (_class: Ref<Class<T>>, attributes: Data<T>): TxCreateDoc<Doc> {
export function createDoc<T extends Doc> (_class: Ref<Class<T>>, attributes: Data<T>): TxCreateDoc<T> {
return txFactory.createTxCreateDoc(_class, core.space.Model, attributes)
}

export function updateDoc<T extends Doc> (
_class: Ref<Class<T>>,
space: Ref<Space>,
objectId: Ref<T>,
operations: DocumentUpdate<T>
): TxUpdateDoc<Doc> {
return txFactory.createTxUpdateDoc(_class, space, objectId, operations)
}

export function deleteDoc<T extends Doc> (_class: Ref<Class<T>>, space: Ref<Space>, objectId: Ref<T>): TxRemoveDoc<Doc> {
return txFactory.createTxRemoveDoc(_class, space, objectId)
}

export interface TestMixin extends Doc {
arr: Arr<string>
}
Expand Down
43 changes: 37 additions & 6 deletions packages/core/src/memdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export abstract class MemDb extends TxProcessor implements Storage {
private readonly objectById = new Map<Ref<Doc>, Doc>()

private readonly accountByPersonId = new Map<Ref<Doc>, Account[]>()
private readonly accountByEmail = new Map<string, Account>()
private readonly accountByEmail = new Map<string, [string, Account][]>()

constructor (protected readonly hierarchy: Hierarchy) {
super()
Expand Down Expand Up @@ -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<T extends Doc>(_id: Ref<T>): T | undefined {
Expand Down Expand Up @@ -225,21 +232,44 @@ 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)
arr.set(doc._id, doc)
})
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])
}
}
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<Doc>): void {
const doc = this.objectById.get(_id)
if (doc === undefined) {
Expand All @@ -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(
Expand Down Expand Up @@ -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 })
}
}
}
Expand Down

0 comments on commit db4e6e1

Please sign in to comment.