UBERF-8083: Optimize account by email search (#6538)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-09-12 14:04:03 +07:00 committed by GitHub
parent 49113d8cd8
commit 04ce0d70ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 28 additions and 37 deletions

View File

@ -32,6 +32,7 @@ export abstract class MemDb extends TxProcessor implements Storage {
private readonly objectById = new Map<Ref<Doc>, Doc>() private readonly objectById = new Map<Ref<Doc>, Doc>()
private readonly accountByPersonId = new Map<Ref<Doc>, Account[]>() private readonly accountByPersonId = new Map<Ref<Doc>, Account[]>()
private readonly accountByEmail = new Map<string, Account>()
constructor (protected readonly hierarchy: Hierarchy) { constructor (protected readonly hierarchy: Hierarchy) {
super() super()
@ -81,6 +82,10 @@ export abstract class MemDb extends TxProcessor implements Storage {
return this.accountByPersonId.get(ref) ?? [] return this.accountByPersonId.get(ref) ?? []
} }
getAccountByEmail (email: Account['email']): Account | undefined {
return this.accountByEmail.get(email)
}
findObject<T extends Doc>(_id: Ref<T>): T | undefined { findObject<T extends Doc>(_id: Ref<T>): T | undefined {
const doc = this.objectById.get(_id) const doc = this.objectById.get(_id)
return doc as T return doc as T
@ -227,6 +232,7 @@ export abstract class MemDb extends TxProcessor implements Storage {
}) })
if (this.hierarchy.isDerived(doc._class, core.class.Account)) { if (this.hierarchy.isDerived(doc._class, core.class.Account)) {
const account = doc as Account const account = doc as Account
this.accountByEmail.set(account.email, account)
if (account.person !== undefined) { if (account.person !== undefined) {
this.accountByPersonId.set(account.person, [...(this.accountByPersonId.get(account.person) ?? []), account]) this.accountByPersonId.set(account.person, [...(this.accountByPersonId.get(account.person) ?? []), account])
} }
@ -245,6 +251,7 @@ export abstract class MemDb extends TxProcessor implements Storage {
}) })
if (this.hierarchy.isDerived(doc._class, core.class.Account)) { if (this.hierarchy.isDerived(doc._class, core.class.Account)) {
const account = doc as Account const account = doc as Account
this.accountByEmail.delete(account.email)
if (account.person !== undefined) { if (account.person !== undefined) {
const acc = this.accountByPersonId.get(account.person) ?? [] const acc = this.accountByPersonId.get(account.person) ?? []
this.accountByPersonId.set( this.accountByPersonId.set(

View File

@ -23,7 +23,7 @@ async function connect (token: string): Promise<Client> {
} }
async function getTxOperations (client: Client, token: Token, isDerived: boolean = false): Promise<TxOperations> { async function getTxOperations (client: Client, token: Token, isDerived: boolean = false): Promise<TxOperations> {
const account = await client.findOne(core.class.Account, { email: token.email }) const account = client.getModel().getAccountByEmail(token.email)
const accountId = account?._id ?? core.account.System const accountId = account?._id ?? core.account.System
return new TxOperations(client, accountId, isDerived) return new TxOperations(client, accountId, isDerived)

View File

@ -140,7 +140,7 @@ export function getUser (modelDb: ModelDb, userEmail: string | undefined, admin?
if (userEmail === undefined) { if (userEmail === undefined) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
} }
const account = modelDb.findAllSync(core.class.Account, { email: userEmail })[0] const account = modelDb.getAccountByEmail(userEmail)
if (account === undefined) { if (account === undefined) {
if (userEmail === systemAccountEmail || admin === true) { if (userEmail === systemAccountEmail || admin === true) {
return { return {
@ -181,7 +181,7 @@ export class SessionDataImpl implements SessionData {
} }
getAccount (account: Ref<Account>): Account | undefined { getAccount (account: Ref<Account>): Account | undefined {
return this.modelDb.findAllSync(core.class.Account, { _id: account })[0] return this.modelDb.findObject(account)
} }
} }

View File

@ -113,12 +113,10 @@ export class ClientSession implements Session {
} }
async getAccount (ctx: ClientSessionCtx): Promise<void> { async getAccount (ctx: ClientSessionCtx): Promise<void> {
const account = this._pipeline.context.modelDb.findAllSync(core.class.Account, { email: this.token.email }) const account = this._pipeline.context.modelDb.getAccountByEmail(this.token.email)
if (account.length === 0 && this.token.extra?.admin === 'true') { if (account === undefined && this.token.extra?.admin === 'true') {
const systemAccount = this._pipeline.context.modelDb.findAllSync(core.class.Account, { const systemAccount = this._pipeline.context.modelDb.findObject(this.token.email as Ref<Account>)
_id: this.token.email as Ref<Account> if (systemAccount === undefined) {
})
if (systemAccount.length === 0) {
// Generate account for admin user // Generate account for admin user
const factory = new TxFactory(core.account.System) const factory = new TxFactory(core.account.System)
const email = `system:${this.token.email}` const email = `system:${this.token.email}`
@ -152,11 +150,11 @@ export class ClientSession implements Session {
await ctx.sendResponse(acc) await ctx.sendResponse(acc)
return return
} else { } else {
await ctx.sendResponse(systemAccount[0]) await ctx.sendResponse(systemAccount)
return return
} }
} }
await ctx.sendResponse(account[0]) await ctx.sendResponse(account)
} }
findAllRaw<T extends Doc>( findAllRaw<T extends Doc>(

View File

@ -629,15 +629,7 @@ class TSessionManager implements SessionManager {
workspaceId: WorkspaceId workspaceId: WorkspaceId
): Promise<void> { ): Promise<void> {
try { try {
const user = ( const user = session.pipeline().context.modelDb.getAccountByEmail(session.getUser())
await session.pipeline().context.modelDb.findAll(
core.class.Account,
{
email: session.getUser()
},
{ limit: 1 }
)
)[0]
if (user === undefined) return if (user === undefined) return
const clientCtx: ClientSessionCtx = { const clientCtx: ClientSessionCtx = {

View File

@ -16,6 +16,7 @@
import calendar, { Event, ExternalCalendar } from '@hcengineering/calendar' import calendar, { Event, ExternalCalendar } from '@hcengineering/calendar'
import contact, { Channel, Contact, type Employee, type PersonAccount } from '@hcengineering/contact' import contact, { Channel, Contact, type Employee, type PersonAccount } from '@hcengineering/contact'
import core, { import core, {
TxOperations,
TxProcessor, TxProcessor,
toIdMap, toIdMap,
type Account, type Account,
@ -25,17 +26,16 @@ import core, {
type Tx, type Tx,
type TxCreateDoc, type TxCreateDoc,
type TxRemoveDoc, type TxRemoveDoc,
type TxUpdateDoc, type TxUpdateDoc
TxOperations
} from '@hcengineering/core' } from '@hcengineering/core'
import { generateToken } from '@hcengineering/server-token'
import setting, { Integration } from '@hcengineering/setting' import setting, { Integration } from '@hcengineering/setting'
import { Collection, type Db } from 'mongodb' import { Collection, type Db } from 'mongodb'
import { CalendarClient } from './calendar' import { CalendarClient } from './calendar'
import { CalendarController } from './calendarController'
import { getClient } from './client' import { getClient } from './client'
import config from './config' import config from './config'
import { SyncHistory, type ProjectCredentials, type User } from './types' import { SyncHistory, type ProjectCredentials, type User } from './types'
import { CalendarController } from './calendarController'
import { generateToken } from '@hcengineering/server-token'
export class WorkspaceClient { export class WorkspaceClient {
private readonly txHandlers: ((...tx: Tx[]) => Promise<void>)[] = [] private readonly txHandlers: ((...tx: Tx[]) => Promise<void>)[] = []
@ -109,9 +109,7 @@ export class WorkspaceClient {
} }
async getUserId (email: string): Promise<Ref<Account>> { async getUserId (email: string): Promise<Ref<Account>> {
const user = await this.client.findOne(core.class.Account, { const user = this.client.getModel().getAccountByEmail(email)
email
})
if (user === undefined) { if (user === undefined) {
throw new Error('User not found') throw new Error('User not found')
} }

View File

@ -408,7 +408,7 @@ export class PlatformWorker {
} }
// We need to re-bind previously created github:login account to a proper person. // We need to re-bind previously created github:login account to a proper person.
const account = (await client.findOne(core.class.Account, { _id: payload.accountId })) as PersonAccount const account = client.getModel().getObject(payload.accountId) as PersonAccount
const person = (await client.findOne(contact.class.Person, { _id: account.person })) as Person const person = (await client.findOne(contact.class.Person, { _id: account.person })) as Person
if (person !== undefined) { if (person !== undefined) {
if (!revoke) { if (!revoke) {
@ -424,9 +424,7 @@ export class PlatformWorker {
}) })
} }
const githubAccount = (await client.findOne(core.class.Account, { const githubAccount = client.getModel().getAccountByEmail('github:' + update.login) as PersonAccount
email: 'github:' + update.login
})) as PersonAccount
if (githubAccount !== undefined && githubAccount.person !== account.person) { if (githubAccount !== undefined && githubAccount.person !== account.person) {
const dummyPerson = githubAccount.person const dummyPerson = githubAccount.person
// To add activity entry to dummy person. // To add activity entry to dummy person.

View File

@ -19,14 +19,14 @@ import core, {
type AttachedDoc, type AttachedDoc,
type Client, type Client,
type Doc, type Doc,
MeasureContext,
type Ref, type Ref,
type Tx, type Tx,
type TxCollectionCUD, type TxCollectionCUD,
type TxCreateDoc, type TxCreateDoc,
TxProcessor, TxProcessor,
type TxRemoveDoc, type TxRemoveDoc,
type TxUpdateDoc, type TxUpdateDoc
MeasureContext
} from '@hcengineering/core' } from '@hcengineering/core'
import gmailP, { type NewMessage } from '@hcengineering/gmail' import gmailP, { type NewMessage } from '@hcengineering/gmail'
import type { StorageAdapter } from '@hcengineering/server-core' import type { StorageAdapter } from '@hcengineering/server-core'
@ -92,9 +92,7 @@ export class WorkspaceClient {
} }
async getUserId (email: string): Promise<Ref<Account>> { async getUserId (email: string): Promise<Ref<Account>> {
const user = await this.client.findOne(core.class.Account, { const user = this.client.getModel().getAccountByEmail(email)
email
})
if (user === undefined) { if (user === undefined) {
throw new Error('User not found') throw new Error('User not found')
} }

View File

@ -179,7 +179,7 @@ export class WorkspaceWorker {
// #region Users // #region Users
async addUser ({ email, phone, conn }: TgUser): Promise<void> { async addUser ({ email, phone, conn }: TgUser): Promise<void> {
const user = (await this.client.findAll(core.class.Account, { email }, { limit: 1 }))[0] const user = this.client.getModel().getAccountByEmail(email)
if (user === undefined) { if (user === undefined) {
throw Error(`Unable to find user by email: ${email}`) throw Error(`Unable to find user by email: ${email}`)