cozy-client 59.4.0 → 60.1.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.
@@ -19,6 +19,7 @@ Object {
19
19
  "partialFilter": undefined,
20
20
  "referenced": undefined,
21
21
  "selector": undefined,
22
+ "sharingId": undefined,
22
23
  "skip": undefined,
23
24
  "sort": undefined,
24
25
  },
@@ -32,6 +33,8 @@ Object {
32
33
  "lastFetch": null,
33
34
  "lastUpdate": null,
34
35
  "options": null,
36
+ "relationshipNames": Array [],
37
+ "storeData": Array [],
35
38
  },
36
39
  }
37
40
  `;
@@ -58,6 +61,7 @@ Object {
58
61
  "partialFilter": undefined,
59
62
  "referenced": undefined,
60
63
  "selector": undefined,
64
+ "sharingId": undefined,
61
65
  "skip": undefined,
62
66
  "sort": undefined,
63
67
  },
@@ -71,6 +75,8 @@ Object {
71
75
  "lastFetch": 1337,
72
76
  "lastUpdate": 1337,
73
77
  "options": null,
78
+ "relationshipNames": Array [],
79
+ "storeData": Array [],
74
80
  },
75
81
  }
76
82
  `;
@@ -96,6 +102,7 @@ Object {
96
102
  "partialFilter": undefined,
97
103
  "referenced": undefined,
98
104
  "selector": undefined,
105
+ "sharingId": undefined,
99
106
  "skip": undefined,
100
107
  "sort": undefined,
101
108
  },
@@ -109,6 +116,8 @@ Object {
109
116
  "lastFetch": 1337,
110
117
  "lastUpdate": 1337,
111
118
  "options": null,
119
+ "relationshipNames": Array [],
120
+ "storeData": Array [],
112
121
  },
113
122
  "b": Object {
114
123
  "bookmark": null,
@@ -134,6 +143,7 @@ Object {
134
143
  },
135
144
  "done": true,
136
145
  },
146
+ "sharingId": undefined,
137
147
  "skip": undefined,
138
148
  "sort": undefined,
139
149
  },
@@ -147,6 +157,8 @@ Object {
147
157
  "lastFetch": null,
148
158
  "lastUpdate": 1337,
149
159
  "options": null,
160
+ "relationshipNames": Array [],
161
+ "storeData": Array [],
150
162
  },
151
163
  }
152
164
  `;
@@ -172,6 +184,7 @@ Object {
172
184
  "partialFilter": undefined,
173
185
  "referenced": undefined,
174
186
  "selector": undefined,
187
+ "sharingId": undefined,
175
188
  "skip": undefined,
176
189
  "sort": undefined,
177
190
  },
@@ -185,6 +198,8 @@ Object {
185
198
  "lastFetch": 1337,
186
199
  "lastUpdate": 1337,
187
200
  "options": null,
201
+ "relationshipNames": Array [],
202
+ "storeData": Array [],
188
203
  },
189
204
  "b": Object {
190
205
  "bookmark": null,
@@ -207,6 +222,7 @@ Object {
207
222
  "selector": Object {
208
223
  "done": true,
209
224
  },
225
+ "sharingId": undefined,
210
226
  "skip": undefined,
211
227
  "sort": undefined,
212
228
  },
@@ -220,6 +236,8 @@ Object {
220
236
  "lastFetch": null,
221
237
  "lastUpdate": 1337,
222
238
  "options": null,
239
+ "relationshipNames": Array [],
240
+ "storeData": Array [],
223
241
  },
224
242
  }
225
243
  `;
@@ -247,6 +265,7 @@ Object {
247
265
  "selector": Object {
248
266
  "done": false,
249
267
  },
268
+ "sharingId": undefined,
250
269
  "skip": undefined,
251
270
  "sort": Array [
252
271
  Object {
@@ -264,6 +283,8 @@ Object {
264
283
  "lastFetch": 1337,
265
284
  "lastUpdate": 1337,
266
285
  "options": null,
286
+ "relationshipNames": Array [],
287
+ "storeData": Array [],
267
288
  },
268
289
  "b": Object {
269
290
  "bookmark": null,
@@ -284,6 +305,7 @@ Object {
284
305
  "selector": Object {
285
306
  "done": true,
286
307
  },
308
+ "sharingId": undefined,
287
309
  "skip": undefined,
288
310
  "sort": undefined,
289
311
  },
@@ -297,6 +319,8 @@ Object {
297
319
  "lastFetch": null,
298
320
  "lastUpdate": null,
299
321
  "options": null,
322
+ "relationshipNames": Array [],
323
+ "storeData": Array [],
300
324
  },
301
325
  }
302
326
  `;
@@ -323,6 +347,7 @@ Object {
323
347
  "partialFilter": undefined,
324
348
  "referenced": undefined,
325
349
  "selector": undefined,
350
+ "sharingId": undefined,
326
351
  "skip": undefined,
327
352
  "sort": undefined,
328
353
  },
@@ -336,6 +361,8 @@ Object {
336
361
  "lastFetch": 1337,
337
362
  "lastUpdate": 1337,
338
363
  "options": null,
364
+ "relationshipNames": Array [],
365
+ "storeData": Array [],
339
366
  },
340
367
  "b": Object {
341
368
  "bookmark": null,
@@ -357,6 +384,7 @@ Object {
357
384
  "partialFilter": undefined,
358
385
  "referenced": undefined,
359
386
  "selector": undefined,
387
+ "sharingId": undefined,
360
388
  "skip": undefined,
361
389
  "sort": undefined,
362
390
  },
@@ -370,6 +398,8 @@ Object {
370
398
  "lastFetch": null,
371
399
  "lastUpdate": 1337,
372
400
  "options": null,
401
+ "relationshipNames": Array [],
402
+ "storeData": Array [],
373
403
  },
374
404
  }
375
405
  `;
@@ -395,6 +425,7 @@ Object {
395
425
  "partialFilter": undefined,
396
426
  "referenced": undefined,
397
427
  "selector": undefined,
428
+ "sharingId": undefined,
398
429
  "skip": undefined,
399
430
  "sort": undefined,
400
431
  },
@@ -408,6 +439,8 @@ Object {
408
439
  "lastFetch": 1337,
409
440
  "lastUpdate": 1337,
410
441
  "options": null,
442
+ "relationshipNames": Array [],
443
+ "storeData": Array [],
411
444
  },
412
445
  "b": Object {
413
446
  "bookmark": null,
@@ -428,6 +461,7 @@ Object {
428
461
  "selector": Object {
429
462
  "done": true,
430
463
  },
464
+ "sharingId": undefined,
431
465
  "skip": undefined,
432
466
  "sort": undefined,
433
467
  },
@@ -445,6 +479,8 @@ Object {
445
479
  "add": false,
446
480
  },
447
481
  },
482
+ "relationshipNames": Array [],
483
+ "storeData": Array [],
448
484
  },
449
485
  }
450
486
  `;
@@ -468,6 +504,7 @@ Object {
468
504
  "partialFilter": undefined,
469
505
  "referenced": undefined,
470
506
  "selector": undefined,
507
+ "sharingId": undefined,
471
508
  "skip": undefined,
472
509
  "sort": undefined,
473
510
  },
@@ -481,6 +518,8 @@ Object {
481
518
  "lastFetch": null,
482
519
  "lastUpdate": null,
483
520
  "options": null,
521
+ "relationshipNames": Array [],
522
+ "storeData": Array [],
484
523
  },
485
524
  "b": Object {
486
525
  "bookmark": null,
@@ -499,6 +538,7 @@ Object {
499
538
  "partialFilter": undefined,
500
539
  "referenced": undefined,
501
540
  "selector": undefined,
541
+ "sharingId": undefined,
502
542
  "skip": undefined,
503
543
  "sort": undefined,
504
544
  },
@@ -512,6 +552,8 @@ Object {
512
552
  "lastFetch": 1337,
513
553
  "lastUpdate": 1337,
514
554
  "options": null,
555
+ "relationshipNames": Array [],
556
+ "storeData": Array [],
515
557
  },
516
558
  }
517
559
  `;
@@ -537,6 +579,7 @@ Object {
537
579
  "partialFilter": undefined,
538
580
  "referenced": undefined,
539
581
  "selector": undefined,
582
+ "sharingId": undefined,
540
583
  "skip": undefined,
541
584
  "sort": undefined,
542
585
  },
@@ -550,6 +593,8 @@ Object {
550
593
  "lastFetch": 1337,
551
594
  "lastUpdate": 1337,
552
595
  "options": null,
596
+ "relationshipNames": Array [],
597
+ "storeData": Array [],
553
598
  },
554
599
  "b": Object {
555
600
  "bookmark": null,
@@ -572,6 +617,7 @@ Object {
572
617
  "selector": Object {
573
618
  "done": true,
574
619
  },
620
+ "sharingId": undefined,
575
621
  "skip": undefined,
576
622
  "sort": undefined,
577
623
  },
@@ -589,6 +635,8 @@ Object {
589
635
  "remove": false,
590
636
  },
591
637
  },
638
+ "relationshipNames": Array [],
639
+ "storeData": Array [],
592
640
  },
593
641
  }
594
642
  `;
@@ -614,6 +662,7 @@ Object {
614
662
  "partialFilter": undefined,
615
663
  "referenced": undefined,
616
664
  "selector": undefined,
665
+ "sharingId": undefined,
617
666
  "skip": undefined,
618
667
  "sort": undefined,
619
668
  },
@@ -627,6 +676,8 @@ Object {
627
676
  "lastFetch": 1337,
628
677
  "lastUpdate": 1337,
629
678
  "options": null,
679
+ "relationshipNames": Array [],
680
+ "storeData": Array [],
630
681
  },
631
682
  "b": Object {
632
683
  "bookmark": null,
@@ -647,6 +698,7 @@ Object {
647
698
  "selector": Object {
648
699
  "done": false,
649
700
  },
701
+ "sharingId": undefined,
650
702
  "skip": undefined,
651
703
  "sort": undefined,
652
704
  },
@@ -660,6 +712,8 @@ Object {
660
712
  "lastFetch": null,
661
713
  "lastUpdate": null,
662
714
  "options": null,
715
+ "relationshipNames": Array [],
716
+ "storeData": Array [],
663
717
  },
664
718
  }
665
719
  `;
@@ -687,6 +741,7 @@ Object {
687
741
  "partialFilter": undefined,
688
742
  "referenced": undefined,
689
743
  "selector": undefined,
744
+ "sharingId": undefined,
690
745
  "skip": undefined,
691
746
  "sort": undefined,
692
747
  },
@@ -700,6 +755,8 @@ Object {
700
755
  "lastFetch": 1337,
701
756
  "lastUpdate": 1337,
702
757
  "options": null,
758
+ "relationshipNames": Array [],
759
+ "storeData": Array [],
703
760
  },
704
761
  "b": Object {
705
762
  "bookmark": null,
@@ -723,6 +780,7 @@ Object {
723
780
  },
724
781
  "referenced": undefined,
725
782
  "selector": undefined,
783
+ "sharingId": undefined,
726
784
  "skip": undefined,
727
785
  "sort": undefined,
728
786
  },
@@ -736,6 +794,8 @@ Object {
736
794
  "lastFetch": null,
737
795
  "lastUpdate": 1337,
738
796
  "options": null,
797
+ "relationshipNames": Array [],
798
+ "storeData": Array [],
739
799
  },
740
800
  }
741
801
  `;
@@ -94,7 +94,9 @@ var queryInitialState = {
94
94
  count: 0,
95
95
  fetchedPagesCount: 0,
96
96
  data: [],
97
- bookmark: null
97
+ storeData: [],
98
+ bookmark: null,
99
+ relationshipNames: []
98
100
  };
99
101
  /**
100
102
  * Return the docs ids accordingly to the given sort and fetched docs
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.equalityCheckForQuery = void 0;
7
+
8
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
9
+
10
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
11
+
12
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
13
+
14
+ /**
15
+ * Perform an equality check to determine whether or not two query results are equal.
16
+ *
17
+ * This is typically called by a `useSelector`, to determine if a render should be made because
18
+ * the query result has changed.
19
+ * See https://react-redux.js.org/api/hooks#equality-comparisons-and-updates
20
+ *
21
+ * We cannot use the default strict reference comparison here, because a new reference for the query
22
+ * result is made every time. However, the query result itself, in `storeData`, preserves references.
23
+ *
24
+ * Note we do not make a shallow equality check on documents, as it is much less efficient.
25
+ * It is however different for relationships: because of their hydratation, the references change
26
+ * even if the data is the same.
27
+ *
28
+ * @param {import("../types").QueryState} queryResA - A query result to compare
29
+ * @param {import("../types").QueryState} queryResB - A query result to compare
30
+ * @returns {boolean} whether or not the two query are equal
31
+ */
32
+ var equalityCheckForQuery = function equalityCheckForQuery(queryResA, queryResB) {
33
+ if (queryResA === queryResB) {
34
+ // Referential equality
35
+ return true;
36
+ }
37
+
38
+ if (typeof queryResA !== 'object' || queryResA === null || typeof queryResB !== 'object' || queryResB === null) {
39
+ // queryResA or queryResB is not an object or null
40
+ return false;
41
+ }
42
+
43
+ if (queryResA.id !== queryResB.id) {
44
+ return false;
45
+ }
46
+
47
+ if (queryResA.fetchStatus !== queryResB.fetchStatus) {
48
+ return false;
49
+ }
50
+
51
+ var docsA = queryResA.storeData;
52
+ var docsB = queryResB.storeData;
53
+
54
+ if (!docsA || !docsB) {
55
+ // No data to check
56
+ return false;
57
+ }
58
+
59
+ if (!Array.isArray(docsA) && !Array.isArray(docsB) && docsA !== docsB) {
60
+ // Only one doc
61
+ return false;
62
+ }
63
+
64
+ if (Array.isArray(docsA) && Array.isArray(docsB) && !arraysHaveSameLength(docsA, docsB)) {
65
+ // A document was added or removed
66
+ return false;
67
+ }
68
+
69
+ if (Array.isArray(docsA) && Array.isArray(docsB)) {
70
+ for (var i = 0; i < docsA.length; i++) {
71
+ if (docsA[i] !== docsB[i]) {
72
+ // References should be the same for non-updated documents
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+
78
+ if (queryResA.relationshipNames) {
79
+ // In case of relationships, we cannot check referential equality, because we
80
+ // "hydrate" the data by creating a new instance of the related relationship class.
81
+ // Thus, we check the document revision instead.
82
+ var hydratedDataA = queryResA.data;
83
+ var hydratedDataB = queryResB.data;
84
+
85
+ if (!Array.isArray(hydratedDataA) && !Array.isArray(hydratedDataB)) {
86
+ // One doc with changed relationship
87
+ return revsAreEqual(hydratedDataA, hydratedDataB);
88
+ }
89
+
90
+ if (!arraysHaveSameLength(hydratedDataA, hydratedDataB)) {
91
+ // A relationship have been added or removed
92
+ return false;
93
+ }
94
+
95
+ if (Array.isArray(hydratedDataA) && Array.isArray(hydratedDataB)) {
96
+ for (var _i = 0; _i < hydratedDataA.length; _i++) {
97
+ var _iterator = _createForOfIteratorHelper(queryResA.relationshipNames),
98
+ _step;
99
+
100
+ try {
101
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
102
+ var name = _step.value;
103
+ // Check hydrated relationship
104
+ var includedA = hydratedDataA[_i][name];
105
+ var includedB = hydratedDataB[_i][name];
106
+
107
+ if (includedA && includedB) {
108
+ if (!revsAreEqual(includedA, includedB)) {
109
+ return false;
110
+ }
111
+ }
112
+ }
113
+ } catch (err) {
114
+ _iterator.e(err);
115
+ } finally {
116
+ _iterator.f();
117
+ }
118
+ }
119
+ }
120
+ } // The query results are indeed equal
121
+
122
+
123
+ return true;
124
+ };
125
+
126
+ exports.equalityCheckForQuery = equalityCheckForQuery;
127
+
128
+ var revsAreEqual = function revsAreEqual(docA, docB) {
129
+ if (!docA._rev || !docB._rev) {
130
+ return false;
131
+ }
132
+
133
+ return (docA === null || docA === void 0 ? void 0 : docA._rev) === (docB === null || docB === void 0 ? void 0 : docB._rev);
134
+ };
135
+
136
+ var arraysHaveSameLength = function arraysHaveSameLength(arrayA, arrayB) {
137
+ return Array.isArray(arrayA) && Array.isArray(arrayB) && arrayA.length === arrayB.length;
138
+ };
@@ -0,0 +1,238 @@
1
+ import { equalityCheckForQuery } from './selector'
2
+
3
+ const mapIdsToDocuments = (state, doctype, ids) => {
4
+ return ids.map(id => state[doctype][id])
5
+ }
6
+
7
+ const state = {
8
+ documents: {
9
+ 'io.cozy.files': {
10
+ doc1: {
11
+ _id: 'doc1'
12
+ },
13
+ doc2: {
14
+ _id: 'doc2'
15
+ },
16
+ doc3: {
17
+ _id: 'doc3'
18
+ }
19
+ }
20
+ },
21
+ queries: {
22
+ query1: {
23
+ id: 'query1',
24
+ data: ['doc1', 'doc2']
25
+ },
26
+ query2: {
27
+ id: 'query2',
28
+ data: ['doc2']
29
+ }
30
+ }
31
+ }
32
+
33
+ const defaultQueryResult = {
34
+ id: 1,
35
+ data: [],
36
+ fetchStatus: 'loaded',
37
+ relationshipNames: null
38
+ }
39
+
40
+ describe('equalityCheckForQuery', () => {
41
+ const queryResultA1 = {
42
+ id: 1,
43
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
44
+ 'doc1',
45
+ 'doc2'
46
+ ]),
47
+ ...defaultQueryResult
48
+ }
49
+ const queryResultA2 = {
50
+ id: 1,
51
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
52
+ 'doc1',
53
+ 'doc2'
54
+ ]),
55
+ ...defaultQueryResult
56
+ }
57
+ const queryResultA3 = {
58
+ id: 1,
59
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
60
+ 'doc1',
61
+ 'doc2',
62
+ 'doc3'
63
+ ]),
64
+ ...defaultQueryResult
65
+ }
66
+ const queryResultA4 = {
67
+ id: 1,
68
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
69
+ 'doc2',
70
+ 'doc3'
71
+ ]),
72
+ ...defaultQueryResult
73
+ }
74
+ const queryResultB1 = {
75
+ id: 2,
76
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc2']),
77
+ ...defaultQueryResult
78
+ }
79
+
80
+ const queryResultB2 = {
81
+ id: 2,
82
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc3']),
83
+ ...defaultQueryResult
84
+ }
85
+
86
+ const queryResultC1 = {
87
+ id: 3,
88
+ storeData: state.documents['io.cozy.files'].doc1,
89
+ data: {},
90
+ ...defaultQueryResult
91
+ }
92
+
93
+ const queryResultC2 = {
94
+ id: 3,
95
+ storeData: state.documents['io.cozy.files'].doc1,
96
+ data: {},
97
+ ...defaultQueryResult
98
+ }
99
+
100
+ const queryResultC3 = {
101
+ id: 3,
102
+ storeData: state.documents['io.cozy.files'].doc2,
103
+ data: {},
104
+ ...defaultQueryResult
105
+ }
106
+
107
+ it('should return true for referential equality', () => {
108
+ expect(equalityCheckForQuery(queryResultA1, queryResultA1)).toBe(true)
109
+ expect(equalityCheckForQuery(null, null)).toBe(true)
110
+ })
111
+
112
+ it('should return false if one object is null', () => {
113
+ expect(equalityCheckForQuery(null, queryResultA1)).toBe(false)
114
+ expect(equalityCheckForQuery(queryResultA1, null)).toBe(false)
115
+ })
116
+
117
+ it('should return false if one or both objects are not objects', () => {
118
+ // @ts-ignore
119
+ expect(equalityCheckForQuery('notAnObject', queryResultA1)).toBe(false)
120
+ // @ts-ignore
121
+ expect(equalityCheckForQuery(queryResultA1, 'notAnObject')).toBe(false)
122
+ })
123
+
124
+ it('should return false if `id` properties are different', () => {
125
+ expect(equalityCheckForQuery(queryResultA1, queryResultB1)).toBe(false)
126
+ })
127
+
128
+ it('should return false if one or both objects lack `data`', () => {
129
+ // @ts-ignore
130
+ expect(equalityCheckForQuery({ id: 1 }, queryResultA1)).toBe(false)
131
+ // @ts-ignore
132
+ expect(equalityCheckForQuery(queryResultA1, { id: 1 })).toBe(false)
133
+ })
134
+
135
+ it('should return false if `data` lengths are different', () => {
136
+ expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false)
137
+ })
138
+
139
+ it('should return false if elements in `data` are different', () => {
140
+ expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false)
141
+ expect(equalityCheckForQuery(queryResultA3, queryResultA4)).toBe(false)
142
+ expect(equalityCheckForQuery(queryResultB1, queryResultB2)).toBe(false)
143
+ })
144
+
145
+ it('should return true for matching data array, with equal references ', () => {
146
+ expect(equalityCheckForQuery(queryResultA1, queryResultA2)).toBe(true)
147
+ })
148
+
149
+ it('should return false for matching data array, with different references ', () => {
150
+ const queryResShallowCopyA1 = {
151
+ ...queryResultA1,
152
+ storeData: JSON.parse(JSON.stringify(queryResultA1.storeData)) // Deep copy
153
+ }
154
+ expect(equalityCheckForQuery(queryResultA1, queryResShallowCopyA1)).toBe(
155
+ false
156
+ )
157
+ })
158
+
159
+ it('should return true for matching object data', () => {
160
+ expect(equalityCheckForQuery(queryResultC1, queryResultC2)).toBe(true)
161
+ })
162
+ it('should return false for different object data', () => {
163
+ expect(equalityCheckForQuery(queryResultC1, queryResultC3)).toBe(false)
164
+ })
165
+ })
166
+
167
+ describe('equalityCheckForQuery with relationships', () => {
168
+ const queryResA = {
169
+ ...defaultQueryResult,
170
+ relationshipNames: ['relation1'],
171
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
172
+ 'doc1',
173
+ 'doc2'
174
+ ]),
175
+ data: [{ relation1: { _rev: 'rev1' } }]
176
+ }
177
+
178
+ const queryResB = {
179
+ ...defaultQueryResult,
180
+ relationshipNames: ['relation1'],
181
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
182
+ 'doc1',
183
+ 'doc2'
184
+ ]),
185
+ data: [{ relation1: { _rev: 'rev2' } }]
186
+ }
187
+
188
+ const queryResC = {
189
+ ...defaultQueryResult,
190
+ relationshipNames: ['relation1'],
191
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
192
+ 'doc1',
193
+ 'doc2'
194
+ ]),
195
+ data: [{ relation1: { _rev: 'rev1' } }, { relation1: { _rev: 'rev2' } }]
196
+ }
197
+
198
+ const queryResD = {
199
+ ...defaultQueryResult,
200
+ relationshipNames: ['relation1', 'relation2'],
201
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
202
+ 'doc1',
203
+ 'doc2'
204
+ ]),
205
+ data: [{ relation1: { _rev: 'rev1' } }, { relation2: { _rev: 'rev2' } }]
206
+ }
207
+
208
+ const queryResE = {
209
+ ...defaultQueryResult,
210
+ relationshipNames: ['relation1'],
211
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1']),
212
+ data: [{ relation1: { _id: '123' } }]
213
+ }
214
+
215
+ const queryResF = {
216
+ ...defaultQueryResult,
217
+ relationshipNames: ['relation1'],
218
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1']),
219
+ data: [{ relation1: { _id: '123' } }]
220
+ }
221
+
222
+ it('returns true when data and relationship revisions match', () => {
223
+ expect(equalityCheckForQuery(queryResA, queryResA)).toBe(true)
224
+ expect(equalityCheckForQuery(queryResD, queryResD)).toBe(true)
225
+ })
226
+
227
+ it('returns false when relationship revisions differ', () => {
228
+ expect(equalityCheckForQuery(queryResA, queryResB)).toBe(false)
229
+ })
230
+
231
+ it('returns false when relationship revisions are missing', () => {
232
+ expect(equalityCheckForQuery(queryResE, queryResF)).toBe(false)
233
+ })
234
+
235
+ it('returns false when data lengths differ', () => {
236
+ expect(equalityCheckForQuery(queryResA, queryResC)).toBe(false)
237
+ })
238
+ })