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;