cozy-client 57.2.0 → 57.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3097,7 +3097,7 @@ var CozyClient = /*#__PURE__*/function () {
3097
3097
  CozyClient.hooks = CozyClient.hooks || {};
3098
3098
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
3099
3099
 
3100
- CozyClient.version = "57.2.0";
3100
+ CozyClient.version = "57.3.0";
3101
3101
 
3102
3102
  _microee.default.mixin(CozyClient);
3103
3103
 
@@ -9,15 +9,13 @@ exports.extractAndMergeDocument = exports.getCollectionFromSlice = exports.getDo
9
9
 
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
12
- var _keyBy = _interopRequireDefault(require("lodash/keyBy"));
13
-
14
12
  var _get = _interopRequireDefault(require("lodash/get"));
15
13
 
16
- var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
17
-
18
14
  var _omit = _interopRequireDefault(require("lodash/omit"));
19
15
 
20
- var _merge = _interopRequireDefault(require("lodash/merge"));
16
+ var _fastDeepEqual = _interopRequireDefault(require("fast-deep-equal"));
17
+
18
+ var _deepmerge = _interopRequireDefault(require("@fastify/deepmerge"));
21
19
 
22
20
  var _logger = _interopRequireDefault(require("../logger"));
23
21
 
@@ -33,6 +31,8 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
33
31
 
34
32
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
35
33
 
34
+ var deepmergeFn = (0, _deepmerge.default)();
35
+
36
36
  var storeDocument = function storeDocument(state, document) {
37
37
  var type = document._type;
38
38
 
@@ -54,7 +54,7 @@ var storeDocument = function storeDocument(state, document) {
54
54
 
55
55
  var existingDoc = (0, _get.default)(state, [type, (0, _helpers.properId)(document)]);
56
56
 
57
- if ((0, _isEqual.default)(existingDoc, document)) {
57
+ if ((0, _fastDeepEqual.default)(existingDoc, document)) {
58
58
  return state;
59
59
  } else {
60
60
  return _objectSpread(_objectSpread({}, state), {}, (0, _defineProperty2.default)({}, type, _objectSpread(_objectSpread({}, state[type]), {}, (0, _defineProperty2.default)({}, (0, _helpers.properId)(document), mergeDocumentsWithRelationships(existingDoc, document)))));
@@ -203,44 +203,76 @@ var getCollectionFromSlice = function getCollectionFromSlice() {
203
203
 
204
204
  return Object.values(state[doctype]);
205
205
  };
206
- /*
207
- This method has been created in order to get a returned object
208
- in `data` with the full set on information coming potentially from
206
+ /**
207
+ *
208
+ * This method has been created in order to get a returned object
209
+ in `data` with the full set on information coming potentially from
209
210
  `included`
210
-
211
+
211
212
  This method should be somewhere else. The `document` shall not be
212
213
  dealt with included / data and so on.
213
-
214
+
214
215
  This method takes `data` and `included` and merge both sources
215
216
  together. It should be always up-to-date. The returned object
216
217
  will be as full of information as it can be.
217
- */
218
+
219
+ * @param {Array<import('../types').CozyClientDocument>} newData - Queries documents
220
+ * @param {import("../types").DocumentsStateSlice} updatedStateWithIncluded documents' state
221
+ * @returns {import("../types").DocumentsStateSlice} the merged documents state
222
+ */
218
223
 
219
224
 
220
225
  exports.getCollectionFromSlice = getCollectionFromSlice;
221
226
 
222
- var extractAndMergeDocument = function extractAndMergeDocument(data, updatedStateWithIncluded) {
223
- var doctype = data[0]._type;
227
+ var extractAndMergeDocument = function extractAndMergeDocument(newData, updatedStateWithIncluded) {
228
+ var doctype = newData[0]._type;
224
229
 
225
230
  if (!doctype) {
226
- _logger.default.info('Document without _type', data[0]);
231
+ _logger.default.info('Document without _type', newData[0]);
227
232
 
228
233
  throw new Error('Document without _type');
229
- }
234
+ } // Index docs by id, for faster retrieval
235
+
236
+
237
+ var newDocsMap = new Map(newData.map(function (doc) {
238
+ return [(0, _helpers.properId)(doc), doc];
239
+ }));
240
+ var mergedState = Object.assign({}, updatedStateWithIncluded); // FIXME: this was introduced for a bug in banks, but it does not look useful
241
+
242
+ mergedState[doctype] = Object.assign({}, updatedStateWithIncluded[doctype]);
230
243
 
231
- var sortedData = (0, _keyBy.default)(data, _helpers.properId);
232
- var mergedData = Object.assign({}, updatedStateWithIncluded);
233
- mergedData[doctype] = Object.assign({}, updatedStateWithIncluded[doctype]);
234
- Object.values(sortedData).map(function (data) {
235
- var id = (0, _helpers.properId)(data);
244
+ if (!mergedState[doctype]) {
245
+ mergedState[doctype] = {};
246
+ }
236
247
 
237
- if (mergedData[doctype][id]) {
238
- mergedData[doctype][id] = (0, _merge.default)({}, mergedData[doctype][id], data);
239
- } else {
240
- mergedData[doctype][id] = data;
248
+ var haveDocumentsChanged = false;
249
+ newDocsMap.forEach(function (newDoc, key) {
250
+ var id = key;
251
+ var currentDoc = mergedState[doctype][id];
252
+
253
+ if (!currentDoc) {
254
+ mergedState[doctype][id] = newDoc;
255
+ haveDocumentsChanged = true;
256
+ } else if (!(0, _fastDeepEqual.default)(currentDoc, newDoc)) {
257
+ // XXX Here we check if the doc has changed. Note this would be way faster
258
+ // by just relying on revision change, but:
259
+ // - it does not work if the new doc is partial (i.e. retrieved with a .select query)
260
+ // - some documents might change without a rev change: typically the thumbnails links
261
+ // in io.cozy.files, and the io.cozy.settings.instance doc, with additional
262
+ // fields added by the stack
263
+ // - some documents don't have any revision
264
+ mergedState[doctype][id] = deepmergeFn(mergedState[doctype][id], newDoc);
265
+ haveDocumentsChanged = true;
241
266
  }
242
- });
243
- return mergedData;
267
+ }); // XXX If there is any state change, the updated state should have a new reference,
268
+ // as we heavily rely on referential equality.
269
+ // Conversely, if there is no change, the same reference should be kept
270
+
271
+ if (haveDocumentsChanged) {
272
+ return mergedState;
273
+ }
274
+
275
+ return updatedStateWithIncluded;
244
276
  };
245
277
 
246
278
  exports.extractAndMergeDocument = extractAndMergeDocument;
@@ -4,11 +4,9 @@ import {
4
4
  } from './documents'
5
5
 
6
6
  describe('extractAndMerge', () => {
7
- const data = {
8
- 0: {
9
- id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
7
+ const data = [
8
+ {
10
9
  _id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
11
- type: 'io.cozy.files',
12
10
  _type: 'io.cozy.files',
13
11
  blabla: 'new field',
14
12
  cozyMetadata: {
@@ -18,24 +16,20 @@ describe('extractAndMerge', () => {
18
16
  }
19
17
  }
20
18
  },
21
- 1: {
22
- id: 'b6ff135b34e041ffb2d4a4865f3e235f',
23
- type: 'io.cozy.files',
24
- _type: 'io.cozy.files',
19
+ {
25
20
  _id: 'b6ff135b34e041ffb2d4a4865f3e235f',
21
+ _type: 'io.cozy.files',
26
22
  blibli: 'another new field'
27
23
  }
28
- }
24
+ ]
29
25
  const updatedStateWithIncluded = {
30
26
  'io.cozy.files': {
31
27
  b6ff135b34e041ffb2d4a4865f3e0a53: {
32
- attributes: {
33
- type: 'file',
34
- name: 'IMG_0016.PNG',
35
- dir_id: '7d2f9c24cd345ce3171bf71f401e80c6'
36
- },
37
- id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
38
28
  _id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
29
+ _type: 'io.cozy.files',
30
+ name: 'IMG_0016.PNG',
31
+ type: 'file',
32
+ dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
39
33
  links: { self: '/files/b6ff135b34e041ffb2d4a4865f3e0a53' },
40
34
  meta: { rev: '5-87840eceaab358e38aa8b6bb0d4577b1' },
41
35
  relationships: {
@@ -43,8 +37,6 @@ describe('extractAndMerge', () => {
43
37
  links: { related: '/files/7d2f9c24cd345ce3171bf71f401e80c6' }
44
38
  }
45
39
  },
46
- type: 'io.cozy.files',
47
- _type: 'io.cozy.files',
48
40
  cozyMetadata: {
49
41
  updated_at: '987654',
50
42
  updatedByApps: {
@@ -53,22 +45,18 @@ describe('extractAndMerge', () => {
53
45
  }
54
46
  },
55
47
  b6ff135b34e041ffb2d4a4865f3e235f: {
56
- attributes: {
57
- type: 'file',
58
- name: 'IMG_0054.PNG',
59
- dir_id: '7d2f9c24cd345ce3171bf71f401e80c6'
60
- },
61
- id: 'b6ff135b34e041ffb2d4a4865f3e235f',
62
48
  _id: 'b6ff135b34e041ffb2d4a4865f3e235f',
49
+ _type: 'io.cozy.files',
50
+ type: 'file',
51
+ name: 'IMG_0054.PNG',
52
+ dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
63
53
  links: { self: '/files/b6ff135b34e041ffb2d4a4865f3e235f' },
64
54
  meta: { rev: '5-ca91c0dc02dafb38eb56070c1d80d62c' },
65
55
  relationships: {
66
56
  parent: {
67
57
  links: { related: '/files/7d2f9c24cd345ce3171bf71f401e80c6' }
68
58
  }
69
- },
70
- type: 'io.cozy.files',
71
- _type: 'io.cozy.files'
59
+ }
72
60
  }
73
61
  }
74
62
  }
@@ -84,11 +72,9 @@ describe('extractAndMerge', () => {
84
72
  b6ff135b34e041ffb2d4a4865f3e0a53: {
85
73
  _id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
86
74
  _type: 'io.cozy.files',
87
- attributes: {
88
- dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
89
- name: 'IMG_0016.PNG',
90
- type: 'file'
91
- },
75
+ dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
76
+ name: 'IMG_0016.PNG',
77
+ type: 'file',
92
78
  blabla: 'new field',
93
79
  cozyMetadata: {
94
80
  created_at: '123456',
@@ -98,34 +84,28 @@ describe('extractAndMerge', () => {
98
84
  date: '2019-06-11T01:02:03Z'
99
85
  }
100
86
  },
101
- id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
102
87
  links: { self: '/files/b6ff135b34e041ffb2d4a4865f3e0a53' },
103
88
  meta: { rev: '5-87840eceaab358e38aa8b6bb0d4577b1' },
104
89
  relationships: {
105
90
  parent: {
106
91
  links: { related: '/files/7d2f9c24cd345ce3171bf71f401e80c6' }
107
92
  }
108
- },
109
- type: 'io.cozy.files'
93
+ }
110
94
  },
111
95
  b6ff135b34e041ffb2d4a4865f3e235f: {
112
96
  _id: 'b6ff135b34e041ffb2d4a4865f3e235f',
113
97
  _type: 'io.cozy.files',
114
- attributes: {
115
- dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
116
- name: 'IMG_0054.PNG',
117
- type: 'file'
118
- },
98
+ dir_id: '7d2f9c24cd345ce3171bf71f401e80c6',
99
+ name: 'IMG_0054.PNG',
100
+ type: 'file',
119
101
  blibli: 'another new field',
120
- id: 'b6ff135b34e041ffb2d4a4865f3e235f',
121
102
  links: { self: '/files/b6ff135b34e041ffb2d4a4865f3e235f' },
122
103
  meta: { rev: '5-ca91c0dc02dafb38eb56070c1d80d62c' },
123
104
  relationships: {
124
105
  parent: {
125
106
  links: { related: '/files/7d2f9c24cd345ce3171bf71f401e80c6' }
126
107
  }
127
- },
128
- type: 'io.cozy.files'
108
+ }
129
109
  }
130
110
  }
131
111
  }
@@ -171,20 +151,16 @@ describe('extractAndMerge', () => {
171
151
  'even if the mergedData is the same, because reselect createSelector update ' +
172
152
  'according to object reference, not only value',
173
153
  () => {
174
- const dataAlreadyIncludedInUpdatedStateWithIncluded = {
175
- 0: {
176
- id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
154
+ const dataAlreadyIncludedInUpdatedStateWithIncluded = [
155
+ {
177
156
  _id: 'b6ff135b34e041ffb2d4a4865f3e0a53',
178
- type: 'io.cozy.files',
179
157
  _type: 'io.cozy.files'
180
158
  },
181
- 1: {
182
- id: 'b6ff135b34e041ffb2d4a4865f3e235f',
183
- type: 'io.cozy.files',
184
- _type: 'io.cozy.files',
185
- _id: 'b6ff135b34e041ffb2d4a4865f3e235f'
159
+ {
160
+ _id: 'b6ff135b34e041ffb2d4a4865f3e235f',
161
+ _type: 'io.cozy.files'
186
162
  }
187
- }
163
+ ]
188
164
 
189
165
  const returnedDatas = extractAndMergeDocument(
190
166
  dataAlreadyIncludedInUpdatedStateWithIncluded,
@@ -202,6 +178,44 @@ describe('extractAndMerge', () => {
202
178
  )
203
179
  }
204
180
  )
181
+ it('should keep state reference in case no document has changed', () => {
182
+ const newDoc = { ...data[0] }
183
+
184
+ const mergedState = extractAndMergeDocument(
185
+ [newDoc],
186
+ updatedStateWithIncluded
187
+ )
188
+ expect(mergedState === updatedStateWithIncluded)
189
+ })
190
+
191
+ it('should have different state reference if a new document is added', () => {
192
+ const newDoc = {
193
+ _id: '1234',
194
+ _type: 'io.cozy.files',
195
+ name: 'New doc'
196
+ }
197
+ const mergedState = extractAndMergeDocument(
198
+ [newDoc],
199
+ updatedStateWithIncluded
200
+ )
201
+ expect(mergedState !== updatedStateWithIncluded)
202
+ })
203
+
204
+ it('should have different state reference if an existing document have changed', () => {
205
+ const newDoc = {
206
+ ...data[0],
207
+ cozyMetadata: {
208
+ ...data[0].cozyMetadata,
209
+ updatedByApps: '2025-01-01'
210
+ }
211
+ }
212
+
213
+ const mergedState = extractAndMergeDocument(
214
+ [newDoc],
215
+ updatedStateWithIncluded
216
+ )
217
+ expect(mergedState !== updatedStateWithIncluded)
218
+ })
205
219
  })
206
220
 
207
221
  describe('mergeDocumentsWithRelationships', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "57.2.0",
3
+ "version": "57.3.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -15,11 +15,13 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@cozy/minilog": "1.0.0",
18
+ "@fastify/deepmerge": "^2.0.2",
18
19
  "@types/jest": "^26.0.20",
19
20
  "@types/lodash": "^4.14.170",
20
21
  "btoa": "^1.2.1",
21
22
  "cozy-stack-client": "^57.2.0",
22
23
  "date-fns": "2.29.3",
24
+ "fast-deep-equal": "^3.1.3",
23
25
  "json-stable-stringify": "^1.0.1",
24
26
  "lodash": "^4.17.13",
25
27
  "microee": "^0.0.6",
@@ -72,5 +74,5 @@
72
74
  "react-native-ios11-devicecheck": "https://github.com/cozy/react-native-devicecheck#app-attest-v0.1"
73
75
  },
74
76
  "sideEffects": false,
75
- "gitHead": "f9c7c5c422ae18a648278cecf820f9a367447263"
77
+ "gitHead": "aa4094d6cb80bbd4173cc82fb1a2a06406718b5e"
76
78
  }
@@ -3,5 +3,5 @@ export default documents;
3
3
  export function getDocumentFromSlice(state: import('../types').DocumentsStateSlice, doctype: string, id: string): import('../types').CozyClientDocument;
4
4
  export function getDocumentsFromSlice(state: import('../types').DocumentsStateSlice, doctype: string, ids: Array<string>): Array<import('../types').CozyClientDocument>;
5
5
  export function getCollectionFromSlice(state: {}, doctype: any): any[];
6
- export function extractAndMergeDocument(data: any, updatedStateWithIncluded: any): any;
6
+ export function extractAndMergeDocument(newData: Array<import('../types').CozyClientDocument>, updatedStateWithIncluded: import("../types").DocumentsStateSlice): import("../types").DocumentsStateSlice;
7
7
  declare function documents(state: {}, action: any): any;