Home Reference Source

core/datastore/processors/offline-data-processor.js

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

import { OperationType } from '../operations';
import { repositoryProvider } from '../repositories';
import { DataProcessor } from './data-processor';
import { generateEntityId, isEmpty } from '../utils';
import { ensureArray, isDefined } from '../../utils';
import { clearQueryCache } from '../querycache';

// imported for typings
// import { SyncManager } from '../sync';

/**
 * @private
 */
export class OfflineDataProcessor extends DataProcessor {
  /** @type {SyncManager} */
  _syncManager;

  constructor(syncManager) {
    super();
    this._syncManager = syncManager;
  }

  process(operation, options) {
    if (operation.type === OperationType.Clear) {
      return this._processClear(operation.collection, operation.query, options);
    }
    return super.process(operation, options);
  }

  // protected methods

  _getRepository() {
    if (!this._repoPromise) {
      this._repoPromise = repositoryProvider.getOfflineRepository();
    }
    return this._repoPromise;
  }

  _deleteEntityAndHandleOfflineState(collection, entity, options) {
    return super._processDeleteById(collection, entity._id, options)
      .then((deletedCount) => {
        if (!deletedCount) {
          return deletedCount;
        }
        return this._syncManager.addDeleteEvent(collection, entity)
          .then(() => deletedCount);
      });
  }

  _deleteEntitiesAndHandleOfflineState(collection, entities, deleteQuery, options) {
    return super._processDelete(collection, deleteQuery, options)
      .then((delCount) => {
        return this._syncManager.addDeleteEvent(collection, entities)
          .then(() => delCount);
      });
  }

  _processUpdate(collection, data, options) {
    return super._processUpdate(collection, data, options)
      .then((updatedItems) => {
        return this._syncManager.addUpdateEvent(collection, updatedItems)
          .then(() => updatedItems);
      });
  }

  _processClear(collection, query, options) {
    return this._syncManager.clearSync(collection, query)
      .then(() => clearQueryCache(collection))
      .then(() => this._getRepository())
      .then(repo => repo.delete(collection, query, options));
  }

  _processDelete(collection, query, options) {
    return this._getRepository()
      .then(repo => repo.read(collection, query, options))
      .then((entities) => {
        if (isEmpty(entities)) {
          return Promise.resolve(0);
        }
        return this._deleteEntitiesAndHandleOfflineState(collection, entities, query, options);
      });
  }

  _processCreate(collection, data, options) {
    data = this._addMetadataToEntities(data);
    return super._processCreate(collection, data, options)
      .then((createdItems) => {
        return this._syncManager.addCreateEvent(collection, createdItems)
          .then(() => createdItems);
      });
  }

  _processDeleteById(collection, entityId, options) {
    return this._getRepository()
      .then(repo => repo.readById(collection, entityId))
      .then(entity => this._deleteEntityAndHandleOfflineState(collection, entity, options));
  }

  // private methods

  _addOfflineMetadataToEntity(entity) {
    const kmd = entity._kmd || {};
    kmd.local = true;
    entity._kmd = kmd;
    entity._id = generateEntityId();
  }

  _addMetadataToEntities(data) {
    const siSingle = !Array.isArray(data);
    const arr = ensureArray(data).map((entity) => {
      if (!isDefined(entity._id)) {
        entity = clone(entity);
        this._addOfflineMetadataToEntity(entity);
      }
      return entity;
    });
    return siSingle ? arr[0] : arr;
  }
}