import type { ChangeEvent } from 'event-reduce-js'; import type { RxChangeEvent } from './rx-change-event.d.ts'; import type { RxDocumentMeta } from './rx-document.d.ts'; import type { RxStorageWriteError } from './rx-error.d.ts'; import type { RxJsonSchema } from './rx-schema.d.ts'; import type { Override } from './util.d.ts'; /** * The document data how it comes out of the storage instance. * Contains all meta data like revision, attachments and deleted-flag. */ export type RxDocumentData = T & { /** * As other NoSQL databases, * RxDB also assumes that no data is finally deleted. * Instead the documents are stored with _deleted: true * which means they will not be returned at queries. */ _deleted: boolean; /** * The attachments meta data is stored besides to document. */ _attachments: { [attachmentId: string]: RxAttachmentData; }; /** * Contains a revision which is concatenated with a [height: number]-[identifier: string] * like: '1-3hl4kj3l4kgj34g34glk'. * The revision is used to detect write conflicts and have a document history. * Revisions behave similar to couchdb revisions: * @link https://docs.couchdb.org/en/stable/replication/conflicts.html#revision-tree * When writing a document, you must send the correct revision in the previous-field * to make sure that you do not cause a write conflict. * The revision of the 'new' document-field must be created, for example via util.createRevision(). * Any revision that matches the [height]-[hash] format can be used. */ _rev: string; _meta: RxDocumentMeta; }; export type RxDocumentDataById = { [documentId: string]: RxDocumentData; }; /** * The document data how it is send to the * storage instance to save it. */ // We & T here instead of in RxDocumentData to preserver indexability by keyof T which the Override breaks export type RxDocumentWriteData = T & Override, { _attachments: { /** * To create a new attachment, set the write data * To delete an attachment, leave it out on the _attachments property. * To change an attachment, set the new write data. * To not touch an attachment, just send the stub again * which came out of the storage instance. */ [attachmentId: string]: RxAttachmentData | RxAttachmentWriteData; }; }>; export type WithDeleted = DocType & { _deleted: boolean; }; export type WithDeletedAndAttachments = DocType & { _deleted: boolean; /** * Here the _attachments might exist * or might not, depending one the use case. */ _attachments?: { [attachmentId: string]: RxAttachmentData | RxAttachmentWriteData; }; }; /** * Send to the bulkWrite() method of a storage instance. */ export type BulkWriteRow = { /** * The current document state in the storage engine, * assumed by the application. * Undefined if the document is a new insert. * Notice that we send the full document data as 'previous', not just the revision. * The reason is that to get the previous revision you anyway have to get the full * previous document and so it is easier to just send it all to the storage instance. * This will later allow us to use something different then the _rev key for conflict detection * when we implement other storage instances. */ previous?: RxDocumentData; /** * The new document data to be stored in the storage instance. */ document: RxDocumentWriteData; }; export type BulkWriteRowById = { [documentId: string]: BulkWriteRow; }; /** * After the RxStorage has processed all rows, * we have this to work with afterwards. */ export type BulkWriteRowProcessed = BulkWriteRow & { document: RxDocumentData; }; export type RxAttachmentData = { /** * Size of the attachments data */ length: number; /** * Content type like 'plain/text' */ type: string; /** * The hash of the attachments content. * It is calculated by RxDB, and send to the storage. * The only guarantee is that the digest will change when the attachments data changes. * @link https://github.com/pouchdb/pouchdb/issues/3156#issuecomment-66831010 * @link https://github.com/pubkey/rxdb/pull/4107 */ digest: string; }; /** * Data which is needed for new attachments * that are send from RxDB to the RxStorage implementation. */ export type RxAttachmentWriteData = RxAttachmentData & { /** * The data of the attachment as a Blob. * Blob is the canonical internal type because: * - Attachments are blob-like things (images, videos, PDFs) * - Blob is immutable (safe, no accidental mutation) * - Blob.type carries MIME type metadata * - Blob.size gives length synchronously * - Blob is structured-cloneable (works with Worker/Electron postMessage) * - IndexedDB stores Blobs efficiently (some engines use external blob storage) * * Conversion to ArrayBuffer only happens at boundaries that require it: * encryption (Web Crypto), compression (CompressionStream), digest hashing, * and WebSocket serialization. * * Encryption/compression run in the wrapRxStorageInstance layer OUTSIDE * storage transactions, so Blob does not extend transaction lifetimes. */ data: Blob; }; /** * The returned data from RxStorageInstance.bulkWrite() * For better performance, we do NOT use an indexed object, * but only plain arrays. Because most of the time * RxDB anyway only need the array data and we can save performance * by not indexing the results. * * We do not longer return the written documents. We only return the errors. * This is because we construct the written docs array from the input+errors anyway * and transferring large amounts of data has bad performance when the storage * is running in a different realm like a WebWorker or remote. */ export type RxStorageBulkWriteResponse = { /** * contains all errored writes. */ error: RxStorageWriteError[]; }; /** * We return a complex object instead of a single array * so we are able to add additional fields in the future. */ export type RxStorageQueryResult = { // the found documents, sort order is important. documents: RxDocumentData[]; }; export type RxStorageCountResult = { count: number; /** * Returns the mode which was used by the storage * to count the documents. * If this returns 'slow', RxDB will throw by default * if 'allowSlowCount' is not set. */ mode: 'fast' | 'slow'; }; export type RxStorageInstanceCreationParams = { /** * A string to uniquely identify the instance of the JavaScript object * of the RxDatabase where this RxStorageInstance belongs to. * In most cases you would use RxDatabase.token here. * * This is used so that we can add caching or reuse stuff that belongs to the same RxDatabase. * For example the BroadcastChannel that is used for event propagation between multiple browser tabs * is cached by this token. * * In theory we could just use the databaseName for that. But to make it easier in unit tests * to simulate cross-tab usage, we cannot assume that the databaseName is unique in a single * JavaScript process. Therefore we use the instance token instead. */ databaseInstanceToken: string; databaseName: string; collectionName: string; schema: RxJsonSchema>; options: InstanceCreationOptions; /** * If multiInstance is true, there can be more * then one instance of the database, for example * when multiple browser tabs exist or more then one Node.js * process relies on the same storage. */ multiInstance: boolean; /** * Typed as `any` because different encryption plugins * may use passwords that are not strings. */ password?: string | any; /** * Some storages can do additional checks * that are performance expensive * and should only be done in dev-mode. */ devMode: boolean; }; export type ChangeStreamOptions = { /** * Sequence number of the first event to start with. * If you want to get all ongoing events, * first get the latest sequence number and input it here. * * Optional on changeStream, * will start from the newest sequence. */ startSequence?: number; /** * limits the amount of results */ limit?: number; }; /** * In the past we handles each RxChangeEvent by its own. * But it has been shown that this take way more performance then needed, * especially when the events get transferred over a data layer * like with WebWorkers or the BroadcastChannel. * So we now process events as bulks internally. */ export type EventBulk = { /** * Unique id of the bulk, * used to detect duplicate bulks * that have already been processed. */ id: string; events: EventType[]; /** * Required for replication. * Passing this checkpoint into getChangedDocumentsSince() * must return all items that have been modified AFTER this write event. */ checkpoint: CheckpointType; /** * The context that was given at the call to bulkWrite() * that caused this EventBulk. */ context: string; }; export type ChangeStreamEvent = ChangeEvent> & { /** * An integer that is increasing * and unique per event. * Can be used to sort events or get information * about how many events there are. */ sequence: number; /** * The value of the primary key * of the changed document */ id: string; }; export type RxStorageChangeEvent = Omit, 'isLocal' | 'collectionName'>; /** * An example for how a RxStorage checkpoint can look like. * NOTICE: Not all implementations use this type. */ export type RxStorageDefaultCheckpoint = { id: string; lwt: number; }; export type CategorizeBulkWriteRowsOutput = { bulkInsertDocs: BulkWriteRowProcessed[]; bulkUpdateDocs: BulkWriteRowProcessed[]; errors: RxStorageWriteError[]; eventBulk: EventBulk>, any>; attachmentsAdd: { documentId: string; attachmentId: string; attachmentData: RxAttachmentWriteData; digest: string; }[]; attachmentsRemove: { documentId: string; attachmentId: string; digest: string; }[]; attachmentsUpdate: { documentId: string; attachmentId: string; attachmentData: RxAttachmentWriteData; digest: string; }[]; /** * Contains the non-error document row that * has the newest _meta.lwt time. * Empty if no successful write exists. */ newestRow?: BulkWriteRowProcessed; };