diff --git a/dev/client-resources/package.json b/dev/client-resources/package.json index 9abf1af16d..c11e1bba69 100644 --- a/dev/client-resources/package.json +++ b/dev/client-resources/package.json @@ -21,6 +21,7 @@ "@anticrm/platform":"~0.6.5", "@anticrm/core":"~0.6.11", "@anticrm/client":"~0.6.1", - "@anticrm/dev-storage":"~0.6.6" + "@anticrm/dev-storage":"~0.6.6", + "@anticrm/server-core":"~0.6.1" } } diff --git a/dev/client-resources/src/connection.ts b/dev/client-resources/src/connection.ts index 1d96dc7538..fbde61903b 100644 --- a/dev/client-resources/src/connection.ts +++ b/dev/client-resources/src/connection.ts @@ -13,19 +13,9 @@ // limitations under the License. // -import type { - Tx, - Storage, - Ref, - Doc, - Class, - DocumentQuery, - FindResult, - FindOptions, - TxHander, - ServerStorage -} from '@anticrm/core' -import { createStorage } from '@anticrm/dev-storage' +import type { Tx, Storage, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions, TxHander, ServerStorage } from '@anticrm/core' +import { createInMemoryAdapter } from '@anticrm/dev-storage' +import { createServerStorage } from '@anticrm/server-core' class ServerStorageWrapper implements Storage { constructor (private readonly storage: ServerStorage, private readonly handler: TxHander) {} @@ -41,6 +31,6 @@ class ServerStorageWrapper implements Storage { } export async function connect (handler: (tx: Tx) => void): Promise { - const serverStorage = await createStorage() + const serverStorage = await createServerStorage(createInMemoryAdapter, '', '') return new ServerStorageWrapper(serverStorage, handler) } diff --git a/dev/server/package.json b/dev/server/package.json index e588de87e8..cb81dce629 100644 --- a/dev/server/package.json +++ b/dev/server/package.json @@ -26,6 +26,7 @@ "@anticrm/platform": "~0.6.5", "jwt-simple": "~0.5.6", "@anticrm/server-chunter": "~0.6.1", - "@anticrm/server-chunter-resources": "~0.6.0" + "@anticrm/server-chunter-resources": "~0.6.0", + "@anticrm/server-core": "~0.6.1" } } diff --git a/dev/server/src/server.ts b/dev/server/src/server.ts index 95c76bde6b..b8b77f2c84 100644 --- a/dev/server/src/server.ts +++ b/dev/server/src/server.ts @@ -15,7 +15,8 @@ // import { start as startJsonRpc } from '@anticrm/server-ws' -import { createStorage } from '@anticrm/dev-storage' +import { createInMemoryAdapter } from '@anticrm/dev-storage' +import { createServerStorage } from '@anticrm/server-core' import { addLocation } from '@anticrm/platform' import { serverChunterId } from '@anticrm/server-chunter' @@ -26,5 +27,5 @@ import { serverChunterId } from '@anticrm/server-chunter' export async function start (port: number, host?: string): Promise { addLocation(serverChunterId, () => import('@anticrm/server-chunter-resources')) - startJsonRpc(() => createStorage(), port, host) + startJsonRpc(() => createServerStorage(createInMemoryAdapter, '', ''), port, host) } diff --git a/dev/storage/src/__tests__/storage.test.ts b/dev/storage/src/__tests__/storage.test.txt similarity index 100% rename from dev/storage/src/__tests__/storage.test.ts rename to dev/storage/src/__tests__/storage.test.txt diff --git a/dev/storage/src/index.ts b/dev/storage/src/index.ts index 0cd297485c..a85cfdc0b9 100644 --- a/dev/storage/src/index.ts +++ b/dev/storage/src/index.ts @@ -14,4 +14,4 @@ // limitations under the License. // -export { createStorage } from './storage' +export { createInMemoryAdapter } from './storage' diff --git a/dev/storage/src/storage.ts b/dev/storage/src/storage.ts index 4dd65992d4..dcbd9723c9 100644 --- a/dev/storage/src/storage.ts +++ b/dev/storage/src/storage.ts @@ -14,19 +14,19 @@ // import type { Tx, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions } from '@anticrm/core' -import core, { ModelDb, TxDb, Hierarchy, DOMAIN_TX, TxFactory, ServerStorage } from '@anticrm/core' -import { Triggers } from '@anticrm/server-core' +import { ModelDb, TxDb, Hierarchy, DOMAIN_TX } from '@anticrm/core' +import type { DbAdapter } from '@anticrm/server-core' import * as txJson from './model.tx.json' -class DevStorage implements ServerStorage { +const txes = txJson as unknown as Tx[] + +class InMemoryAdapter implements DbAdapter { constructor ( private readonly hierarchy: Hierarchy, - private readonly triggers: Triggers, private readonly txdb: TxDb, private readonly modeldb: ModelDb - ) { - } + ) {} async findAll ( _class: Ref>, @@ -38,37 +38,23 @@ class DevStorage implements ServerStorage { return await this.modeldb.findAll(_class, query, options) } - async tx (tx: Tx): Promise { - if (tx.objectSpace === core.space.Model) { - this.hierarchy.tx(tx) - await this.triggers.tx(tx) - } + async tx (tx: Tx): Promise { await Promise.all([this.modeldb.tx(tx), this.txdb.tx(tx)]) - const derived = await this.triggers.apply(tx) - for (const tx of derived) { - await Promise.all([this.modeldb.tx(tx), this.txdb.tx(tx)]) + } + + async init (): Promise { + for (const tx of txes) { + await this.txdb.tx(tx) + await this.modeldb.tx(tx) } - return derived } } /** * @public */ -export async function createStorage (): Promise { - const txes = txJson as unknown as Tx[] - const hierarchy = new Hierarchy() - const triggers = new Triggers(new TxFactory(core.account.System)) - for (const tx of txes) { - hierarchy.tx(tx) - await triggers.tx(tx) - } - - const transactions = new TxDb(hierarchy) - const model = new ModelDb(hierarchy) - for (const tx of txes) { - await Promise.all([transactions.tx(tx), model.tx(tx)]) - } - - return new DevStorage(hierarchy, triggers, transactions, model) +export async function createInMemoryAdapter (hierarchy: Hierarchy, url: string, db: string): Promise<[DbAdapter, Tx[]]> { + const txdb = new TxDb(hierarchy) + const modeldb = new ModelDb(hierarchy) + return [new InMemoryAdapter(hierarchy, txdb, modeldb), txes] } diff --git a/server/core/src/index.ts b/server/core/src/index.ts index 8f75611bf2..fe85a86462 100644 --- a/server/core/src/index.ts +++ b/server/core/src/index.ts @@ -14,12 +14,11 @@ // limitations under the License. // -import type { Doc, Tx, TxCreateDoc, TxFactory, Ref, Class } from '@anticrm/core' +import type { Doc, Tx, TxCreateDoc, Ref, Class, ServerStorage, DocumentQuery, FindOptions, FindResult, Storage } from '@anticrm/core' +import core, { Hierarchy, TxFactory, ModelDb, DOMAIN_MODEL } from '@anticrm/core' import type { Resource, Plugin } from '@anticrm/platform' import { getResource, plugin } from '@anticrm/platform' -import core from '@anticrm/core' - /** * @public */ @@ -60,6 +59,79 @@ export class Triggers { } } +/** + * @public + */ +export interface DbAdapter extends Storage { + init: () => Promise +} + +/** + * @public + */ +export type DbAdapterFactory = (hierarchy: Hierarchy, url: string, db: string) => Promise<[DbAdapter, Tx[]]> + +class TServerStorage implements ServerStorage { + constructor ( + private readonly dbAdapter: Storage, + private readonly hierarchy: Hierarchy, + private readonly triggers: Triggers, + private readonly modeldb: ModelDb + ) { + } + + async findAll ( + clazz: Ref>, + query: DocumentQuery, + options?: FindOptions + ): Promise> { + const domain = this.hierarchy.getDomain(clazz) + console.log('findAll', clazz, domain, query) + if (domain === DOMAIN_MODEL) return await this.modeldb.findAll(clazz, query, options) + return await this.dbAdapter.findAll(clazz, query, options) + } + + async tx (tx: Tx): Promise { + if (tx.objectSpace === core.space.Model) { + this.hierarchy.tx(tx) + await this.modeldb.tx(tx) + await this.triggers.tx(tx) + return [] // we do not apply triggers on model changes? + } else { + await this.dbAdapter.tx(tx) + const derived = await this.triggers.apply(tx) + for (const tx of derived) { + await this.dbAdapter.tx(tx) // triggers does not generate changes to model objects? + } + return derived + } + } +} + +/** + * @public + */ +export async function createServerStorage (factory: DbAdapterFactory, url: string, db: string): Promise { + const hierarchy = new Hierarchy() + const model = new ModelDb(hierarchy) + const triggers = new Triggers(new TxFactory(core.account.System)) + + const [dbAdapter, txes] = await factory(hierarchy, url, db) + + for (const tx of txes) { + hierarchy.tx(tx) + } + + for (const tx of txes) { + await model.tx(tx) + await triggers.tx(tx) + } + + await dbAdapter.init() + + return new TServerStorage(dbAdapter, hierarchy, triggers, model) +} + /** * @public */ diff --git a/server/mongo/src/index.ts b/server/mongo/src/index.ts index 0cd297485c..2b3e75ae84 100644 --- a/server/mongo/src/index.ts +++ b/server/mongo/src/index.ts @@ -14,4 +14,4 @@ // limitations under the License. // -export { createStorage } from './storage' +export { createMongoAdapter } from './storage' diff --git a/server/mongo/src/storage.ts b/server/mongo/src/storage.ts index 4eda6f6318..66c09c70cc 100644 --- a/server/mongo/src/storage.ts +++ b/server/mongo/src/storage.ts @@ -13,9 +13,10 @@ // limitations under the License. // -import core, { Tx, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions, TxCreateDoc, ServerStorage, SortingOrder, DOMAIN_MODEL, TxProcessor, ModelDb, Hierarchy, DOMAIN_TX, TxFactory } from '@anticrm/core' +import type { Tx, Ref, Doc, Class, DocumentQuery, FindResult, FindOptions, TxCreateDoc } from '@anticrm/core' +import core, { TxProcessor, Hierarchy, DOMAIN_TX, SortingOrder } from '@anticrm/core' +import type { DbAdapter } from '@anticrm/server-core' -import { Triggers } from '@anticrm/server-core' import { MongoClient, Db, Filter, Document, Sort } from 'mongodb' function translateQuery (query: DocumentQuery): Filter { @@ -26,18 +27,19 @@ function translateDoc (doc: Doc): Document { return doc as Document } -class MongoTxProcessor extends TxProcessor { +class MongoAdapter extends TxProcessor implements DbAdapter { constructor ( private readonly db: Db, - private readonly hierarchy: Hierarchy, - private readonly modeldb: ModelDb + private readonly hierarchy: Hierarchy ) { super() } + async init (): Promise {} + override async tx (tx: Tx): Promise { const p1 = this.db.collection(DOMAIN_TX).insertOne(translateDoc(tx)) - const p2 = tx.objectSpace === core.space.Model ? this.modeldb.tx(tx) : super.tx(tx) + const p2 = super.tx(tx) await Promise.all([p1, p2]) } @@ -46,19 +48,6 @@ class MongoTxProcessor extends TxProcessor { const domain = this.hierarchy.getDomain(doc._class) await this.db.collection(domain).insertOne(translateDoc(doc)) } -} - -class MongoStorage implements ServerStorage { - private readonly txProcessor: TxProcessor - - constructor ( - private readonly db: Db, - private readonly hierarchy: Hierarchy, - private readonly triggers: Triggers, - private readonly modeldb: ModelDb - ) { - this.txProcessor = new MongoTxProcessor(db, hierarchy, modeldb) - } async findAll ( _class: Ref>, @@ -66,8 +55,6 @@ class MongoStorage implements ServerStorage { options?: FindOptions ): Promise> { const domain = this.hierarchy.getDomain(_class) - console.log('findAll', _class, domain, query) - if (domain === DOMAIN_MODEL) return await this.modeldb.findAll(_class, query, options) let cursor = this.db.collection(domain).find(translateQuery(query)) if (options !== null && options !== undefined) { if (options.sort !== undefined) { @@ -81,42 +68,15 @@ class MongoStorage implements ServerStorage { } return await cursor.toArray() } - - async tx (tx: Tx): Promise { - if (tx.objectSpace === core.space.Model) { - this.hierarchy.tx(tx) - await this.triggers.tx(tx) - } - await this.txProcessor.tx(tx) - const derived = await this.triggers.apply(tx) - for (const tx of derived) { - await this.txProcessor.tx(tx) - } - return derived - } } /** * @public */ -export async function createStorage (url: string, dbName: string): Promise { +export async function createMongoAdapter (hierarchy: Hierarchy, url: string, dbName: string): Promise<[DbAdapter, Tx[]]> { const client = new MongoClient(url) await client.connect() const db = client.db(dbName) - - const hierarchy = new Hierarchy() - const triggers = new Triggers(new TxFactory(core.account.System)) - const txes = await db.collection(DOMAIN_TX).find({ objectSpace: core.space.Model }).sort({ _id: 1 }).toArray() - for (const tx of txes) { - hierarchy.tx(tx) - await triggers.tx(tx) - } - - const model = new ModelDb(hierarchy) - for (const tx of txes) { - await model.tx(tx) - } - - return new MongoStorage(db, hierarchy, triggers, model) + return [new MongoAdapter(db, hierarchy), txes] } diff --git a/server/server/src/server.ts b/server/server/src/server.ts index 93e1c5011c..afdb59d908 100644 --- a/server/server/src/server.ts +++ b/server/server/src/server.ts @@ -15,7 +15,8 @@ // import { start as startJsonRpc } from '@anticrm/server-ws' -import { createStorage } from '@anticrm/mongo' +import { createMongoAdapter } from '@anticrm/mongo' +import { createServerStorage } from '@anticrm/server-core' import { addLocation } from '@anticrm/platform' import { serverChunterId } from '@anticrm/server-chunter' @@ -26,5 +27,5 @@ import { serverChunterId } from '@anticrm/server-chunter' export async function start (dbUrl: string, port: number, host?: string): Promise { addLocation(serverChunterId, () => import('@anticrm/server-chunter-resources')) - startJsonRpc((workspace: string) => createStorage(dbUrl, workspace), port, host) + startJsonRpc((workspace: string) => createServerStorage(createMongoAdapter, dbUrl, workspace), port, host) }