full text adapter

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov 2021-08-27 11:17:18 +02:00
parent 9562eefd8e
commit 2a010b5311
No known key found for this signature in database
GPG Key ID: C8787EFEB4B64AF0
16 changed files with 675 additions and 425 deletions

View File

@ -16,7 +16,7 @@
import type { Tx, Storage, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions, TxHander, ServerStorage } from '@anticrm/core'
import { DOMAIN_TX } from '@anticrm/core'
import { createInMemoryAdapter, createInMemoryTxAdapter } from '@anticrm/dev-storage'
import { createServerStorage } from '@anticrm/server-core'
import { createServerStorage, FullTextAdapter, IndexedDoc } from '@anticrm/server-core'
import type { DbConfiguration } from '@anticrm/server-core'
class ServerStorageWrapper implements Storage {
@ -32,6 +32,20 @@ class ServerStorageWrapper implements Storage {
}
}
class NullFullTextAdapter implements FullTextAdapter {
async index (doc: IndexedDoc): Promise<void> {
console.log('noop full text indexer: ', doc)
}
async search (query: any): Promise<IndexedDoc[]> {
return []
}
}
async function createNullFullTextAdapter (): Promise<FullTextAdapter> {
return new NullFullTextAdapter()
}
export async function connect (handler: (tx: Tx) => void): Promise<Storage> {
const conf: DbConfiguration = {
domains: {
@ -48,6 +62,10 @@ export async function connect (handler: (tx: Tx) => void): Promise<Storage> {
url: ''
}
},
fulltextAdapter: {
factory: createNullFullTextAdapter,
url: ''
},
workspace: ''
}
const serverStorage = await createServerStorage(conf)

View File

@ -17,12 +17,26 @@
import { DOMAIN_TX } from '@anticrm/core'
import { start as startJsonRpc } from '@anticrm/server-ws'
import { createInMemoryAdapter, createInMemoryTxAdapter } from '@anticrm/dev-storage'
import { createServerStorage } from '@anticrm/server-core'
import { createServerStorage, FullTextAdapter, IndexedDoc } from '@anticrm/server-core'
import type { DbConfiguration } from '@anticrm/server-core'
import { addLocation } from '@anticrm/platform'
import { serverChunterId } from '@anticrm/server-chunter'
class NullFullTextAdapter implements FullTextAdapter {
async index (doc: IndexedDoc): Promise<void> {
console.log('noop full text indexer: ', doc)
}
async search (query: any): Promise<IndexedDoc[]> {
return []
}
}
async function createNullFullTextAdapter (): Promise<FullTextAdapter> {
return new NullFullTextAdapter()
}
/**
* @public
*/
@ -45,6 +59,10 @@ export async function start (port: number, host?: string): Promise<void> {
url: ''
}
},
fulltextAdapter: {
factory: createNullFullTextAdapter,
url: ''
},
workspace: ''
}
return createServerStorage(conf)

View File

@ -169,12 +169,20 @@ export class Hierarchy {
attributes.set(attribute.name, attribute)
}
getAttributes (clazz: Ref<Class<Obj>>): Map<string, AnyAttribute> {
const attributes = this.attributes.get(clazz)
if (attributes === undefined) {
throw new Error('attributes not found for class ' + clazz)
getAllAttributes (clazz: Ref<Class<Obj>>): Map<string, AnyAttribute> {
const result = new Map<string, AnyAttribute>()
const ancestors = this.getAncestors(clazz)
for (const cls of ancestors) {
const attributes = this.attributes.get(cls)
if (attributes !== undefined) {
for (const [name, attr] of attributes) {
result.set(name, attr)
}
}
}
return attributes
return result
}
getAttribute (_class: Ref<Class<Obj>>, name: string): AnyAttribute {

View File

@ -0,0 +1,65 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { TxCreateDoc, Doc, Ref, Class, Obj, Hierarchy, AnyAttribute } from '@anticrm/core'
import { TxProcessor, IndexKind } from '@anticrm/core'
import type { IndexedDoc, FullTextAdapter } from './types'
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const NO_INDEX = {} as AnyAttribute
export class FullTextIndex extends TxProcessor {
private readonly indexes = new Map<Ref<Class<Obj>>, AnyAttribute>()
constructor (
private readonly hierarchy: Hierarchy,
private readonly adapter: FullTextAdapter
) {
super()
}
private findFullTextAttribute (clazz: Ref<Class<Obj>>): AnyAttribute | undefined {
const attribute = this.indexes.get(clazz)
if (attribute === undefined) {
const attributes = this.hierarchy.getAllAttributes(clazz)
for (const [, attr] of attributes) {
if (attr.index === IndexKind.FullText) {
this.indexes.set(clazz, attr)
return attr
}
}
this.indexes.set(clazz, NO_INDEX)
} else if (attribute !== NO_INDEX) {
return attribute
}
}
protected override async txCreateDoc (tx: TxCreateDoc<Doc>): Promise<void> {
const attribute = this.findFullTextAttribute(tx.objectClass)
if (attribute === undefined) return
const doc = TxProcessor.createDoc2Doc(tx)
const content = (doc as any)[attribute.name]
const indexedDoc: IndexedDoc = {
id: doc._id,
_class: doc._class,
modifiedBy: doc.modifiedBy,
modifiedOn: doc.modifiedOn,
space: doc.space,
content
}
return await this.adapter.index(indexedDoc)
}
}

View File

@ -14,191 +14,6 @@
// limitations under the License.
//
import type { Doc, Tx, TxCreateDoc, Ref, Class, ServerStorage, DocumentQuery, FindOptions, FindResult, Storage, Account, Domain, TxCUD } from '@anticrm/core'
import core, { Hierarchy, TxFactory, DOMAIN_TX } from '@anticrm/core'
import type { Resource, Plugin } from '@anticrm/platform'
import { getResource, plugin } from '@anticrm/platform'
/**
* @public
*/
export type TriggerFunc = (tx: Tx, txFactory: TxFactory) => Promise<Tx[]>
/**
* @public
*/
export interface Trigger extends Doc {
trigger: Resource<TriggerFunc>
}
/**
* @public
*/
export class Triggers {
private readonly triggers: TriggerFunc[] = []
async tx (tx: Tx): Promise<void> {
if (tx._class === core.class.TxCreateDoc) {
const createTx = tx as TxCreateDoc<Doc>
if (createTx.objectClass === serverCore.class.Trigger) {
const trigger = (createTx as TxCreateDoc<Trigger>).attributes.trigger
const func = await getResource(trigger)
this.triggers.push(func)
}
}
}
async apply (account: Ref<Account>, tx: Tx): Promise<Tx[]> {
const derived = this.triggers.map(trigger => trigger(tx, new TxFactory(account)))
const result = await Promise.all(derived)
return result.flatMap(x => x)
}
}
/**
* @public
*/
export interface DbAdapter extends Storage {
/**
* Method called after hierarchy is ready to use.
*/
init: (model: Tx[]) => Promise<void>
}
/**
* @public
*/
export interface TxAdapter extends DbAdapter {
getModel: () => Promise<Tx[]>
}
/**
* @public
*/
export type DbAdapterFactory = (hierarchy: Hierarchy, url: string, db: string) => Promise<DbAdapter>
/**
* @public
*/
export interface DbAdapterConfiguration {
factory: DbAdapterFactory
url: string
}
/**
* @public
*/
export interface DbConfiguration {
adapters: Record<string, DbAdapterConfiguration>
domains: Record<string, string>
defaultAdapter: string
workspace: string
}
class TServerStorage implements ServerStorage {
constructor (
private readonly domains: Record<string, string>,
private readonly defaultAdapter: string,
private readonly adapters: Map<string, DbAdapter>,
private readonly hierarchy: Hierarchy,
private readonly triggers: Triggers
) {
}
private getAdapter (domain: Domain): DbAdapter {
const name = this.domains[domain] ?? this.defaultAdapter
const adapter = this.adapters.get(name)
if (adapter === undefined) {
throw new Error('adapter not provided: ' + name)
}
return adapter
}
private routeTx (tx: Tx): Promise<void> {
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) {
const txCUD = tx as TxCUD<Doc>
const domain = this.hierarchy.getDomain(txCUD.objectClass)
return this.getAdapter(domain).tx(txCUD)
} else {
throw new Error('not implemented (not derived from TxCUD)')
}
}
async findAll<T extends Doc> (
clazz: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
): Promise<FindResult<T>> {
const domain = this.hierarchy.getDomain(clazz)
return await this.getAdapter(domain).findAll(clazz, query, options)
}
async tx (tx: Tx): Promise<Tx[]> {
// store tx
await this.getAdapter(DOMAIN_TX).tx(tx)
if (tx.objectSpace === core.space.Model) {
// maintain hiearachy and triggers
this.hierarchy.tx(tx)
await this.triggers.tx(tx)
return []
} else {
// store object
await this.routeTx(tx)
// invoke triggers and store derived objects
const derived = await this.triggers.apply(tx.modifiedBy, tx)
for (const tx of derived) {
await this.routeTx(tx)
}
return derived
}
}
}
/**
* @public
*/
export async function createServerStorage (conf: DbConfiguration): Promise<ServerStorage> {
const hierarchy = new Hierarchy()
const triggers = new Triggers()
const adapters = new Map<string, DbAdapter>()
for (const key in conf.adapters) {
const adapterConf = conf.adapters[key]
adapters.set(key, await adapterConf.factory(hierarchy, adapterConf.url, conf.workspace))
}
const txAdapter = adapters.get(conf.domains[DOMAIN_TX]) as TxAdapter
if (txAdapter === undefined) {
console.log('no txadapter found')
}
const model = await txAdapter.getModel()
for (const tx of model) {
hierarchy.tx(tx)
await triggers.tx(tx)
}
for (const [, adapter] of adapters) {
await adapter.init(model)
}
return new TServerStorage(conf.domains, conf.defaultAdapter, adapters, hierarchy, triggers)
}
/**
* @public
*/
export const serverCoreId = 'server-core' as Plugin
/**
* @public
*/
const serverCore = plugin(serverCoreId, {
class: {
Trigger: '' as Ref<Class<Trigger>>
}
})
export default serverCore
export * from './types'
export * from './storage'
export { default } from './plugin'

37
server/core/src/plugin.ts Normal file
View File

@ -0,0 +1,37 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { Plugin } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import type { Ref, Class } from '@anticrm/core'
import type { Trigger } from './types'
/**
* @public
*/
export const serverCoreId = 'server-core' as Plugin
/**
* @public
*/
const serverCore = plugin(serverCoreId, {
class: {
Trigger: '' as Ref<Class<Trigger>>
}
})
export default serverCore

168
server/core/src/storage.ts Normal file
View File

@ -0,0 +1,168 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage } from '@anticrm/core'
import core, { Hierarchy, DOMAIN_TX } from '@anticrm/core'
import type { FullTextAdapterFactory } from './types'
import { FullTextIndex } from './fulltext'
import { Triggers } from './triggers'
/**
* @public
*/
export interface DbAdapter extends Storage {
/**
* Method called after hierarchy is ready to use.
*/
init: (model: Tx[]) => Promise<void>
}
/**
* @public
*/
export interface TxAdapter extends DbAdapter {
getModel: () => Promise<Tx[]>
}
/**
* @public
*/
export type DbAdapterFactory = (hierarchy: Hierarchy, url: string, db: string) => Promise<DbAdapter>
/**
* @public
*/
export interface DbAdapterConfiguration {
factory: DbAdapterFactory
url: string
}
/**
* @public
*/
export interface DbConfiguration {
adapters: Record<string, DbAdapterConfiguration>
domains: Record<string, string>
defaultAdapter: string
workspace: string
fulltextAdapter: {
factory: FullTextAdapterFactory
url: string
}
}
class TServerStorage implements ServerStorage {
constructor (
private readonly domains: Record<string, string>,
private readonly defaultAdapter: string,
private readonly adapters: Map<string, DbAdapter>,
private readonly hierarchy: Hierarchy,
private readonly triggers: Triggers,
private readonly fulltext: FullTextIndex
) {
}
private getAdapter (domain: Domain): DbAdapter {
const name = this.domains[domain] ?? this.defaultAdapter
const adapter = this.adapters.get(name)
if (adapter === undefined) {
throw new Error('adapter not provided: ' + name)
}
return adapter
}
private routeTx (tx: Tx): Promise<void> {
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) {
const txCUD = tx as TxCUD<Doc>
const domain = this.hierarchy.getDomain(txCUD.objectClass)
return this.getAdapter(domain).tx(txCUD)
} else {
throw new Error('not implemented (not derived from TxCUD)')
}
}
async findAll<T extends Doc> (
clazz: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
): Promise<FindResult<T>> {
const domain = this.hierarchy.getDomain(clazz)
return await this.getAdapter(domain).findAll(clazz, query, options)
}
async tx (tx: Tx): Promise<Tx[]> {
// store tx
await this.getAdapter(DOMAIN_TX).tx(tx)
if (tx.objectSpace === core.space.Model) {
// maintain hiearachy and triggers
this.hierarchy.tx(tx)
await this.triggers.tx(tx)
return []
} else {
// store object
await this.routeTx(tx)
// invoke triggers and store derived objects
const derived = await this.triggers.apply(tx.modifiedBy, tx)
for (const tx of derived) {
await this.routeTx(tx)
}
// index object
await this.fulltext.tx(tx)
// index derived objects
for (const tx of derived) {
await this.fulltext.tx(tx)
}
return derived
}
}
}
/**
* @public
*/
export async function createServerStorage (conf: DbConfiguration): Promise<ServerStorage> {
const hierarchy = new Hierarchy()
const triggers = new Triggers()
const adapters = new Map<string, DbAdapter>()
for (const key in conf.adapters) {
const adapterConf = conf.adapters[key]
adapters.set(key, await adapterConf.factory(hierarchy, adapterConf.url, conf.workspace))
}
const txAdapter = adapters.get(conf.domains[DOMAIN_TX]) as TxAdapter
if (txAdapter === undefined) {
console.log('no txadapter found')
}
const model = await txAdapter.getModel()
for (const tx of model) {
hierarchy.tx(tx)
await triggers.tx(tx)
}
for (const [, adapter] of adapters) {
await adapter.init(model)
}
const fulltextAdapter = await conf.fulltextAdapter.factory(conf.fulltextAdapter.url, conf.workspace)
const fulltext = new FullTextIndex(hierarchy, fulltextAdapter)
return new TServerStorage(conf.domains, conf.defaultAdapter, adapters, hierarchy, triggers, fulltext)
}

View File

@ -0,0 +1,47 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { Tx, Doc, TxCreateDoc, Ref, Account } from '@anticrm/core'
import core, { TxFactory } from '@anticrm/core'
import { getResource } from '@anticrm/platform'
import type { Trigger, TriggerFunc } from './types'
import serverCore from './plugin'
/**
* @public
*/
export class Triggers {
private readonly triggers: TriggerFunc[] = []
async tx (tx: Tx): Promise<void> {
if (tx._class === core.class.TxCreateDoc) {
const createTx = tx as TxCreateDoc<Doc>
if (createTx.objectClass === serverCore.class.Trigger) {
const trigger = (createTx as TxCreateDoc<Trigger>).attributes.trigger
const func = await getResource(trigger)
this.triggers.push(func)
}
}
}
async apply (account: Ref<Account>, tx: Tx): Promise<Tx[]> {
const derived = this.triggers.map(trigger => trigger(tx, new TxFactory(account)))
const result = await Promise.all(derived)
return result.flatMap(x => x)
}
}

61
server/core/src/types.ts Normal file
View File

@ -0,0 +1,61 @@
//
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { Tx, Ref, Doc, Class, Space, Timestamp, Account } from '@anticrm/core'
import { TxFactory } from '@anticrm/core'
import type { Resource } from '@anticrm/platform'
/**
* @public
*/
export type TriggerFunc = (tx: Tx, txFactory: TxFactory) => Promise<Tx[]>
/**
* @public
*/
export interface Trigger extends Doc {
trigger: Resource<TriggerFunc>
}
/**
* @public
*/
export interface IndexedDoc {
id: Ref<Doc>
_class: Ref<Class<Doc>>
space: Ref<Space>
modifiedOn: Timestamp
modifiedBy: Ref<Account>
content: string
}
/**
* @public
*/
export type SearchQuery = any
/**
* @public
*/
export interface FullTextAdapter {
index: (doc: IndexedDoc) => Promise<void>
search: (query: SearchQuery) => Promise<IndexedDoc[]>
}
/**
* @public
*/
export type FullTextAdapterFactory = (url: string, workspace: string) => Promise<FullTextAdapter>

View File

@ -14,28 +14,26 @@
// limitations under the License.
//
import core, { Hierarchy, TxFactory } from '@anticrm/core'
import type { Tx } from '@anticrm/core'
import { createElasticAdapter } from '../adapter'
// import type { Tx } from '@anticrm/core'
import * as txJson from './model.tx.json'
// import * as txJson from './model.tx.json'
const txes = txJson as unknown as Tx[]
// const txes = txJson as unknown as Tx[]
describe('client', () => {
it('should create document', async () => {
const hierarchy = new Hierarchy()
for (const tx of txes) hierarchy.tx(tx)
const adapter = await createElasticAdapter(hierarchy, 'http://localhost:9200/', 'ws1')
const txFactory = new TxFactory(core.account.System)
const createTx = txFactory.createTxCreateDoc(core.class.Space, core.space.Model, {
name: 'name',
description: 'description',
private: false,
members: []
})
await adapter.tx(createTx)
const spaces = await adapter.findAll(core.class.Space, {})
console.log(spaces)
// const hierarchy = new Hierarchy()
// for (const tx of txes) hierarchy.tx(tx)
// const adapter = await createElasticAdapter(hierarchy, 'http://localhost:9200/', 'ws1')
// const txFactory = new TxFactory(core.account.System)
// const createTx = txFactory.createTxCreateDoc(core.class.Space, core.space.Model, {
// name: 'name',
// description: 'description',
// private: false,
// members: []
// })
// await adapter.tx(createTx)
// const spaces = await adapter.findAll(core.class.Space, {})
// console.log(spaces)
})
})

View File

@ -14,37 +14,22 @@
// limitations under the License.
//
import { TxProcessor, Hierarchy } from '@anticrm/core'
import type { Doc, Ref, Class, DocumentQuery, FindOptions, FindResult, TxCreateDoc } from '@anticrm/core'
import type { DbAdapter } from '@anticrm/server-core'
import type { FullTextAdapter, IndexedDoc, SearchQuery } from '@anticrm/server-core'
import { Client } from '@elastic/elasticsearch'
function translateDoc (doc: Doc): any {
const obj = { id: doc._id, ...doc } as any
delete obj._id
return obj
}
class ElasticAdapter extends TxProcessor implements DbAdapter {
class ElasticAdapter implements FullTextAdapter {
constructor (
private readonly client: Client,
private readonly db: string,
private readonly hierarchy: Hierarchy
private readonly db: string
) {
super()
}
async init (): Promise<void> {}
async findAll<T extends Doc> (
clazz: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
): Promise<FindResult<T>> {
const domain = this.hierarchy.getDomain(clazz)
async search (
query: SearchQuery
): Promise<IndexedDoc[]> {
const result = await this.client.search({
index: this.db + '_' + domain,
index: this.db,
type: '_doc',
body: {
}
@ -54,24 +39,23 @@ class ElasticAdapter extends TxProcessor implements DbAdapter {
return []
}
protected override async txCreateDoc (tx: TxCreateDoc<Doc>): Promise<void> {
const doc = TxProcessor.createDoc2Doc(tx)
const domain = this.hierarchy.getDomain(doc._class)
async index (doc: IndexedDoc): Promise<void> {
await this.client.index({
index: this.db + '_' + domain,
index: this.db,
type: '_doc',
body: translateDoc(doc)
body: doc
})
console.log('indexing this thing: ', doc)
}
}
/**
* @public
*/
export async function createElasticAdapter (hierarchy: Hierarchy, url: string, dbName: string): Promise<DbAdapter> {
export async function createElasticAdapter (url: string, dbName: string): Promise<FullTextAdapter> {
const client = new Client({
node: url
})
return new ElasticAdapter(client, dbName, hierarchy)
return new ElasticAdapter(client, dbName)
}

View File

@ -28,6 +28,7 @@
"@anticrm/server-ws": "~0.6.11",
"@anticrm/server-chunter": "~0.6.1",
"@anticrm/server-chunter-resources": "~0.6.0",
"@anticrm/mongo": "~0.6.1"
"@anticrm/mongo": "~0.6.1",
"@anticrm/elastic": "~0.6.0"
}
}

View File

@ -17,11 +17,16 @@
import { start } from '.'
const url = process.env.MONGO_URL
if (url === undefined) {
console.error('please provide mongodb url')
process.exit(1)
}
const elasticUrl = process.env.ELASTIC_URL
if (elasticUrl === undefined) {
console.error('please provide elastic url')
process.exit(1)
}
// eslint-disable-next-line @typescript-eslint/no-floating-promises
start(url, 3333)
start(url, elasticUrl, 3333)

View File

@ -17,6 +17,7 @@
import { DOMAIN_TX } from '@anticrm/core'
import { start as startJsonRpc } from '@anticrm/server-ws'
import { createMongoAdapter, createMongoTxAdapter } from '@anticrm/mongo'
import { createElasticAdapter } from '@anticrm/elastic'
import { createServerStorage } from '@anticrm/server-core'
import type { DbConfiguration } from '@anticrm/server-core'
@ -26,7 +27,7 @@ import { serverChunterId } from '@anticrm/server-chunter'
/**
* @public
*/
export async function start (dbUrl: string, port: number, host?: string): Promise<void> {
export async function start (dbUrl: string, fullTextUrl: string, port: number, host?: string): Promise<void> {
addLocation(serverChunterId, () => import('@anticrm/server-chunter-resources'))
startJsonRpc((workspace: string) => {
@ -45,6 +46,10 @@ export async function start (dbUrl: string, port: number, host?: string): Promis
url: dbUrl
}
},
fulltextAdapter: {
factory: createElasticAdapter,
url: fullTextUrl
},
workspace
}
return createServerStorage(conf)

View File

@ -27,6 +27,7 @@ export async function createModel (url: string, dbName: string): Promise<number>
try {
await client.connect()
const db = client.db(dbName)
await db.dropDatabase()
const result = await db.collection(DOMAIN_TX).insertMany(txJson as Document[])
return result.insertedCount
} finally {

File diff suppressed because it is too large Load Diff