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 { mapDocumentsDataToCacheDocs } from './doc-cache.ts';
  import { overwriteGetterForCaching } from './plugins/utils/index.ts';
  import { newRxError } from './rx-error.ts';
  import { RxQueryBase } from './rx-query.ts';
  import type {
      RxDocument,
      RxDocumentData
  } from './types';
  
  /**
   * Counter to create unique result IDs cheaply.
   * Used instead of now() to avoid expensive timestamp computation
   * when we only need uniqueness for change detection.
   */
  let _resultIdCounter = 0;
  
  /**
   * RxDB needs the query results in multiple formats.
   * Sometimes as a Map or an array with only the documentData.
   * For better performance we work with this class
   * that initializes stuff lazily so that
   * we can directly work with the query results after RxQuery.exec()
   */
  export class RxQuerySingleResult<RxDocType> {
      /**
       * Unique identifier for this result state.
       * Used to determine if the result set has changed since X
       * so that we do not emit the same result multiple times on subscription.
       */
      public readonly time = ++_resultIdCounter;
      public readonly documents: RxDocument<RxDocType>[];
      constructor(
          public readonly query: RxQueryBase<RxDocType, unknown>,
          // only used internally, do not use outside, use this.docsData instead
          docsDataFromStorageInstance: RxDocumentData<RxDocType>[],
          // can be overwritten for count-queries
          public readonly count: number,
      ) {
          /**
           * @performance Skip document mapping for count queries
           * since they only need the count number and pass an empty array.
           */
          if (query.op === 'count') {
              this.documents = [];
          } else {
              this.documents = mapDocumentsDataToCacheDocs<RxDocType, any>(this.query.collection._docCache, docsDataFromStorageInstance);
          }
      }
  
  
      /**
       * Instead of using the newResultData in the result cache,
       * we directly use the objects that are stored in the RxDocument
       * to ensure we do not store the same data twice and fill up the memory.
       * @overwrites itself with the actual value
       */
      get docsData(): RxDocumentData<RxDocType>[] {
          return overwriteGetterForCaching(
              this,
              'docsData',
              this.documents.map(d => d._data)
          );
      }
  
  
      // A key->document map, used in the event reduce optimization.
      get docsDataMap(): Map<string, RxDocumentData<RxDocType>> {
          const map = new Map<string, RxDocumentData<RxDocType>>();
          this.documents.forEach(d => {
              map.set(d.primary, d._data);
          });
          return overwriteGetterForCaching(
              this,
              'docsDataMap',
              map
          );
      }
  
      get docsMap(): Map<string, RxDocument<RxDocType>> {
          const map = new Map<string, RxDocument<RxDocType>>();
          const documents = this.documents;
          for (let i = 0; i < documents.length; i++) {
              const doc = documents[i];
              map.set(doc.primary, doc);
          }
          return overwriteGetterForCaching(
              this,
              'docsMap',
              map
          );
      }
  
      getValue(throwIfMissing?: boolean) {
          const op = this.query.op;
          if (op === 'count') {
              return this.count;
          } else if (op === 'findOne') {
              // findOne()-queries emit RxDocument or null
              const doc = this.documents.length === 0 ? null : this.documents[0];
              if (!doc && throwIfMissing) {
                  throw newRxError('QU10', {
                      collection: this.query.collection.name,
                      query: this.query.mangoQuery,
                      op
                  });
              } else {
                  return doc;
              }
          } else if (op === 'findByIds') {
              return this.docsMap;
          } else {
              // find()-queries emit RxDocument[]
              // Flat copy the array so it won't matter if the user modifies it.
              return this.documents.slice(0);
          }
      }
  }
  