Home Reference Source

core/datastore/repositories/repository-provider.js

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

import { Client } from '../../client';
import { KinveyError } from '../../errors';
import { InmemoryOfflineRepository } from './offline-repositories';
import { NetworkRepository } from './network-repository';
import { StorageProvider } from './storage-provider';
import { ensureArray } from '../../utils';
import { PromiseQueueByKey } from '../utils';
import { MemoryKeyValuePersister } from '../persisters';
import { testSupportCollection } from './utils';

const inmemoryRepoBuilder = (queue) => {
  const persister = new MemoryKeyValuePersister();
  return new InmemoryOfflineRepository(persister, queue);
};

// all inmemory instances should share the queue
const queue = new PromiseQueueByKey();
let _chosenRepoPromise;

let _availableStorages = {
  [StorageProvider.Memory]: inmemoryRepoBuilder
};

function _getRepoType() {
  return Client.sharedInstance().storage;
}

function _testRepoSupport(repo) {
  return repo.create(testSupportCollection, { _id: '1' });
}

function _getRepoForStorageProvider(storageProvider) {
  const repoBuilder = _availableStorages[storageProvider];
  if (!repoBuilder) {
    const errMsg = `The requested storage provider "${storageProvider}" is not available in this environment`;
    throw new KinveyError(errMsg);
  }
  return repoBuilder(queue);
}

/**
 * Selects the first repo from the priority list,
 * which returns a resolved promise for the support test
 * @param {string[]} storagePrecedence An array of enum values, sorted by priority
 * @returns {Promise<OfflineRepository>}
 */
function _getFirstSupportedRepo(storagePrecedence) {
  return storagePrecedence.reduce((result, storageProvider) => {
    return result.catch(() => {
      const repo = _getRepoForStorageProvider(storageProvider);
      return _testRepoSupport(repo)
        .then(() => repo);
    });
  }, Promise.reject());
}

function _chooseOfflineRepo() {
  const storagePrecedence = ensureArray(_getRepoType());

  return _getFirstSupportedRepo(storagePrecedence)
    .catch(() => {
      const errMsg = 'None of the selected storage providers are supported in this environment.';
      return Promise.reject(new KinveyError(errMsg));
    });
}

function getOfflineRepository() {
  if (!_chosenRepoPromise) {
    _chosenRepoPromise = _chooseOfflineRepo();
  }
  return _chosenRepoPromise;
}

function getNetworkRepository() {
  return new NetworkRepository();
}

function setSupportedRepoBuilders(repos) {
  _availableStorages = repos;
}

function getSupportedStorages() {
  return keys(_availableStorages);
}

/**
 * @private
 */
export const repositoryProvider = {
  getNetworkRepository,
  getOfflineRepository,
  setSupportedRepoBuilders,
  getSupportedStorages
};