mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-08 00:37:42 +00:00
TSK-803: Fix load speed (#2728)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
b6980f307e
commit
9eddd84ada
@ -34,8 +34,10 @@ import {
|
|||||||
DOMAIN_MODEL,
|
DOMAIN_MODEL,
|
||||||
Enum,
|
Enum,
|
||||||
EnumOf,
|
EnumOf,
|
||||||
|
FieldIndex,
|
||||||
FullTextData,
|
FullTextData,
|
||||||
FullTextSearchContext,
|
FullTextSearchContext,
|
||||||
|
IndexingConfiguration,
|
||||||
IndexKind,
|
IndexKind,
|
||||||
IndexStageState,
|
IndexStageState,
|
||||||
Interface,
|
Interface,
|
||||||
@ -249,15 +251,22 @@ export class TFulltextData extends TDoc implements FullTextData {
|
|||||||
export class TDocIndexState extends TDoc implements DocIndexState {
|
export class TDocIndexState extends TDoc implements DocIndexState {
|
||||||
objectClass!: Ref<Class<Doc>>
|
objectClass!: Ref<Class<Doc>>
|
||||||
|
|
||||||
attachedTo?: Ref<Doc>
|
@Prop(TypeRef(core.class.Doc), core.string.AttachedTo)
|
||||||
attachedToClass?: Ref<Class<Doc>>
|
@Index(IndexKind.Indexed)
|
||||||
|
@Hidden()
|
||||||
|
attachedTo?: Ref<Doc>
|
||||||
|
|
||||||
|
@Prop(TypeRef(core.class.Doc), core.string.AttachedToClass)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
|
@Hidden()
|
||||||
|
attachedToClass?: Ref<Class<Doc>>
|
||||||
|
|
||||||
// Indexable attributes of document.
|
// Indexable attributes of document.
|
||||||
attributes!: Record<string, any>
|
attributes!: Record<string, any>
|
||||||
|
|
||||||
removed!: boolean
|
removed!: boolean
|
||||||
|
|
||||||
// States for diffetent stages
|
// States for different stages
|
||||||
stages!: Record<string, boolean | string>
|
stages!: Record<string, boolean | string>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,3 +293,8 @@ export class TConfiguration extends TDoc implements Configuration {
|
|||||||
@Prop(TypeBoolean(), core.string.Private)
|
@Prop(TypeBoolean(), core.string.Private)
|
||||||
enabled!: boolean
|
enabled!: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MMixin(core.mixin.IndexConfiguration, core.class.Class)
|
||||||
|
export class TIndexConfiguration<T extends Doc = Doc> extends TClass implements IndexingConfiguration<T> {
|
||||||
|
indexes!: FieldIndex<T>[]
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { AccountRole } from '@hcengineering/core'
|
import { AccountRole, TxCollectionCUD, Doc, AttachedDoc, IndexingConfiguration, Class } from '@hcengineering/core'
|
||||||
import { Builder } from '@hcengineering/model'
|
import { Builder } from '@hcengineering/model'
|
||||||
import core from './component'
|
import core from './component'
|
||||||
import {
|
import {
|
||||||
@ -31,6 +31,7 @@ import {
|
|||||||
TEnumOf,
|
TEnumOf,
|
||||||
TFulltextData,
|
TFulltextData,
|
||||||
TFullTextSearchContext,
|
TFullTextSearchContext,
|
||||||
|
TIndexConfiguration,
|
||||||
TIndexStageState,
|
TIndexStageState,
|
||||||
TInterface,
|
TInterface,
|
||||||
TMixin,
|
TMixin,
|
||||||
@ -104,7 +105,8 @@ export function createModel (builder: Builder): void {
|
|||||||
TIndexStageState,
|
TIndexStageState,
|
||||||
TFullTextSearchContext,
|
TFullTextSearchContext,
|
||||||
TConfiguration,
|
TConfiguration,
|
||||||
TConfigurationElement
|
TConfigurationElement,
|
||||||
|
TIndexConfiguration
|
||||||
)
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
@ -116,4 +118,23 @@ export function createModel (builder: Builder): void {
|
|||||||
},
|
},
|
||||||
core.account.System
|
core.account.System
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.mixin<Class<TxCollectionCUD<Doc, AttachedDoc>>, IndexingConfiguration<TxCollectionCUD<Doc, AttachedDoc>>>(
|
||||||
|
core.class.TxCollectionCUD,
|
||||||
|
core.class.Class,
|
||||||
|
core.mixin.IndexConfiguration,
|
||||||
|
{
|
||||||
|
indexes: [
|
||||||
|
'tx.objectId',
|
||||||
|
'tx._class',
|
||||||
|
'tx.objectClass',
|
||||||
|
'tx.operations.attachedTo',
|
||||||
|
'objectSpace',
|
||||||
|
{
|
||||||
|
objectSpace: 1,
|
||||||
|
_id: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import {
|
|||||||
TxRemoveDoc,
|
TxRemoveDoc,
|
||||||
TxUpdateDoc
|
TxUpdateDoc
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { Index, Model } from '@hcengineering/model'
|
import { Hidden, Index, Model, Prop, TypeRef } from '@hcengineering/model'
|
||||||
import core from './component'
|
import core from './component'
|
||||||
import { TDoc } from './core'
|
import { TDoc } from './core'
|
||||||
|
|
||||||
@ -43,7 +43,10 @@ import { TDoc } from './core'
|
|||||||
|
|
||||||
@Model(core.class.Tx, core.class.Doc, DOMAIN_TX)
|
@Model(core.class.Tx, core.class.Doc, DOMAIN_TX)
|
||||||
export class TTx extends TDoc implements Tx {
|
export class TTx extends TDoc implements Tx {
|
||||||
objectSpace!: Ref<Space>
|
@Prop(TypeRef(core.class.Space), core.string.Space)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
|
@Hidden()
|
||||||
|
objectSpace!: Ref<Space>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(core.class.TxModelUpgrade, core.class.Tx, DOMAIN_TX)
|
@Model(core.class.TxModelUpgrade, core.class.Tx, DOMAIN_TX)
|
||||||
@ -51,10 +54,15 @@ export class TTxModelUpgrade extends TTx {}
|
|||||||
|
|
||||||
@Model(core.class.TxCUD, core.class.Tx)
|
@Model(core.class.TxCUD, core.class.Tx)
|
||||||
export class TTxCUD<T extends Doc> extends TTx implements TxCUD<T> {
|
export class TTxCUD<T extends Doc> extends TTx implements TxCUD<T> {
|
||||||
|
@Prop(TypeRef(core.class.Doc), core.string.Object)
|
||||||
@Index(IndexKind.Indexed)
|
@Index(IndexKind.Indexed)
|
||||||
|
@Hidden()
|
||||||
objectId!: Ref<T>
|
objectId!: Ref<T>
|
||||||
|
|
||||||
objectClass!: Ref<Class<T>>
|
@Prop(TypeRef(core.class.Class), core.string.ClassLabel)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
|
@Hidden()
|
||||||
|
objectClass!: Ref<Class<T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(core.class.TxCreateDoc, core.class.TxCUD)
|
@Model(core.class.TxCreateDoc, core.class.TxCUD)
|
||||||
|
@ -211,9 +211,11 @@ export class TIssue extends TAttachedDoc implements Issue {
|
|||||||
description!: Markup
|
description!: Markup
|
||||||
|
|
||||||
@Prop(TypeRef(tracker.class.IssueStatus), tracker.string.Status)
|
@Prop(TypeRef(tracker.class.IssueStatus), tracker.string.Status)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
status!: Ref<IssueStatus>
|
status!: Ref<IssueStatus>
|
||||||
|
|
||||||
@Prop(TypeIssuePriority(), tracker.string.Priority)
|
@Prop(TypeIssuePriority(), tracker.string.Priority)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
priority!: IssuePriority
|
priority!: IssuePriority
|
||||||
|
|
||||||
@Prop(TypeNumber(), tracker.string.Number)
|
@Prop(TypeNumber(), tracker.string.Number)
|
||||||
@ -221,9 +223,11 @@ export class TIssue extends TAttachedDoc implements Issue {
|
|||||||
number!: number
|
number!: number
|
||||||
|
|
||||||
@Prop(TypeRef(contact.class.Employee), tracker.string.Assignee)
|
@Prop(TypeRef(contact.class.Employee), tracker.string.Assignee)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
assignee!: Ref<Employee> | null
|
assignee!: Ref<Employee> | null
|
||||||
|
|
||||||
@Prop(TypeRef(tracker.class.Project), tracker.string.Project)
|
@Prop(TypeRef(tracker.class.Project), tracker.string.Project)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
project!: Ref<Project> | null
|
project!: Ref<Project> | null
|
||||||
|
|
||||||
@Prop(Collection(tracker.class.Issue), tracker.string.SubIssues)
|
@Prop(Collection(tracker.class.Issue), tracker.string.SubIssues)
|
||||||
@ -256,6 +260,7 @@ export class TIssue extends TAttachedDoc implements Issue {
|
|||||||
rank!: string
|
rank!: string
|
||||||
|
|
||||||
@Prop(TypeRef(tracker.class.Sprint), tracker.string.Sprint)
|
@Prop(TypeRef(tracker.class.Sprint), tracker.string.Sprint)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
sprint!: Ref<Sprint> | null
|
sprint!: Ref<Sprint> | null
|
||||||
|
|
||||||
@Prop(TypeNumber(), tracker.string.Estimation)
|
@Prop(TypeNumber(), tracker.string.Estimation)
|
||||||
@ -397,6 +402,7 @@ export class TSprint extends TDoc implements Sprint {
|
|||||||
description?: Markup
|
description?: Markup
|
||||||
|
|
||||||
@Prop(TypeSprintStatus(), tracker.string.Status)
|
@Prop(TypeSprintStatus(), tracker.string.Status)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
status!: SprintStatus
|
status!: SprintStatus
|
||||||
|
|
||||||
@Prop(TypeRef(contact.class.Employee), tracker.string.ProjectLead)
|
@Prop(TypeRef(contact.class.Employee), tracker.string.ProjectLead)
|
||||||
@ -423,6 +429,7 @@ export class TSprint extends TDoc implements Sprint {
|
|||||||
capacity!: number
|
capacity!: number
|
||||||
|
|
||||||
@Prop(TypeRef(tracker.class.Project), tracker.string.Project)
|
@Prop(TypeRef(tracker.class.Project), tracker.string.Project)
|
||||||
|
@Index(IndexKind.Indexed)
|
||||||
project!: Ref<Project>
|
project!: Ref<Project>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ export interface FullTextSearchContext extends Class<Doc> {
|
|||||||
fullTextSummary?: boolean
|
fullTextSummary?: boolean
|
||||||
forceIndex?: boolean
|
forceIndex?: boolean
|
||||||
|
|
||||||
// If defined, will propogate changes to childs with defined set of classes
|
// If defined, will propagate changes to child's with defined set of classes
|
||||||
propogate?: Ref<Class<Doc>>[]
|
propogate?: Ref<Class<Doc>>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,7 +401,7 @@ export interface FullTextSearchContext extends Class<Doc> {
|
|||||||
export interface ConfigurationElement extends Class<Doc> {
|
export interface ConfigurationElement extends Class<Doc> {
|
||||||
// Title will be presented to owner.
|
// Title will be presented to owner.
|
||||||
title: IntlString
|
title: IntlString
|
||||||
// Group for groupping.
|
// Group for grouping.
|
||||||
group: IntlString
|
group: IntlString
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ export interface ConfigurationElement extends Class<Doc> {
|
|||||||
*
|
*
|
||||||
* Define configuration value configuration for workspace.
|
* Define configuration value configuration for workspace.
|
||||||
*
|
*
|
||||||
* Configuration is accessble only for owners of workspace and underhood services.
|
* Configuration is accessible only for owners of workspace and under hood services.
|
||||||
*/
|
*/
|
||||||
export interface Configuration extends Doc {
|
export interface Configuration extends Doc {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
@ -420,3 +420,30 @@ export interface Configuration extends Doc {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export type RelatedDocument = Pick<Doc, '_id' | '_class'>
|
export type RelatedDocument = Pick<Doc, '_id' | '_class'>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export enum IndexOrder {
|
||||||
|
Ascending = 1,
|
||||||
|
Descending = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export type FieldIndex<T extends Doc> = {
|
||||||
|
[P in keyof T]?: IndexOrder
|
||||||
|
} & {
|
||||||
|
[key: string]: IndexOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* Mixin for extra indexing fields.
|
||||||
|
*/
|
||||||
|
export interface IndexingConfiguration<T extends Doc> extends Class<Doc> {
|
||||||
|
// Define a list of extra index definitions.
|
||||||
|
indexes: (FieldIndex<T> | string)[]
|
||||||
|
}
|
||||||
|
@ -166,12 +166,13 @@ export async function createClient (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const conn = await connect(txHandler)
|
const conn = await connect(txHandler)
|
||||||
|
const t = Date.now()
|
||||||
const atxes = await conn.findAll(
|
const atxes = await conn.findAll(
|
||||||
core.class.Tx,
|
core.class.Tx,
|
||||||
{ objectSpace: core.space.Model },
|
{ objectSpace: core.space.Model },
|
||||||
{ sort: { _id: SortingOrder.Ascending } }
|
{ sort: { _id: SortingOrder.Ascending } }
|
||||||
)
|
)
|
||||||
console.log('find model', atxes.length)
|
console.log('find model', atxes.length, Date.now() - t)
|
||||||
|
|
||||||
let systemTx: Tx[] = []
|
let systemTx: Tx[] = []
|
||||||
const userTx: Tx[] = []
|
const userTx: Tx[] = []
|
||||||
|
@ -42,7 +42,8 @@ import type {
|
|||||||
UserStatus,
|
UserStatus,
|
||||||
Configuration,
|
Configuration,
|
||||||
ConfigurationElement,
|
ConfigurationElement,
|
||||||
IndexStageState
|
IndexStageState,
|
||||||
|
IndexingConfiguration
|
||||||
} from './classes'
|
} from './classes'
|
||||||
import type {
|
import type {
|
||||||
Tx,
|
Tx,
|
||||||
@ -109,7 +110,8 @@ export default plugin(coreId, {
|
|||||||
},
|
},
|
||||||
mixin: {
|
mixin: {
|
||||||
FullTextSearchContext: '' as Ref<Mixin<FullTextSearchContext>>,
|
FullTextSearchContext: '' as Ref<Mixin<FullTextSearchContext>>,
|
||||||
ConfigurationElement: '' as Ref<Mixin<ConfigurationElement>>
|
ConfigurationElement: '' as Ref<Mixin<ConfigurationElement>>,
|
||||||
|
IndexConfiguration: '' as Ref<Mixin<IndexingConfiguration<Doc>>>
|
||||||
},
|
},
|
||||||
space: {
|
space: {
|
||||||
Tx: '' as Ref<Space>,
|
Tx: '' as Ref<Space>,
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
"AddIssue": "Add Issue",
|
"AddIssue": "Add Issue",
|
||||||
"NewIssue": "New issue",
|
"NewIssue": "New issue",
|
||||||
"ResumeDraft": "Resume draft",
|
"ResumeDraft": "Resume draft",
|
||||||
"SaveIssue": "Save issue",
|
"SaveIssue": "Create issue",
|
||||||
"SetPriority": "Set priority\u2026",
|
"SetPriority": "Set priority\u2026",
|
||||||
"SetStatus": "Set status\u2026",
|
"SetStatus": "Set status\u2026",
|
||||||
"SelectIssue": "Select issue",
|
"SelectIssue": "Select issue",
|
||||||
|
@ -17,9 +17,11 @@ import contact from '@hcengineering/contact'
|
|||||||
import core, {
|
import core, {
|
||||||
BackupClient,
|
BackupClient,
|
||||||
Client as CoreClient,
|
Client as CoreClient,
|
||||||
|
Doc,
|
||||||
Domain,
|
Domain,
|
||||||
DOMAIN_MODEL,
|
DOMAIN_MODEL,
|
||||||
DOMAIN_TX,
|
DOMAIN_TX,
|
||||||
|
FieldIndex,
|
||||||
IndexKind,
|
IndexKind,
|
||||||
Tx,
|
Tx,
|
||||||
WorkspaceId
|
WorkspaceId
|
||||||
@ -198,7 +200,7 @@ async function createUpdateIndexes (connection: CoreClient, db: Db): Promise<voi
|
|||||||
const classes = await connection.findAll(core.class.Class, {})
|
const classes = await connection.findAll(core.class.Class, {})
|
||||||
|
|
||||||
const hierarchy = connection.getHierarchy()
|
const hierarchy = connection.getHierarchy()
|
||||||
const domains = new Map<Domain, Set<string>>()
|
const domains = new Map<Domain, Set<string | FieldIndex<Doc>>>()
|
||||||
// Find all domains and indexed fields inside
|
// Find all domains and indexed fields inside
|
||||||
for (const c of classes) {
|
for (const c of classes) {
|
||||||
try {
|
try {
|
||||||
@ -207,22 +209,30 @@ async function createUpdateIndexes (connection: CoreClient, db: Db): Promise<voi
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const attrs = hierarchy.getAllAttributes(c._id)
|
const attrs = hierarchy.getAllAttributes(c._id)
|
||||||
const domainAttrs = domains.get(domain) ?? new Set<string>()
|
const domainAttrs = domains.get(domain) ?? new Set<string | FieldIndex<Doc>>()
|
||||||
for (const a of attrs.values()) {
|
for (const a of attrs.values()) {
|
||||||
if (a.index !== undefined && a.index === IndexKind.Indexed) {
|
if (a.index !== undefined && a.index === IndexKind.Indexed) {
|
||||||
domainAttrs.add(a.name)
|
domainAttrs.add(a.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle extra configurations
|
||||||
|
if (hierarchy.hasMixin(c, core.mixin.IndexConfiguration)) {
|
||||||
|
const config = hierarchy.as(c, core.mixin.IndexConfiguration)
|
||||||
|
for (const attr of config.indexes) {
|
||||||
|
domainAttrs.add(attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
domains.set(domain, domainAttrs)
|
domains.set(domain, domainAttrs)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// Ignore, since we have clases without domain.
|
// Ignore, since we have classes without domain.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [d, v] of domains.entries()) {
|
for (const [d, v] of domains.entries()) {
|
||||||
const collection = db.collection(d)
|
const collection = db.collection(d)
|
||||||
const bb: string[] = []
|
const bb: (string | FieldIndex<Doc>)[] = []
|
||||||
for (const vv of v.values()) {
|
for (const vv of v.values()) {
|
||||||
await collection.createIndex(vv)
|
await collection.createIndex(vv)
|
||||||
bb.push(vv)
|
bb.push(vv)
|
||||||
|
@ -30,7 +30,7 @@ test.describe('project tests', () => {
|
|||||||
await page.fill('[placeholder="Issue\\ title"]', 'issue')
|
await page.fill('[placeholder="Issue\\ title"]', 'issue')
|
||||||
await page.click('form button:has-text("Project")')
|
await page.click('form button:has-text("Project")')
|
||||||
await page.click(`.selectPopup button:has-text("${prjId}")`)
|
await page.click(`.selectPopup button:has-text("${prjId}")`)
|
||||||
await page.click('form button:has-text("Save issue")')
|
await page.click('form button:has-text("Create issue")')
|
||||||
await page.waitForSelector('form.antiCard', { state: 'detached' })
|
await page.waitForSelector('form.antiCard', { state: 'detached' })
|
||||||
|
|
||||||
await page.click('.listGrid :has-text("issue")')
|
await page.click('.listGrid :has-text("issue")')
|
||||||
|
@ -84,7 +84,7 @@ export async function createIssue (page: Page, props: IssueProps): Promise<void>
|
|||||||
await page.waitForSelector('span:has-text("Default")')
|
await page.waitForSelector('span:has-text("Default")')
|
||||||
await page.click('button:has-text("New issue")')
|
await page.click('button:has-text("New issue")')
|
||||||
await fillIssueForm(page, props)
|
await fillIssueForm(page, props)
|
||||||
await page.click('button:has-text("Save issue")')
|
await page.click('button:has-text("Create issue")')
|
||||||
await page.waitForSelector('form.antiCard', { state: 'detached' })
|
await page.waitForSelector('form.antiCard', { state: 'detached' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user