Home Reference Source

core/datastore/cachestore.js

import { Promise } from 'es6-promise';
import assign from 'lodash/assign';

import { isDefined } from '../utils';
import { NetworkStore } from './networkstore';

import { OperationType } from './operations';
import { processorFactory } from './processors';
import { syncManagerProvider } from './sync';
import { formTaggedCollectionName, getEntitiesPendingPushError } from './utils';

/**
 * @private
 * The CacheStore class is used to find, create, update, remove, count and group entities. Entities are stored
 * in a cache and synced with the backend.
 */
export class CacheStore extends NetworkStore {
  constructor(collection, processor, options = {}) {
    collection = formTaggedCollectionName(collection, options.tag);
    const proc = processor || processorFactory.getCacheOfflineDataProcessor();
    super(collection, proc, options);

    /**
     * @type {number|undefined}
     */
    this.ttl = options.ttl || undefined;
    this.syncManager = syncManagerProvider.getSyncManager();

    /**
     * @type {boolean}
     */
    this.useDeltaSet = options.useDeltaSet === true;
  }

  /**
   * Remove a single entity in the data store by id.
   *
   * @param   {string}                id                               Entity by id to remove.
   * @param   {Object}                [options]                        Options
   * @param   {Properties}            [options.properties]             Custom properties to send with
   *                                                                   the request.
   * @param   {Number}                [options.timeout]                Timeout for the request.
   * @return  {Promise}                                                Promise.
   */
  removeById(id, options = {}) {
    if (!isDefined(id)) {
      return Promise.resolve({ count: 0 });
    }

    return super.removeById(id, options);
  }

  /**
   * Remove all entities in the data store that are stored locally.
   *
   * @param   {Query}                 [query]                           Query used to filter entities.
   * @param   {Object}                [options]                         Options
   * @param   {Properties}            [options.properties]              Custom properties to send with
   *                                                                    the request.
   * @param   {Number}                [options.timeout]                 Timeout for the request.
   * @return  {Promise}                                                 Promise.
   */
  clear(query, options = {}) {
    const errPromise = this._validateQuery(query);
    if (errPromise) {
      return errPromise;
    }

    const operation = this._buildOperationObject(OperationType.Clear, query);
    return this._executeOperation(operation, options)
      .then(count => ({ count }));
  }

  /**
   * Count the number of entities waiting to be pushed to the network. A promise will be
   * returned with the count of entities or rejected with an error.
   *
   * @param   {Query}                 [query]                                   Query to count a subset of entities.
   * @return  {Promise}                                                         Promise
   */
  pendingSyncCount(query) {
    return this.syncManager.getSyncItemCountByEntityQuery(this.collection, query);
  }

  pendingSyncEntities(query) {
    return this.syncManager.getSyncEntities(this.collection, query);
  }

  /**
   * Push sync items for the data store to the network. A promise will be returned that will be
   * resolved with the result of the push or rejected with an error.
   *
   * @param   {Query}                 [query]                                   Query to push a subset of items.
   * @param   {Object}                options                                   Options
   * @param   {Properties}            [options.properties]                      Custom properties to send with
   *                                                                            the request.
   * @param   {Number}                [options.timeout]                         Timeout for the request.
   * @return  {Promise}                                                         Promise
   */
  push(query, options) {
    return this.syncManager.push(this.collection, query, options);
  }

  /**
   * Pull items for the data store from the network to your local cache. A promise will be
   * returned that will be resolved with the result of the pull or rejected with an error.
   *
   * IMPORTANT: This method is not intended to be used to make concurrent requests.
   * If you wish to pull multiple pages, please use the autoPagination option
   *
   * @param   {Query}                 [query]                                   Query to pull a subset of items.
   * @param   {Object}                options                                   Options
   * @param   {Properties}            [options.properties]                      Custom properties to send with
   *                                                                            the request.
   * @param   {Number}                [options.timeout]                         Timeout for the request.
   * @return  {Promise.<number>}                                                Promise
   */
  pull(query, options = {}) {
    options = assign({ useDeltaSet: this.useDeltaSet }, options);
    return this.syncManager.getSyncItemCountByEntityQuery(this.collection, query)
      .then((count) => {
        if (count > 0) {
          const err = getEntitiesPendingPushError(count, 'fetch the entities');
          return Promise.reject(err);
        }
        return Promise.resolve();
      })
      .then(() => this.syncManager.pull(this.collection, query, options));
  }

  /**
   * Sync items for the data store. This will push pending sync items first and then
   * pull items from the network into your local cache. A promise will be
   * returned that will be resolved with the result of the pull or rejected with an error.
   *
   * @param   {Query}                 [query]                                   Query to pull a subset of items.
   * @param   {Object}                options                                   Options
   * @param   {Properties}            [options.properties]                      Custom properties to send with the request.
   * @param   {Number}                [options.timeout]                         Timeout for the request.
   * @return  {Promise.<{push: [], pull: number}>}                              Promise
   */
  sync(query, options) {
    options = assign({ useDeltaSet: this.useDeltaSet }, options);
    const result = {};
    return this.push(query, options)
      .then((pushResult) => {
        result.push = pushResult;
        return this.pull(query, options);
      })
      .then((pullResult) => {
        result.pull = pullResult;
        return result;
      });
  }

  clearSync(query) {
    return this.syncManager.clearSync(this.collection, query);
  }
}