From 28dca6632cc30f48d112b054c068c028d84a0298 Mon Sep 17 00:00:00 2001 From: Vyacheslav Tumanov Date: Tue, 23 Jan 2024 20:26:15 +0500 Subject: [PATCH] UBERF-5018: search improvements/Indexing fix (#4403) Signed-off-by: Vyacheslav Tumanov --- models/server-contact/src/index.ts | 4 ++- models/server-core/src/index.ts | 4 +-- models/server-recruit/src/index.ts | 7 +++-- server-plugins/contact/src/index.ts | 4 +-- server/core/src/indexer/fulltextPush.ts | 4 +-- server/core/src/indexer/types.ts | 2 +- server/core/src/mapper.ts | 34 +++++++++++++++++++------ server/core/src/types.ts | 10 +++++--- 8 files changed, 48 insertions(+), 21 deletions(-) diff --git a/models/server-contact/src/index.ts b/models/server-contact/src/index.ts index 49adc09336..eb1df4ba0d 100644 --- a/models/server-contact/src/index.ts +++ b/models/server-contact/src/index.ts @@ -55,7 +55,9 @@ export function createModel (builder: Builder): void { } ] }, - getSearchTitle: serverContact.function.ContactNameProvider + getSearchTitle: { + name: serverContact.function.ContactNameProvider + } }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { diff --git a/models/server-core/src/index.ts b/models/server-core/src/index.ts index 6ef15b74a5..919cfd38d4 100644 --- a/models/server-core/src/index.ts +++ b/models/server-core/src/index.ts @@ -45,8 +45,8 @@ export class TObjectDDParticipant extends TClass implements ObjectDDParticipant @Mixin(serverCore.mixin.SearchPresenter, core.class.Class) export class TSearchPresenter extends TClass implements SearchPresenter { searchConfig!: ClassSearchConfig - getSearchShortTitle!: Resource - getSearchTitle!: Resource + getSearchShortTitle!: SearchPresenterFunc + getSearchTitle!: SearchPresenterFunc } export function createModel (builder: Builder): void { diff --git a/models/server-recruit/src/index.ts b/models/server-recruit/src/index.ts index 823a55f73f..6b4f5ae7db 100644 --- a/models/server-recruit/src/index.ts +++ b/models/server-recruit/src/index.ts @@ -65,10 +65,13 @@ export function createModel (builder: Builder): void { props: ['number'] }, title: { - props: [{ _class: ['attachedTo', '_class'] }, { name: ['attachedTo', 'name'] }] + tmpl: '{name} - {vacName}', + props: [{ _class: ['attachedTo', '_class'] }, { name: ['attachedTo', 'name'] }, { vacName: ['space', 'name'] }] } }, - getSearchTitle: serverContact.function.ContactNameProvider + getSearchTitle: { + name: serverContact.function.ContactNameProvider + } }) builder.mixin( diff --git a/server-plugins/contact/src/index.ts b/server-plugins/contact/src/index.ts index 7554ea4858..816537037a 100644 --- a/server-plugins/contact/src/index.ts +++ b/server-plugins/contact/src/index.ts @@ -16,7 +16,7 @@ import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import type { TriggerFunc, SearchPresenterFunc } from '@hcengineering/server-core' +import type { TriggerFunc, SearchPresenterProvider } from '@hcengineering/server-core' import { Presenter } from '@hcengineering/server-notification' /** @@ -38,6 +38,6 @@ export default plugin(serverContactId, { OrganizationHTMLPresenter: '' as Resource, OrganizationTextPresenter: '' as Resource, - ContactNameProvider: '' as Resource + ContactNameProvider: '' as Resource } }) diff --git a/server/core/src/indexer/fulltextPush.ts b/server/core/src/indexer/fulltextPush.ts index a60b08c023..45ff201e9e 100644 --- a/server/core/src/indexer/fulltextPush.ts +++ b/server/core/src/indexer/fulltextPush.ts @@ -178,12 +178,12 @@ export class FullTextPushStage implements FullTextPipelineStage { } } } - const parentDoc: DocIndexState | undefined = undefined + let parentDoc: DocIndexState | undefined if (doc.attachedToClass != null && doc.attachedTo != null) { const propagate: Ref>[] = collectPropagate(pipeline, doc.attachedToClass) if (propagate.some((it) => pipeline.hierarchy.isDerived(doc.objectClass, it))) { // We need to include all parent content into this one. - const [parentDoc] = await metrics.with( + ;[parentDoc] = await metrics.with( 'find-parent', {}, async (ctx) => diff --git a/server/core/src/indexer/types.ts b/server/core/src/indexer/types.ts index d9851d1dd1..f81b0a351c 100644 --- a/server/core/src/indexer/types.ts +++ b/server/core/src/indexer/types.ts @@ -107,4 +107,4 @@ export const fieldStateId = 'fld-v11' /** * @public */ -export const fullTextPushStageId = 'fts-v9' +export const fullTextPushStageId = 'fts-v9bc' diff --git a/server/core/src/mapper.ts b/server/core/src/mapper.ts index 9d777d91a0..9f26cd7fd8 100644 --- a/server/core/src/mapper.ts +++ b/server/core/src/mapper.ts @@ -1,8 +1,8 @@ import { Class, Doc, DocIndexState, docKey, Hierarchy, Ref, RefTo, SearchResultDoc } from '@hcengineering/core' -import { getResource } from '@hcengineering/platform' +import { getResource, Resource } from '@hcengineering/platform' import plugin from './plugin' -import { ClassSearchConfigProps, IndexedDoc, SearchPresenter, SearchScoring } from './types' +import { ClassSearchConfigProps, IndexedDoc, SearchPresenter, SearchPresenterFunc, SearchScoring } from './types' interface IndexedReader { get: (attribute: string) => any @@ -39,7 +39,14 @@ function createIndexedReader ( } } -function readAndMapProps (reader: IndexedReader, props: ClassSearchConfigProps[]): Record { +async function readAndMapProps ( + reader: IndexedReader, + props: ClassSearchConfigProps[], + searchProvider?: { + hierarchy: Hierarchy + providers: SearchPresenterFunc + } +): Promise> { const res: Record = {} for (const prop of props) { if (typeof prop === 'string') { @@ -48,7 +55,18 @@ function readAndMapProps (reader: IndexedReader, props: ClassSearchConfigProps[] for (const [propName, rest] of Object.entries(prop)) { if (rest.length > 1) { const val = reader.getDoc(rest[0])?.get(rest[1]) - res[propName] = Array.isArray(val) ? val[0] : val + const v = Array.isArray(val) ? val[0] : val + if (searchProvider !== undefined) { + const func = + searchProvider.providers !== undefined && Object.keys(searchProvider.providers).includes(propName) + ? ((await getResource(searchProvider.providers[propName])) as any) + : undefined + if (func !== undefined) { + res[propName] = func(searchProvider.hierarchy, { _class: res?._class, [propName]: v }) + continue + } + } + res[propName] = v } } } @@ -116,16 +134,16 @@ export async function updateDocWithPresenter ( let value if (prop.config.tmpl !== undefined) { const tmpl = prop.config.tmpl - const renderProps = readAndMapProps(reader, prop.config.props) + const renderProps = await readAndMapProps(reader, prop.config.props, { hierarchy, providers: prop.provider }) value = fillTemplate(tmpl, renderProps) } else if (typeof prop.config === 'string') { value = reader.get(prop.config) } else if (prop.provider !== undefined) { - const func = (await getResource(prop.provider)) as any - const renderProps = readAndMapProps(reader, prop.config.props) + const func = await getResource(Object.values(prop.provider)[0] as Resource) + const renderProps = await readAndMapProps(reader, prop.config.props) value = func(hierarchy, { _class: elasticDoc._class, ...renderProps }) } else if (prop.name === 'searchIcon') { - value = readAndMapProps(reader, prop.config.props) + value = await readAndMapProps(reader, prop.config.props) } elasticDoc[prop.name] = value } diff --git a/server/core/src/types.ts b/server/core/src/types.ts index 750a7dd137..05cc8cf5df 100644 --- a/server/core/src/types.ts +++ b/server/core/src/types.ts @@ -349,7 +349,11 @@ export type SearchProps = Record /** * @public */ -export type SearchPresenterFunc = (hierarchy: Hierarchy, props: SearchProps) => string +export type SearchPresenterProvider = (hierarchy: Hierarchy, props: SearchProps) => string +/** + * @public + */ +export type SearchPresenterFunc = Record> /** * @public @@ -386,6 +390,6 @@ export interface ClassSearchConfig { */ export interface SearchPresenter extends Class { searchConfig: ClassSearchConfig - getSearchShortTitle?: Resource - getSearchTitle?: Resource + getSearchShortTitle?: SearchPresenterFunc + getSearchTitle?: SearchPresenterFunc }