import { filter } from 'rxjs/operators'; import { DocumentCache } from 'nxdb-old/src/doc-cache'; import { IncrementalWriteQueue } from 'nxdb-old/src/incremental-write'; import { newRxError } from 'nxdb-old/src/rx-error'; import { fillWithDefaultSettings } from 'nxdb-old/src/rx-schema-helper'; import { getWrappedStorageInstance, storageChangeEventToRxChangeEvent } from 'nxdb-old/src/rx-storage-helper'; import type { LocalDocumentParent, LocalDocumentState, RxChangeEvent, RxChangeEventBulk, RxDatabase, RxDocumentData, RxJsonSchema, RxLocalDocumentData, RxStorage } from 'nxdb-old/src/types'; import { randomCouchString } from 'nxdb-old/src/plugins/utils'; import { createRxLocalDocument } from 'nxdb-old/src/plugins/local-documents/rx-local-document'; import { overwritable } from 'nxdb-old/src/overwritable'; export const LOCAL_DOC_STATE_BY_PARENT: WeakMap> = new WeakMap(); export const LOCAL_DOC_STATE_BY_PARENT_RESOLVED: WeakMap = new WeakMap(); export function createLocalDocStateByParent(parent: LocalDocumentParent): void { const database: RxDatabase = parent.database ? parent.database : parent as any; const collectionName = parent.database ? parent.name : ''; const statePromise = (async () => { let storageInstance = await createLocalDocumentStorageInstance( database.token, database.storage, database.name, collectionName, database.instanceCreationOptions, database.multiInstance ); storageInstance = getWrappedStorageInstance( database, storageInstance, RX_LOCAL_DOCUMENT_SCHEMA ); const docCache = new DocumentCache( 'id', parent.$.pipe( filter(cE => (cE as RxChangeEvent).isLocal) ), docData => createRxLocalDocument(docData, parent) as any ); const incrementalWriteQueue = new IncrementalWriteQueue( storageInstance, 'id', () => { }, () => { } ); /** * Emit the changestream into the collections change stream */ const databaseStorageToken = await database.storageToken; const subLocalDocs = storageInstance.changeStream().subscribe(eventBulk => { const changeEventBulk: RxChangeEventBulk = { id: eventBulk.id, internal: false, collectionName: parent.database ? parent.name : undefined, storageToken: databaseStorageToken, events: eventBulk.events.map(ev => storageChangeEventToRxChangeEvent( true, ev, parent.database ? parent as any : undefined )), databaseToken: database.token, checkpoint: eventBulk.checkpoint, context: eventBulk.context }; database.$emit(changeEventBulk); }); parent._subs.push(subLocalDocs); const state = { database, parent, storageInstance, docCache, incrementalWriteQueue }; LOCAL_DOC_STATE_BY_PARENT_RESOLVED.set(parent, state); return state; })(); LOCAL_DOC_STATE_BY_PARENT.set(parent, statePromise); } export function getLocalDocStateByParent(parent: LocalDocumentParent): Promise { const statePromise = LOCAL_DOC_STATE_BY_PARENT.get(parent); if (!statePromise) { const database: RxDatabase = parent.database ? parent.database : parent as any; const collectionName = parent.database ? parent.name : ''; throw newRxError('LD8', { database: database.name, collection: collectionName }); } return statePromise; } export function createLocalDocumentStorageInstance( databaseInstanceToken: string, storage: RxStorage, databaseName: string, collectionName: string, instanceCreationOptions: any, multiInstance: boolean ) { return storage.createStorageInstance({ databaseInstanceToken, databaseName: databaseName, /** * Use a different collection name for the local documents instance * so that the local docs can be kept while deleting the normal instance * after migration. */ collectionName: getCollectionLocalInstanceName(collectionName), schema: RX_LOCAL_DOCUMENT_SCHEMA, options: instanceCreationOptions, multiInstance, devMode: overwritable.isDevMode() }); } export function closeStateByParent(parent: LocalDocumentParent) { const statePromise = LOCAL_DOC_STATE_BY_PARENT.get(parent); if (statePromise) { LOCAL_DOC_STATE_BY_PARENT.delete(parent); return statePromise.then(state => state.storageInstance.close()); } } export async function removeLocalDocumentsStorageInstance( storage: RxStorage, databaseName: string, collectionName: string ) { const databaseInstanceToken = randomCouchString(10); const storageInstance = await createLocalDocumentStorageInstance( databaseInstanceToken, storage, databaseName, collectionName, {}, false ); await storageInstance.remove(); } export function getCollectionLocalInstanceName(collectionName: string): string { return 'plugin-local-documents-' + collectionName; } export const RX_LOCAL_DOCUMENT_SCHEMA: RxJsonSchema> = fillWithDefaultSettings({ title: 'RxLocalDocument', version: 0, primaryKey: 'id', type: 'object', properties: { id: { type: 'string', maxLength: 128 }, data: { type: 'object', additionalProperties: true } }, required: [ 'id', 'data' ] });