1 import { put } from 'redux-saga/effects' |
1 import { put } from 'redux-saga/effects'; |
2 import Immutable from 'immutable'; |
2 import * as R from 'ramda'; |
|
3 import { ActionEnum } from '../constants'; |
|
4 |
|
5 const testLocalListHas = R.useWith(R.compose,[R.contains, R.prop]); |
|
6 const getPropValues = R.compose(R.values, R.prop); |
3 |
7 |
4 export const SyncMixin = Base => class extends Base { |
8 export const SyncMixin = Base => class extends Base { |
5 |
9 |
6 constructor(syncEntries, client) { |
10 constructor(syncEntries, client) { |
7 super(); |
11 super(); |
8 this.syncEntries = syncEntries; |
12 this.syncEntries = syncEntries; |
9 this.client = client; |
13 this.client = client; |
10 this.localDiffs = null; |
14 this.localDiffs = null; |
11 } |
15 } |
12 |
16 |
13 // abstract methods |
|
14 |
|
15 // local diffs (immutable) |
|
16 // getLocalDiffs() |
|
17 |
|
18 // remote urls |
|
19 // getRemoteLoadUrl() |
|
20 // getRemoteDeleteUrl(localObjInst); |
|
21 // getRemoteCreateUrl(localObjInst) |
|
22 // getRemoteUpdateUrl(localObjInst) |
|
23 |
|
24 // build remote json message |
|
25 // getRemoteData(localObjInst) |
|
26 // getLocalRecord(remoteObj) |
|
27 |
|
28 // actions |
|
29 // doDeleteLocalObj(localObjId); |
|
30 // resetLocalObj(localObjInst) |
|
31 // loadObj(objRecord) |
|
32 |
|
33 |
17 |
34 * loadFromRemote() { |
18 * loadFromRemote() { |
35 |
19 const objIds = R.compose(R.map(R.prop('ext_id')),R.reject(R.propEq('action', ActionEnum.UPDATED)))(this.syncEntries); |
36 const objIds = this.syncEntries |
|
37 .filter((syncEntry) => syncEntry.action !== 2) |
|
38 .map((syncEntry) => syncEntry.ext_id); |
|
39 |
20 |
40 if(objIds.length === 0) { |
21 if(objIds.length === 0) { |
41 return ; |
22 return ; |
42 } |
23 } |
43 |
24 |
44 //TODO: manage pagination |
25 //TODO: manage pagination |
45 const remoteObjs = yield this.client.get(this.getRemoteLoadUrl(), { ext_id__in: objIds.join(',') }) |
26 const remoteObjs = yield this.client.get(this.getRemoteLoadUrl(), { ext_id__in: objIds.join(',') }) |
46 |
27 |
47 for (var remoteObj of remoteObjs.results) { |
28 for (var remoteObj of remoteObjs.results) { |
48 |
29 |
49 if(this.localDiffs.get('deleted').has(remoteObj.ext_id)) { |
30 if(testLocalListHas(remoteObj.ext_id, 'deleted')(this.localDiffs)) { |
|
31 // if(this.localDiffs.get('deleted').has(remoteObj.ext_id)) { |
50 // The session has been deleted locally, we will delete it later |
32 // The session has been deleted locally, we will delete it later |
51 continue; |
33 continue; |
52 } |
34 } |
53 |
35 |
54 if(this.localDiffs.get('created').has(remoteObj.ext_id)) { |
36 if(testLocalListHas(remoteObj.ext_id, 'created')(this.localDiffs)) { |
|
37 // if(this.localDiffs.get('created').has(remoteObj.ext_id)) { |
55 // The session has been modified both locally and remotely |
38 // The session has been modified both locally and remotely |
56 // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions |
39 // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions |
57 const newCreatedMap = this.localDiffs.get('created').delete(remoteObj.ext_id); |
40 this.localDiffs = R.merge(this.localDiffs, { created: R.omit([remoteObj.ext_id,], this.localDiffs.created) } ); |
58 this.localDiffs = this.localDiffs.set('created', newCreatedMap); |
41 // const newCreatedMap = this.localDiffs.get('created').delete(remoteObj.ext_id); |
|
42 // this.localDiffs = this.localDiffs.set('created', newCreatedMap); |
59 } |
43 } |
60 |
44 |
61 if(this.localDiffs.get('updated').has(remoteObj.ext_id)) { |
45 if(testLocalListHas(remoteObj.ext_id, 'updated')(this.localDiffs)) { |
62 // The session has been modified both locally and remotely |
46 // The session has been modified both locally and remotely |
63 // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions |
47 // the server wins, it will be loaded locally, we must remove it from the list of locally changed sessions |
64 const newModifiedMap = this.localDiffs.get('updated').delete(remoteObj.ext_id); |
48 // const newModifiedMap = this.localDiffs.get('updated').delete(remoteObj.ext_id); |
65 this.localDiffs = this.localDiffs.set('updated', newModifiedMap); |
49 // this.localDiffs = this.localDiffs.set('updated', newModifiedMap); |
|
50 this.localDiffs = R.merge(this.localDiffs, { updated: R.omit([remoteObj.ext_id,], this.localDiffs.updated) } ); |
66 } |
51 } |
67 |
52 |
68 let objRecord = this.getLocalRecord(remoteObj); |
53 let objRecord = this.getLocalRecord(remoteObj); |
69 yield put(this.loadObj(objRecord)); |
54 yield put(this.loadObj(objRecord)); |
70 } |
55 } |
74 |
59 |
75 const objToDelete = this.syncEntries |
60 const objToDelete = this.syncEntries |
76 .filter((syncObj) => syncObj.action === 2) |
61 .filter((syncObj) => syncObj.action === 2) |
77 .map((syncObj) => syncObj.ext_id); |
62 .map((syncObj) => syncObj.ext_id); |
78 |
63 |
79 let deleteObjs = this.localDiffs.get('deleted'); |
64 let deleteObjs = R.prop('deleted', this.localDiffs); |
80 let updatedObjs = this.localDiffs.get('updated'); |
65 let updatedObjs = R.prop('updated', this.localDiffs); |
81 let createdObjs = this.localDiffs.get('created'); |
66 let createdObjs = R.prop('created', this.localDiffs); |
82 for (var objId of objToDelete) { |
67 for (var objId of objToDelete) { |
83 if(deleteObjs.has(objId)) { |
68 const omitObjId = R.omit([objId,]) |
84 // we remove it from the list of sessions to delete |
69 deleteObjs = omitObjId(deleteObjs); |
85 deleteObjs = deleteObjs.delete(objId); |
70 updatedObjs = omitObjId(updatedObjs); |
86 } |
71 createdObjs = omitObjId(createdObjs); |
87 if(updatedObjs.has(objId)) { |
|
88 updatedObjs = updatedObjs.delete(objId); |
|
89 } |
|
90 if(createdObjs.has(objId)) { |
|
91 createdObjs = createdObjs.delete(objId); |
|
92 } |
|
93 yield put(this.doDeleteLocalObj(objId)); |
72 yield put(this.doDeleteLocalObj(objId)); |
94 } |
73 } |
95 this.localDiffs = Immutable.Map({created: createdObjs, updated: updatedObjs, deleted: deleteObjs}); |
74 this.localDiffs = {created: createdObjs, updated: updatedObjs, deleted: deleteObjs}; |
96 } |
75 } |
97 |
76 |
98 * syncObjects() { |
77 * syncObjects() { |
99 |
78 |
100 this.localDiffs = yield this.getLocalDiffs(); |
79 this.localDiffs = yield this.getLocalDiffs(); |
101 |
80 |
102 yield this.loadFromRemote(); |
81 yield this.loadFromRemote(); |
103 yield this.deleteFromRemote(); |
82 yield this.deleteFromRemote(); |
104 |
83 |
105 let localObjInst; |
84 let localObjInst; |
|
85 const getLocalDiffPropValues = R.flip(getPropValues)(this.localDiffs); |
106 |
86 |
107 // delete remote obj |
87 // delete remote obj |
108 for(localObjInst of this.localDiffs.get('deleted').values()) { |
88 for(localObjInst of getLocalDiffPropValues('deleted')) { |
109 |
89 |
110 try { |
90 try { |
111 yield this.client.delete(this.getRemoteDeleteUrl(localObjInst)); |
91 yield this.client.delete(this.getRemoteDeleteUrl(localObjInst)); |
112 } catch(err) { |
92 } catch(err) { |
113 if(err.status !== 404) { |
93 if(err.status !== 404) { |
115 console.log("error whe deleting object", err); |
95 console.log("error whe deleting object", err); |
116 } |
96 } |
117 // otherwise, this is ok |
97 // otherwise, this is ok |
118 } |
98 } |
119 |
99 |
120 yield put(this.doDeleteLocalObj(localObjInst.get('_id'))); |
100 yield put(this.doDeleteLocalObj(localObjInst._id)); |
121 } |
101 } |
122 |
102 |
123 for(localObjInst of this.localDiffs.get('created').values()) { |
103 for(localObjInst of getLocalDiffPropValues('created')) { |
124 const remoteData = this.getRemoteData(localObjInst); |
104 const remoteData = this.getRemoteData(localObjInst); |
125 //TODO: SET VERSION !!!! |
105 //TODO: SET VERSION !!!! |
126 yield this.client.post(this.getRemoteCreateUrl(localObjInst), remoteData); |
106 yield this.client.post(this.getRemoteCreateUrl(localObjInst), remoteData); |
127 yield put(this.resetLocalObj(localObjInst)); |
107 yield put(this.resetLocalObj(localObjInst)); |
128 } |
108 } |
129 |
109 |
130 for(localObjInst of this.localDiffs.get('updated').values()) { |
110 for(localObjInst of getLocalDiffPropValues('updated')) { |
131 const remoteData = this.getRemoteData(localObjInst); |
111 const remoteData = this.getRemoteData(localObjInst); |
132 //TODO: SET VERSION !!!! |
112 //TODO: SET VERSION !!!! |
133 yield this.client.put(this.getRemoteUpdateUrl(localObjInst), remoteData); |
113 yield this.client.put(this.getRemoteUpdateUrl(localObjInst), remoteData); |
134 yield put(this.resetLocalObj(localObjInst)); |
114 yield put(this.resetLocalObj(localObjInst)); |
135 } |
115 } |