client/src/sagas/BaseSyncronizer.js
changeset 129 d48946d164c6
child 168 ea92f4fe783d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/sagas/BaseSyncronizer.js	Fri Jul 28 19:40:35 2017 +0200
@@ -0,0 +1,140 @@
+import { put } from 'redux-saga/effects'
+import Immutable from 'immutable';
+
+export const SyncMixin = Base => class extends Base {
+
+  constructor(syncEntries, client) {
+    super();
+    this.syncEntries = syncEntries;
+    this.client = client;
+    this.localDiffs = null;
+  }
+
+  // abstract methods
+
+  // local diffs (immutable)
+  // getLocalDiffs()
+
+  // remote urls
+  // getRemoteLoadUrl()
+  // getRemoteDeleteUrl(localObjInst);
+  // getRemoteCreateUrl(localObjInst)
+  // getRemoteUpdateUrl(localObjInst)
+
+  // build remote json message
+  // getRemoteData(localObjInst)
+  // getLocalRecord(remoteObj)
+
+  // actions
+  // doDeleteLocalObj(localObjId);
+  // resetLocalObj(localObjInst)
+  // loadObj(objRecord)
+
+
+  * loadFromRemote() {
+
+    const objIds = this.syncEntries
+      .filter((syncEntry) => syncEntry.action !== 2)
+      .map((syncEntry) => syncEntry.ext_id);
+
+    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(this.localDiffs.get('deleted').has(remoteObj.ext_id)) {
+        // The session has been deleted locally, we will delete it later
+        continue;
+      }
+
+      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
+        const newCreatedMap = this.localDiffs.get('created').delete(remoteObj.ext_id);
+        this.localDiffs = this.localDiffs.set('created', newCreatedMap);
+      }
+
+      if(this.localDiffs.get('updated').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
+        const newModifiedMap = this.localDiffs.get('updated').delete(remoteObj.ext_id);
+        this.localDiffs = this.localDiffs.set('updated', newModifiedMap);
+      }
+
+      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 = this.localDiffs.get('deleted');
+    let updatedObjs = this.localDiffs.get('updated');
+    let createdObjs = this.localDiffs.get('created');
+    for (var objId of objToDelete) {
+      if(deleteObjs.has(objId)) {
+        // we remove it from the list of sessions to delete
+        deleteObjs = deleteObjs.delete(objId);
+      }
+      if(updatedObjs.has(objId)) {
+        updatedObjs = updatedObjs.delete(objId);
+      }
+      if(createdObjs.has(objId)) {
+        createdObjs = createdObjs.delete(objId);
+      }
+      yield put(this.doDeleteLocalObj(objId));
+    }
+    this.localDiffs = Immutable.Map({created: createdObjs, updated: updatedObjs, deleted: deleteObjs});
+  }
+
+  * syncObjects() {
+
+    this.localDiffs = yield this.getLocalDiffs();
+
+    yield this.loadFromRemote();
+    yield this.deleteFromRemote();
+
+    let localObjInst;
+
+    // delete remote obj
+    for(localObjInst of this.localDiffs.get('deleted').values()) {
+
+      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.get('_id')));
+    }
+
+    for(localObjInst of this.localDiffs.get('created').values()) {
+      const remoteData = this.getRemoteData(localObjInst);
+      //TODO: SET VERSION !!!!
+      yield this.client.post(this.getRemoteCreateUrl(localObjInst), remoteData);
+      yield put(this.resetLocalObj(localObjInst));
+    }
+
+    for(localObjInst of this.localDiffs.get('updated').values()) {
+      const remoteData = this.getRemoteData(localObjInst);
+      //TODO: SET VERSION !!!!
+      yield this.client.put(this.getRemoteUpdateUrl(localObjInst), remoteData);
+      yield put(this.resetLocalObj(localObjInst));
+    }
+
+  }
+}
+
+export default SyncMixin;