repo_description: A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
repo_topics: angular browser-database couchdb crdt database firebase graphql indexeddb ionic local-first localstorage nodejs nosql postgres pouchdb react-native realtime realtime-database rxdb sqlite
code: import type {
      BulkWriteRow,
      EventBulk,
      RxDocumentData,
      RxStorageBulkWriteResponse,
      RxStorageChangeEvent,
      RxStorageCountResult,
      RxStorageInstanceCreationParams,
      RxStorageQueryResult
  } from './rx-storage.ts';
  import type {
      MangoQuerySelector,
      MangoQuerySortPart,
      RxJsonSchema,
      RxQueryPlan
  } from './index.d.ts';
  import type {
      Observable
  } from 'rxjs';
  
  /**
   * RxStorage
   * This is an interface that abstracts the storage engine.
   * This allows us to use RxDB with different storage engines.
   *
   * @link https://rxdb.info/rx-storage.html
   * @link https://github.com/pubkey/rxdb/issues/1636
   */
  
  /**
   * A RxStorage is a module that acts
   * as a factory that can create multiple RxStorageInstance
   * objects.
   *
   * All data inputs and outputs of a StorageInstance must be structured-cloneable.
   * Document data must be plain JSON objects. Attachment data uses Blob.
   * Do not use Map, Set or anything else that is not structured-cloneable.
   * This will ensure that the storage can exchange data
   * when it is a WebWorker or a WASM process or data is send via BroadcastChannel.
   * The only exception is the WebSocket transport, which serializes at its boundary.
   */
  export interface RxStorage<Internals, InstanceCreationOptions> {
      /**
       * name of the storage engine
       * used to detect if plugins do not work so we can throw proper errors.
       */
      readonly name: string;
  
      /**
       * RxDB version is part of the storage
       * so we can have fallbacks and stuff when
       * multiple storages with different version are in use
       * like in the storage migration plugin.
       */
      readonly rxdbVersion: string;
  
      /**
       * Creates a storage instance
       * that can contain the NoSQL documents of a collection.
       */
      createStorageInstance<RxDocType>(
          params: RxStorageInstanceCreationParams<RxDocType, InstanceCreationOptions>
      ): Promise<RxStorageInstance<RxDocType, Internals, InstanceCreationOptions>>;
  }
  
  
  /**
   * User provided mango queries will be filled up by RxDB via normalizeMangoQuery()
   * so we do not have to do many if-field-exist tests in the internals.
   */
  export type FilledMangoQuery<RxDocType> = {
      /**
       * The selector is required here.
       */
      selector: MangoQuerySelector<RxDocumentData<RxDocType>>;
  
      /**
       * In contrast to the user-provided MangoQuery,
       * the sorting is required here because
       * RxDB has to ensure that the primary key is always
       * part of the sort params.
       */
      sort: MangoQuerySortPart<RxDocumentData<RxDocType>>[];
  
      /**
       * In the normalized mango query,
       * the index must always be a string[],
       * never just a string.
       * This makes it easier to use the query because
       * we do not have to do an array check.
       */
      index?: string[];
  
      /**
       * Skip must be set which defaults to 0
       */
      skip: number;
  
      limit?: number;
  };
  
  
  /**
   * Before sending a query to the storageInstance.query()
   * we run it through the query planner and do some normalization
   * stuff. Notice that the queryPlan is a hint for the storage and
   * it is not required to use it when running queries. Some storages
   * might use their own query planning instead.
   */
  export type PreparedQuery<RxDocType> = {
      // original query from the input
      query: FilledMangoQuery<RxDocType>;
      queryPlan: RxQueryPlan;
  };
  
  export interface RxStorageInstance<
      /**
       * The type of the documents that can be stored in this instance.
       * All documents in an instance must comply to the same schema.
       * Also all documents are RxDocumentData with the meta properties like
       * _deleted or _rev etc.
       */
      RxDocType,
      Internals,
      InstanceCreationOptions,
      CheckpointType = any
  > {
      readonly databaseName: string;
      /**
       * Returns the internal data that is used by the storage engine.
       */
      readonly internals: Readonly<Internals>;
      readonly options: Readonly<InstanceCreationOptions>;
      /**
       * The schema that defines the documents that are stored in this instance.
       * Notice that the schema must be enhanced with the meta properties like
       * _meta, _rev and _deleted etc. which are added by fillWithDefaultSettings()
       */
      readonly schema: Readonly<RxJsonSchema<RxDocumentData<RxDocType>>>;
      readonly collectionName: string;
  
      /**
       * (Optional) reference to the underlying persistent storage instance.
       * If set, things like replication will run on that storageInstance instead of the parent.
       * This is mostly used in things like the memory-synced storage where we want to
       * run replications and migrations on the persistent storage instead of the in-memory storage.
       *
       * Having this is the least hacky option. The only other option would be to toggle all calls to the
       * storageInstance by checking the givent context-string. But this would make it impossible
       * to run a replication on the parentStorage itself.
       */
      readonly underlyingPersistentStorage?: RxStorageInstance<RxDocType, any, any, any>;
  
      /**
       * Writes multiple documents to the storage instance.
       * The write for each single document is atomic, there
       * is no transaction around all documents.
       * The written documents must be the newest revision of that documents data.
       * If the previous document is not the current newest revision, a conflict error
       * must be returned.
       * It must be possible that some document writes succeed
       * and others error. We need this to have a similar behavior as most NoSQL databases.
       */
      bulkWrite(
          documentWrites: BulkWriteRow<RxDocType>[],
          /**
           * Context will be used in all
           * changeStream()-events that are emitted as a result
           * of that bulkWrite() operation.
           * Used in plugins so that we can detect that event X
           * comes from operation Y.
           */
          context: string
      ): Promise<RxStorageBulkWriteResponse<RxDocType>>;
  
      /**
       * Get Multiple documents by their primary value.
       * This must also return deleted documents.
       */
      findDocumentsById(
          /**
           * List of primary values
           * of the documents to find.
           */
          ids: string[],
          /**
           * If set to true, deleted documents will also be returned.
           */
          withDeleted: boolean
  
      ): Promise<
          /**
           * For better performance, we return an array
           * instead of an indexed object because most consumers
           * of this anyway have to fill a Map() instance or
           * even do only need the list at all.
           */
          RxDocumentData<RxDocType>[]
      >;
  
      /**
       * Runs a NoSQL 'mango' query over the storage
       * and returns the found documents data.
       * Having all storage instances behave similar
       * is likely the most difficult thing when creating a new
       * rx-storage implementation.
       */
      query(
          preparedQuery: PreparedQuery<RxDocType>
      ): Promise<RxStorageQueryResult<RxDocType>>;
  
      /**
       * Returns the amount of non-deleted documents
       * that match the given query.
       * Must return the same amount as if the equivalent query()
       * was run and the result array length measured.
       * For example with .count({limit: 3}) must return the same
       * as .query({limit: 3}).documents.length .
       */
      count(
          preparedQuery: PreparedQuery<RxDocType>
      ): Promise<RxStorageCountResult>;
  
      /**
       * Returns the data of a single attachment as a Blob.
       */
      getAttachmentData(
          documentId: string,
          attachmentId: string,
          digest: string
      ): Promise<Blob>;
  
      /**
       * Returns the current (not the old!) data of all documents that have been changed AFTER the given checkpoint.
       * If the returned array does not reach the limit, it can be assumed that the "end" is reached, when paginating over the changes.
       * Also returns a new checkpoint for each document which can be used to continue with the pagination from that change on.
       * Must never return the same document multiple times in the same call operation.
       * This is used by RxDB to known what has changed since X so these docs can be handled by the backup or the replication
       * plugin.
       *
       * Important: This method is optional. If not defined,
       * RxDB will manually run a query and use the last returned document
       * for checkpointing. In  the future we might even remove this method completely
       * and let RxDB do the work instead of the RxStorage.
       */
      getChangedDocumentsSince?(
          limit: number,
          /**
           * The checkpoint from with to start
           * when the events are sorted in time.
           * If we want to start from the beginning,
           * undefined is used as a checkpoint.
           */
          checkpoint?: CheckpointType
      ): Promise<{
          documents: RxDocumentData<RxDocType>[];
          /**
           * The checkpoint contains data so that another
           * call to getChangedDocumentsSince() will continue
           * from exactly the last document that was returned before.
           */
          checkpoint: CheckpointType;
      }>;
  
      /**
       * Returns an ongoing stream
       * of all changes that happen to the
       * storage instance.
       * Do not forget to unsubscribe.
       *
       * If the RxStorage support multi-instance,
       * and the storage is persistent,
       * then the emitted changes of one RxStorageInstance
       * must be also emitted to other instances with the same databaseName+collectionName.
       * See ./rx-storage-multiinstance.ts
       */
      changeStream(): Observable<EventBulk<RxStorageChangeEvent<RxDocType>, CheckpointType>>;
  
      /**
       * Runs a cleanup that removes all tompstones
       * of documents that have _deleted set to true
       * to free up disc space.
       *
       * Returns true if all cleanable documents have been removed.
       * Returns false if there are more documents to be cleaned up,
       * but not all have been purged because that would block the storage for too long.
       */
      cleanup(
          /**
           * The minimum time in milliseconds
           * of how long a document must have been deleted
           * until it is purged by the cleanup.
           */
          minimumDeletedTime: number
      ): Promise<
          /**
           * True if all docs cleaned up,
           * false if there are more docs to clean up
           */
          boolean
      >;
  
      /**
       * Closes the storage instance so it cannot be used
       * anymore and should clear all memory.
       * The returned promise must resolve when everything is cleaned up.
       */
      close(): Promise<void>;
  
      /**
       * Remove the database and
       * deletes all of its data.
       */
      remove(): Promise<void>;
  }
  