client/src/sagas/BaseSyncronizer.js
author ymh <ymh.work@gmail.com>
Mon, 08 Oct 2018 18:35:47 +0200
changeset 168 ea92f4fe783d
parent 129 d48946d164c6
permissions -rw-r--r--
- move SlateEditor and dependencies to its own folder - remove Immutable - remove redux-persist-immutable - remobe redux-immutable - update libraries - added tests on store manipulations (accessor and reducers)

import { put } from 'redux-saga/effects';
import * as R from 'ramda';
import { ActionEnum } from '../constants';

const testLocalListHas = R.useWith(R.compose,[R.contains, R.prop]);
const getPropValues = R.compose(R.values, R.prop);

export const SyncMixin = Base => class extends Base {

  constructor(syncEntries, client) {
    super();
    this.syncEntries = syncEntries;
    this.client = client;
    this.localDiffs = null;
  }


  * loadFromRemote() {
    const objIds = R.compose(R.map(R.prop('ext_id')),R.reject(R.propEq('action', ActionEnum.UPDATED)))(this.syncEntries);

    if(objIds.length === 0) {
      return ;
    }

    //TODO: manage pagination
    const remoteObjs = yield this.client.get(this.getRemoteLoadUrl(), { ext_id__in: objIds.join(',') })

    for (var remoteObj of remoteObjs.results) {

      if(testLocalListHas(remoteObj.ext_id, 'deleted')(this.localDiffs)) {
      // if(this.localDiffs.get('deleted').has(remoteObj.ext_id)) {
        // The session has been deleted locally, we will delete it later
        continue;
      }

      if(testLocalListHas(remoteObj.ext_id, 'created')(this.localDiffs)) {
      // if(this.localDiffs.get('created').has(remoteObj.ext_id)) {
        // The session has been modified both locally and remotely
        // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions
        this.localDiffs = R.merge(this.localDiffs, { created: R.omit([remoteObj.ext_id,], this.localDiffs.created) } );
        // const newCreatedMap = this.localDiffs.get('created').delete(remoteObj.ext_id);
        // this.localDiffs = this.localDiffs.set('created', newCreatedMap);
      }

      if(testLocalListHas(remoteObj.ext_id, 'updated')(this.localDiffs)) {
        // The session has been modified both locally and remotely
        // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions
        // const newModifiedMap = this.localDiffs.get('updated').delete(remoteObj.ext_id);
        // this.localDiffs = this.localDiffs.set('updated', newModifiedMap);
        this.localDiffs = R.merge(this.localDiffs, { updated: R.omit([remoteObj.ext_id,], this.localDiffs.updated) } );
      }

      let objRecord = this.getLocalRecord(remoteObj);
      yield put(this.loadObj(objRecord));
    }
  }

  * deleteFromRemote() {

    const objToDelete = this.syncEntries
      .filter((syncObj) => syncObj.action === 2)
      .map((syncObj) => syncObj.ext_id);

    let deleteObjs = R.prop('deleted', this.localDiffs);
    let updatedObjs = R.prop('updated', this.localDiffs);
    let createdObjs = R.prop('created', this.localDiffs);
    for (var objId of objToDelete) {
      const omitObjId = R.omit([objId,])
      deleteObjs = omitObjId(deleteObjs);
      updatedObjs = omitObjId(updatedObjs);
      createdObjs = omitObjId(createdObjs);
      yield put(this.doDeleteLocalObj(objId));
    }
    this.localDiffs = {created: createdObjs, updated: updatedObjs, deleted: deleteObjs};
  }

  * syncObjects() {

    this.localDiffs = yield this.getLocalDiffs();

    yield this.loadFromRemote();
    yield this.deleteFromRemote();

    let localObjInst;
    const getLocalDiffPropValues = R.flip(getPropValues)(this.localDiffs);

    // delete remote obj
    for(localObjInst of getLocalDiffPropValues('deleted')) {

      try {
        yield this.client.delete(this.getRemoteDeleteUrl(localObjInst));
      } catch(err) {
        if(err.status !== 404) {
          //TODO: better error handling ???
          console.log("error whe deleting object", err);
        }
        // otherwise, this is ok
      }

      yield put(this.doDeleteLocalObj(localObjInst._id));
    }

    for(localObjInst of getLocalDiffPropValues('created')) {
      const remoteData = this.getRemoteData(localObjInst);
      //TODO: SET VERSION !!!!
      yield this.client.post(this.getRemoteCreateUrl(localObjInst), remoteData);
      yield put(this.resetLocalObj(localObjInst));
    }

    for(localObjInst of getLocalDiffPropValues('updated')) {
      const remoteData = this.getRemoteData(localObjInst);
      //TODO: SET VERSION !!!!
      yield this.client.put(this.getRemoteUpdateUrl(localObjInst), remoteData);
      yield put(this.resetLocalObj(localObjInst));
    }

  }
}

export default SyncMixin;