|
1 import { put } from 'redux-saga/effects' |
|
2 import Immutable from 'immutable'; |
|
3 |
|
4 export const SyncMixin = Base => class extends Base { |
|
5 |
|
6 constructor(syncEntries, client) { |
|
7 super(); |
|
8 this.syncEntries = syncEntries; |
|
9 this.client = client; |
|
10 this.localDiffs = null; |
|
11 } |
|
12 |
|
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 |
|
34 * loadFromRemote() { |
|
35 |
|
36 const objIds = this.syncEntries |
|
37 .filter((syncEntry) => syncEntry.action !== 2) |
|
38 .map((syncEntry) => syncEntry.ext_id); |
|
39 |
|
40 if(objIds.length === 0) { |
|
41 return ; |
|
42 } |
|
43 |
|
44 //TODO: manage pagination |
|
45 const remoteObjs = yield this.client.get(this.getRemoteLoadUrl(), { ext_id__in: objIds.join(',') }) |
|
46 |
|
47 for (var remoteObj of remoteObjs.results) { |
|
48 |
|
49 if(this.localDiffs.get('deleted').has(remoteObj.ext_id)) { |
|
50 // The session has been deleted locally, we will delete it later |
|
51 continue; |
|
52 } |
|
53 |
|
54 if(this.localDiffs.get('created').has(remoteObj.ext_id)) { |
|
55 // 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 |
|
57 const newCreatedMap = this.localDiffs.get('created').delete(remoteObj.ext_id); |
|
58 this.localDiffs = this.localDiffs.set('created', newCreatedMap); |
|
59 } |
|
60 |
|
61 if(this.localDiffs.get('updated').has(remoteObj.ext_id)) { |
|
62 // 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 |
|
64 const newModifiedMap = this.localDiffs.get('updated').delete(remoteObj.ext_id); |
|
65 this.localDiffs = this.localDiffs.set('updated', newModifiedMap); |
|
66 } |
|
67 |
|
68 let objRecord = this.getLocalRecord(remoteObj); |
|
69 yield put(this.loadObj(objRecord)); |
|
70 } |
|
71 } |
|
72 |
|
73 * deleteFromRemote() { |
|
74 |
|
75 const objToDelete = this.syncEntries |
|
76 .filter((syncObj) => syncObj.action === 2) |
|
77 .map((syncObj) => syncObj.ext_id); |
|
78 |
|
79 let deleteObjs = this.localDiffs.get('deleted'); |
|
80 let updatedObjs = this.localDiffs.get('updated'); |
|
81 let createdObjs = this.localDiffs.get('created'); |
|
82 for (var objId of objToDelete) { |
|
83 if(deleteObjs.has(objId)) { |
|
84 // we remove it from the list of sessions to delete |
|
85 deleteObjs = deleteObjs.delete(objId); |
|
86 } |
|
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)); |
|
94 } |
|
95 this.localDiffs = Immutable.Map({created: createdObjs, updated: updatedObjs, deleted: deleteObjs}); |
|
96 } |
|
97 |
|
98 * syncObjects() { |
|
99 |
|
100 this.localDiffs = yield this.getLocalDiffs(); |
|
101 |
|
102 yield this.loadFromRemote(); |
|
103 yield this.deleteFromRemote(); |
|
104 |
|
105 let localObjInst; |
|
106 |
|
107 // delete remote obj |
|
108 for(localObjInst of this.localDiffs.get('deleted').values()) { |
|
109 |
|
110 try { |
|
111 yield this.client.delete(this.getRemoteDeleteUrl(localObjInst)); |
|
112 } catch(err) { |
|
113 if(err.status !== 404) { |
|
114 //TODO: better error handling ??? |
|
115 console.log("error whe deleting object", err); |
|
116 } |
|
117 // otherwise, this is ok |
|
118 } |
|
119 |
|
120 yield put(this.doDeleteLocalObj(localObjInst.get('_id'))); |
|
121 } |
|
122 |
|
123 for(localObjInst of this.localDiffs.get('created').values()) { |
|
124 const remoteData = this.getRemoteData(localObjInst); |
|
125 //TODO: SET VERSION !!!! |
|
126 yield this.client.post(this.getRemoteCreateUrl(localObjInst), remoteData); |
|
127 yield put(this.resetLocalObj(localObjInst)); |
|
128 } |
|
129 |
|
130 for(localObjInst of this.localDiffs.get('updated').values()) { |
|
131 const remoteData = this.getRemoteData(localObjInst); |
|
132 //TODO: SET VERSION !!!! |
|
133 yield this.client.put(this.getRemoteUpdateUrl(localObjInst), remoteData); |
|
134 yield put(this.resetLocalObj(localObjInst)); |
|
135 } |
|
136 |
|
137 } |
|
138 } |
|
139 |
|
140 export default SyncMixin; |