mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-24 01:07:50 +00:00
UBER-803: Fix slow filter (#3634)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
97abd2fc12
commit
72c026d505
@ -224,14 +224,14 @@ export class LiveQuery {
|
|||||||
|
|
||||||
const unsub = liveQuery.query(
|
const unsub = liveQuery.query(
|
||||||
_class,
|
_class,
|
||||||
piplineQuery.query ?? query,
|
query,
|
||||||
(result) => {
|
(result) => {
|
||||||
// If we have one more request after this one, no need to do something.
|
// If we have one more request after this one, no need to do something.
|
||||||
if (id === this.reqId) {
|
if (id === this.reqId) {
|
||||||
callback(result)
|
callback(result)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
piplineQuery.options ?? options
|
options
|
||||||
)
|
)
|
||||||
this.unsubscribe = () => {
|
this.unsubscribe = () => {
|
||||||
unsub()
|
unsub()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import type { DisplayTx, TxViewlet } from '@hcengineering/activity'
|
import type { DisplayTx, TxViewlet } from '@hcengineering/activity'
|
||||||
import attachment from '@hcengineering/attachment'
|
import attachment from '@hcengineering/attachment'
|
||||||
import chunter from '@hcengineering/chunter'
|
import chunter from '@hcengineering/chunter'
|
||||||
import contact, { Employee, PersonAccount, getName } from '@hcengineering/contact'
|
import contact, { Person, PersonAccount, getName } from '@hcengineering/contact'
|
||||||
import core, { AnyAttribute, Class, Doc, Ref, TxCUD, getCurrentAccount } from '@hcengineering/core'
|
import core, { AnyAttribute, Class, Doc, Ref, TxCUD, getCurrentAccount } from '@hcengineering/core'
|
||||||
import { Asset } from '@hcengineering/platform'
|
import { Asset } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
@ -56,7 +56,7 @@
|
|||||||
let viewlet: TxDisplayViewlet | undefined
|
let viewlet: TxDisplayViewlet | undefined
|
||||||
let props: any
|
let props: any
|
||||||
let account: PersonAccount | undefined
|
let account: PersonAccount | undefined
|
||||||
let employee: Employee | undefined
|
let person: Person | undefined
|
||||||
let model: AttributeModel[] = []
|
let model: AttributeModel[] = []
|
||||||
let modelIcon: Asset | undefined = undefined
|
let modelIcon: Asset | undefined = undefined
|
||||||
let iconComponent: AnyComponent | undefined = undefined
|
let iconComponent: AnyComponent | undefined = undefined
|
||||||
@ -67,7 +67,7 @@
|
|||||||
$: if (tx.tx._id !== ptx?.tx._id) {
|
$: if (tx.tx._id !== ptx?.tx._id) {
|
||||||
if (tx.tx.modifiedBy !== account?._id) {
|
if (tx.tx.modifiedBy !== account?._id) {
|
||||||
account = undefined
|
account = undefined
|
||||||
employee = undefined
|
person = undefined
|
||||||
}
|
}
|
||||||
viewlet = undefined
|
viewlet = undefined
|
||||||
props = undefined
|
props = undefined
|
||||||
@ -107,10 +107,10 @@
|
|||||||
|
|
||||||
$: account &&
|
$: account &&
|
||||||
employeeQuery.query(
|
employeeQuery.query(
|
||||||
contact.mixin.Employee,
|
contact.class.Person,
|
||||||
{ _id: account.person as Ref<Employee> },
|
{ _id: account.person },
|
||||||
(res) => {
|
(res) => {
|
||||||
;[employee] = res
|
;[person] = res
|
||||||
},
|
},
|
||||||
{ limit: 1 }
|
{ limit: 1 }
|
||||||
)
|
)
|
||||||
@ -191,7 +191,7 @@
|
|||||||
{#if showIcon}
|
{#if showIcon}
|
||||||
{#if withAvatar}
|
{#if withAvatar}
|
||||||
<div class="msgactivity-avatar">
|
<div class="msgactivity-avatar">
|
||||||
<Component is={contact.component.Avatar} props={{ avatar: employee?.avatar, size: 'medium' }} />
|
<Component is={contact.component.Avatar} props={{ avatar: person?.avatar, size: 'medium' }} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="msgactivity-icon">
|
<div class="msgactivity-icon">
|
||||||
@ -212,8 +212,8 @@
|
|||||||
<div class="msgactivity-content__header">
|
<div class="msgactivity-content__header">
|
||||||
<div class="msgactivity-content__title labels-row">
|
<div class="msgactivity-content__title labels-row">
|
||||||
<span class={withAvatar ? 'bold' : 'strong'}>
|
<span class={withAvatar ? 'bold' : 'strong'}>
|
||||||
{#if employee}
|
{#if person}
|
||||||
{getName(client.getHierarchy(), employee)}
|
{getName(client.getHierarchy(), person)}
|
||||||
{:else}
|
{:else}
|
||||||
<Label label={core.string.System} />
|
<Label label={core.string.System} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -96,8 +96,8 @@ export class AggregationMiddleware extends BasePresentationMiddleware implements
|
|||||||
const statusFields: Array<Attribute<Doc>> = []
|
const statusFields: Array<Attribute<Doc>> = []
|
||||||
const allAttrs = h.getAllAttributes(_class)
|
const allAttrs = h.getAllAttributes(_class)
|
||||||
|
|
||||||
const updatedQuery: DocumentQuery<T> = { ...(ret.query ?? query) }
|
const updatedQuery: DocumentQuery<T> = h.clone(ret.query ?? query)
|
||||||
const finalOptions = { ...(ret.options ?? options ?? {}) }
|
const finalOptions = h.clone(ret.options ?? options ?? {})
|
||||||
|
|
||||||
await this.updateQueryOptions<T>(allAttrs, h, statusFields, updatedQuery, finalOptions)
|
await this.updateQueryOptions<T>(allAttrs, h, statusFields, updatedQuery, finalOptions)
|
||||||
|
|
||||||
@ -139,11 +139,13 @@ export class AggregationMiddleware extends BasePresentationMiddleware implements
|
|||||||
const docFields: Array<Attribute<Doc>> = []
|
const docFields: Array<Attribute<Doc>> = []
|
||||||
const h = this.client.getHierarchy()
|
const h = this.client.getHierarchy()
|
||||||
const allAttrs = h.getAllAttributes(_class)
|
const allAttrs = h.getAllAttributes(_class)
|
||||||
const finalOptions = options ?? {}
|
const finalOptions = h.clone(options ?? {})
|
||||||
|
|
||||||
await this.updateQueryOptions<T>(allAttrs, h, docFields, query, finalOptions)
|
const fquery = h.clone(query ?? {})
|
||||||
|
|
||||||
const result = await this.provideFindAll(_class, query, finalOptions)
|
await this.updateQueryOptions<T>(allAttrs, h, docFields, fquery, finalOptions)
|
||||||
|
|
||||||
|
const result = await this.provideFindAll(_class, fquery, finalOptions)
|
||||||
// We need to add $
|
// We need to add $
|
||||||
if (docFields.length > 0) {
|
if (docFields.length > 0) {
|
||||||
// We need to update $lookup for doc fields and provide $doc group fields.
|
// We need to update $lookup for doc fields and provide $doc group fields.
|
||||||
|
@ -24,16 +24,19 @@ import core, {
|
|||||||
DocumentQuery,
|
DocumentQuery,
|
||||||
FindOptions,
|
FindOptions,
|
||||||
Hierarchy,
|
Hierarchy,
|
||||||
|
IdMap,
|
||||||
Ref,
|
Ref,
|
||||||
SortingOrder,
|
SortingOrder,
|
||||||
SortingRules,
|
SortingRules,
|
||||||
Space,
|
Space,
|
||||||
Status,
|
Status,
|
||||||
|
StatusCategory,
|
||||||
StatusManager,
|
StatusManager,
|
||||||
StatusValue,
|
StatusValue,
|
||||||
Tx,
|
Tx,
|
||||||
WithLookup,
|
WithLookup,
|
||||||
matchQuery
|
matchQuery,
|
||||||
|
toIdMap
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { LiveQuery } from '@hcengineering/query'
|
import { LiveQuery } from '@hcengineering/query'
|
||||||
import { AggregationManager, GrouppingManager } from '@hcengineering/view'
|
import { AggregationManager, GrouppingManager } from '@hcengineering/view'
|
||||||
@ -47,8 +50,15 @@ export const statusStore = writable<StatusManager>(new StatusManager([]))
|
|||||||
*/
|
*/
|
||||||
export class StatusAggregationManager implements AggregationManager {
|
export class StatusAggregationManager implements AggregationManager {
|
||||||
docs: Doc[] | undefined
|
docs: Doc[] | undefined
|
||||||
|
|
||||||
|
docsByName: Map<string, Status[]> = new Map<string, Status[]>()
|
||||||
mgr: StatusManager | Promise<StatusManager> | undefined
|
mgr: StatusManager | Promise<StatusManager> | undefined
|
||||||
|
statusCategory: IdMap<StatusCategory> = new Map()
|
||||||
query: (() => void) | undefined
|
query: (() => void) | undefined
|
||||||
|
|
||||||
|
categoryQuery: (() => void) | undefined
|
||||||
|
categoryPromise!: Promise<void>
|
||||||
|
|
||||||
lq: LiveQuery
|
lq: LiveQuery
|
||||||
lqCallback: () => void
|
lqCallback: () => void
|
||||||
|
|
||||||
@ -68,14 +78,27 @@ export class StatusAggregationManager implements AggregationManager {
|
|||||||
}
|
}
|
||||||
return this.mgr
|
return this.mgr
|
||||||
}
|
}
|
||||||
|
this.categoryPromise = new Promise((resolve) => {
|
||||||
|
this.categoryQuery = this.lq.query(core.class.StatusCategory, {}, (res) => {
|
||||||
|
this.statusCategory = toIdMap(res)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
this.mgr = new Promise<StatusManager>((resolve) => {
|
this.mgr = new Promise<StatusManager>((resolve) => {
|
||||||
this.query = this.lq.query(
|
this.query = this.lq.query(
|
||||||
core.class.Status,
|
core.class.Status,
|
||||||
{},
|
{},
|
||||||
(res) => {
|
(res) => {
|
||||||
const first = this.docs === undefined
|
const first = this.docs === undefined
|
||||||
|
|
||||||
this.docs = res
|
this.docs = res
|
||||||
|
const newMap = new Map<string, Status[]>()
|
||||||
|
for (const d of this.docs as Array<WithLookup<Status>>) {
|
||||||
|
const n = d.name.toLowerCase().trim()
|
||||||
|
newMap.set(n, [...(newMap.get(n) ?? []), d])
|
||||||
|
}
|
||||||
this.mgr = new StatusManager(res)
|
this.mgr = new StatusManager(res)
|
||||||
|
this.docsByName = newMap
|
||||||
statusStore.set(this.mgr)
|
statusStore.set(this.mgr)
|
||||||
if (!first) {
|
if (!first) {
|
||||||
this.lqCallback()
|
this.lqCallback()
|
||||||
@ -83,9 +106,6 @@ export class StatusAggregationManager implements AggregationManager {
|
|||||||
resolve(this.mgr)
|
resolve(this.mgr)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lookup: {
|
|
||||||
category: core.class.StatusCategory
|
|
||||||
},
|
|
||||||
sort: {
|
sort: {
|
||||||
rank: SortingOrder.Ascending
|
rank: SortingOrder.Ascending
|
||||||
}
|
}
|
||||||
@ -98,6 +118,7 @@ export class StatusAggregationManager implements AggregationManager {
|
|||||||
|
|
||||||
close (): void {
|
close (): void {
|
||||||
this.query?.()
|
this.query?.()
|
||||||
|
this.categoryQuery?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
async notifyTx (tx: Tx): Promise<void> {
|
async notifyTx (tx: Tx): Promise<void> {
|
||||||
@ -110,15 +131,13 @@ export class StatusAggregationManager implements AggregationManager {
|
|||||||
|
|
||||||
async categorize (target: Array<Ref<Doc>>, attr: AnyAttribute): Promise<Array<Ref<Doc>>> {
|
async categorize (target: Array<Ref<Doc>>, attr: AnyAttribute): Promise<Array<Ref<Doc>>> {
|
||||||
const mgr = await this.getManager()
|
const mgr = await this.getManager()
|
||||||
|
const idMap = mgr.getIdMap()
|
||||||
|
|
||||||
for (const sid of [...target]) {
|
for (const sid of [...target]) {
|
||||||
const s = mgr.getIdMap().get(sid as Ref<Status>) as WithLookup<Status>
|
const s = idMap.get(sid as Ref<Status>) as WithLookup<Status>
|
||||||
if (s !== undefined) {
|
if (s !== undefined) {
|
||||||
let statuses = mgr.getDocs()
|
const statuses = (this.docsByName.get(s.name.toLowerCase().trim()) ?? []).filter(
|
||||||
statuses = statuses.filter(
|
(it) => it.ofAttribute === attr._id && it._id !== s._id
|
||||||
(it) =>
|
|
||||||
it.ofAttribute === attr._id &&
|
|
||||||
it.name.toLowerCase().trim() === s.name.toLowerCase().trim() &&
|
|
||||||
it._id !== s._id
|
|
||||||
)
|
)
|
||||||
target.push(...statuses.map((it) => it._id))
|
target.push(...statuses.map((it) => it._id))
|
||||||
}
|
}
|
||||||
@ -140,10 +159,11 @@ export class StatusAggregationManager implements AggregationManager {
|
|||||||
// Fill custom sorting.
|
// Fill custom sorting.
|
||||||
let statuses = (await this.getManager()).getDocs()
|
let statuses = (await this.getManager()).getDocs()
|
||||||
statuses = statuses.filter((it) => it.ofAttribute === attr._id)
|
statuses = statuses.filter((it) => it.ofAttribute === attr._id)
|
||||||
|
await this.categoryPromise
|
||||||
statuses.sort((a, b) => {
|
statuses.sort((a, b) => {
|
||||||
let ret = 0
|
let ret = 0
|
||||||
if (a.category !== undefined && b.category !== undefined) {
|
if (a.category !== undefined && b.category !== undefined) {
|
||||||
ret = (a.$lookup?.category?.order ?? 0) - (b.$lookup?.category?.order ?? 0)
|
ret = (this.statusCategory.get(a.category)?.order ?? 0) - (this.statusCategory.get(b.category)?.order ?? 0)
|
||||||
}
|
}
|
||||||
if (ret === 0) {
|
if (ret === 0) {
|
||||||
if (a.name.toLowerCase().trim() === b.name.toLowerCase().trim()) {
|
if (a.name.toLowerCase().trim() === b.name.toLowerCase().trim()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user