cozy-client 31.0.1 → 32.0.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.
@@ -2550,7 +2550,7 @@ var CozyClient = /*#__PURE__*/function () {
2550
2550
  CozyClient.hooks = CozyClient.hooks || {};
2551
2551
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
2552
2552
 
2553
- CozyClient.version = "31.0.1";
2553
+ CozyClient.version = "32.0.0";
2554
2554
 
2555
2555
  _microee.default.mixin(CozyClient);
2556
2556
 
@@ -184,6 +184,7 @@ describe('Query', () => {
184
184
  {
185
185
  bookmark: null,
186
186
  count: 0,
187
+ fetchedPagesCount: 0,
187
188
  data: [],
188
189
  definition: { doctype: 'io.cozy.todos' },
189
190
  fetch: expect.any(Function),
@@ -84,6 +84,7 @@ describe('use query', () => {
84
84
  'lastError',
85
85
  'hasMore',
86
86
  'count',
87
+ 'fetchedPagesCount',
87
88
  'data',
88
89
  'bookmark',
89
90
  'options',
@@ -23,6 +23,7 @@ Object {
23
23
  "sort": undefined,
24
24
  },
25
25
  "fetchStatus": "pending",
26
+ "fetchedPagesCount": 0,
26
27
  "hasMore": false,
27
28
  "id": "a",
28
29
  "lastError": null,
@@ -60,6 +61,7 @@ Object {
60
61
  "sort": undefined,
61
62
  },
62
63
  "fetchStatus": "loaded",
64
+ "fetchedPagesCount": 1,
63
65
  "hasMore": false,
64
66
  "id": "a",
65
67
  "lastError": null,
@@ -96,6 +98,7 @@ Object {
96
98
  "sort": undefined,
97
99
  },
98
100
  "fetchStatus": "loaded",
101
+ "fetchedPagesCount": 1,
99
102
  "hasMore": false,
100
103
  "id": "a",
101
104
  "lastError": null,
@@ -132,6 +135,7 @@ Object {
132
135
  "sort": undefined,
133
136
  },
134
137
  "fetchStatus": "pending",
138
+ "fetchedPagesCount": 0,
135
139
  "hasMore": false,
136
140
  "id": "b",
137
141
  "lastError": null,
@@ -168,6 +172,7 @@ Object {
168
172
  "sort": undefined,
169
173
  },
170
174
  "fetchStatus": "loaded",
175
+ "fetchedPagesCount": 1,
171
176
  "hasMore": false,
172
177
  "id": "a",
173
178
  "lastError": null,
@@ -201,6 +206,7 @@ Object {
201
206
  "sort": undefined,
202
207
  },
203
208
  "fetchStatus": "pending",
209
+ "fetchedPagesCount": 0,
204
210
  "hasMore": false,
205
211
  "id": "b",
206
212
  "lastError": null,
@@ -243,6 +249,7 @@ Object {
243
249
  ],
244
250
  },
245
251
  "fetchStatus": "loaded",
252
+ "fetchedPagesCount": 1,
246
253
  "hasMore": false,
247
254
  "id": "a",
248
255
  "lastError": null,
@@ -274,6 +281,7 @@ Object {
274
281
  "sort": undefined,
275
282
  },
276
283
  "fetchStatus": "pending",
284
+ "fetchedPagesCount": 0,
277
285
  "hasMore": false,
278
286
  "id": "b",
279
287
  "lastError": null,
@@ -311,6 +319,7 @@ Object {
311
319
  "sort": undefined,
312
320
  },
313
321
  "fetchStatus": "loaded",
322
+ "fetchedPagesCount": 1,
314
323
  "hasMore": false,
315
324
  "id": "a",
316
325
  "lastError": null,
@@ -343,6 +352,7 @@ Object {
343
352
  "sort": undefined,
344
353
  },
345
354
  "fetchStatus": "pending",
355
+ "fetchedPagesCount": 0,
346
356
  "hasMore": false,
347
357
  "id": "b",
348
358
  "lastError": null,
@@ -379,6 +389,7 @@ Object {
379
389
  "sort": undefined,
380
390
  },
381
391
  "fetchStatus": "loaded",
392
+ "fetchedPagesCount": 1,
382
393
  "hasMore": false,
383
394
  "id": "a",
384
395
  "lastError": null,
@@ -410,6 +421,7 @@ Object {
410
421
  "sort": undefined,
411
422
  },
412
423
  "fetchStatus": "pending",
424
+ "fetchedPagesCount": 0,
413
425
  "hasMore": false,
414
426
  "id": "b",
415
427
  "lastError": null,
@@ -448,6 +460,7 @@ Object {
448
460
  "sort": undefined,
449
461
  },
450
462
  "fetchStatus": "pending",
463
+ "fetchedPagesCount": 0,
451
464
  "hasMore": false,
452
465
  "id": "a",
453
466
  "lastError": null,
@@ -477,6 +490,7 @@ Object {
477
490
  "sort": undefined,
478
491
  },
479
492
  "fetchStatus": "pending",
493
+ "fetchedPagesCount": 0,
480
494
  "hasMore": false,
481
495
  "id": "b",
482
496
  "lastError": null,
@@ -513,6 +527,7 @@ Object {
513
527
  "sort": undefined,
514
528
  },
515
529
  "fetchStatus": "loaded",
530
+ "fetchedPagesCount": 2,
516
531
  "hasMore": false,
517
532
  "id": "a",
518
533
  "lastError": null,
@@ -546,6 +561,7 @@ Object {
546
561
  "sort": undefined,
547
562
  },
548
563
  "fetchStatus": "pending",
564
+ "fetchedPagesCount": 0,
549
565
  "hasMore": false,
550
566
  "id": "b",
551
567
  "lastError": null,
@@ -586,6 +602,7 @@ Object {
586
602
  "sort": undefined,
587
603
  },
588
604
  "fetchStatus": "loaded",
605
+ "fetchedPagesCount": 1,
589
606
  "hasMore": false,
590
607
  "id": "a",
591
608
  "lastError": null,
@@ -617,6 +634,7 @@ Object {
617
634
  "sort": undefined,
618
635
  },
619
636
  "fetchStatus": "pending",
637
+ "fetchedPagesCount": 0,
620
638
  "hasMore": false,
621
639
  "id": "b",
622
640
  "lastError": null,
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.QueryIDGenerator = exports.getQueryFromSlice = exports.receiveQueryError = exports.receiveQueryResult = exports.loadQuery = exports.initQuery = exports.default = exports.makeSorterFromDefinition = exports.mergeSelectorAndPartialIndex = exports.convert$gtNullSelectors = exports.isReceivingData = exports.isQueryAction = void 0;
8
+ exports.QueryIDGenerator = exports.getQueryFromSlice = exports.receiveQueryError = exports.receiveQueryResult = exports.loadQuery = exports.initQuery = exports.default = exports.makeSorterFromDefinition = exports.mergeSelectorAndPartialIndex = exports.convert$gtNullSelectors = exports.sortAndLimitDocsIds = exports.isReceivingData = exports.isQueryAction = void 0;
9
9
 
10
10
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
11
 
@@ -90,25 +90,65 @@ var queryInitialState = {
90
90
  lastError: null,
91
91
  hasMore: false,
92
92
  count: 0,
93
+ fetchedPagesCount: 0,
93
94
  data: [],
94
95
  bookmark: null
95
96
  };
97
+ /**
98
+ * Return the docs ids accordingly to the given sort and fetched docs
99
+ *
100
+ * @param {QueryState} queryState - Current state
101
+ * @param {DocumentsStateSlice} documents - Reference to the documents slice
102
+ * @param {Array<string>} ids - The updated ids after query
103
+ * @param {object} params - The additional params
104
+ * @param {number} params.count - The count of retrieved docs
105
+ * @param {number} params.fetchedPagesCount - The number of pages already fetched
106
+ * @returns {Array<string>} The list of sorted ids
107
+ */
96
108
 
97
- var updateQueryDataFromResponse = function updateQueryDataFromResponse(queryState, response, documents) {
98
- var updatedIds = (0, _uniq.default)([].concat((0, _toConsumableArray2.default)(queryState.data), (0, _toConsumableArray2.default)(response.data.map(_helpers.properId))));
109
+ var sortAndLimitDocsIds = function sortAndLimitDocsIds(queryState, documents, ids, _ref) {
110
+ var count = _ref.count,
111
+ fetchedPagesCount = _ref.fetchedPagesCount;
112
+ var evaluatedIds = (0, _toConsumableArray2.default)(ids);
99
113
 
100
- if (queryState.definition.sort) {
114
+ if (queryState.definition.sort && documents) {
101
115
  var sorter = makeSorterFromDefinition(queryState.definition);
102
- var doctype = queryState.definition.doctype;
103
- var allDocs = documents[doctype];
104
- var docs = allDocs ? updatedIds.map(function (_id) {
116
+ var allDocs = documents[queryState.definition.doctype];
117
+ var docs = allDocs ? evaluatedIds.map(function (_id) {
105
118
  return allDocs[_id];
106
119
  }).filter(Boolean) : [];
107
- var sortedDocs = sorter(docs);
108
- updatedIds = sortedDocs.map(_helpers.properId);
120
+ evaluatedIds = sorter(docs).map(_helpers.properId);
121
+ }
122
+
123
+ if (queryState.definition.limit) {
124
+ evaluatedIds = queryState.definition.limit ? evaluatedIds.slice(0, count * fetchedPagesCount) : evaluatedIds;
109
125
  }
110
126
 
111
- return updatedIds;
127
+ return evaluatedIds;
128
+ };
129
+ /**
130
+ * Return the query docs ids, taken from the action response and the documents' slice
131
+ *
132
+ * @param {QueryState} queryState - Current state
133
+ * @param {object} response - The action response
134
+ * @param {DocumentsStateSlice} documents - Reference to the documents slice
135
+ * @param {object} params - The additional params
136
+ * @param {number} params.count - The count of retrieved docs
137
+ * @param {number} params.fetchedPagesCount - The number of pages already fetched
138
+ * @returns {Array<string>} The list of sorted ids
139
+ */
140
+
141
+
142
+ exports.sortAndLimitDocsIds = sortAndLimitDocsIds;
143
+
144
+ var updateQueryDataFromResponse = function updateQueryDataFromResponse(queryState, response, documents, _ref2) {
145
+ var count = _ref2.count,
146
+ fetchedPagesCount = _ref2.fetchedPagesCount;
147
+ var updatedIds = (0, _uniq.default)([].concat((0, _toConsumableArray2.default)(queryState.data), (0, _toConsumableArray2.default)(response.data.map(_helpers.properId))));
148
+ return sortAndLimitDocsIds(queryState, documents, updatedIds, {
149
+ count: count,
150
+ fetchedPagesCount: fetchedPagesCount
151
+ });
112
152
  };
113
153
  /**
114
154
  * Reducer for a query slice
@@ -177,11 +217,18 @@ var query = function query() {
177
217
  });
178
218
  }
179
219
 
220
+ var count = response.meta && response.meta.count ? response.meta.count : response.data.length;
221
+ var fetchedPagesCount = state.fetchedPagesCount + 1;
222
+ var data = updateQueryDataFromResponse(state, response, documents, {
223
+ count: count,
224
+ fetchedPagesCount: fetchedPagesCount
225
+ });
180
226
  return _objectSpread(_objectSpread(_objectSpread({}, state), common), {}, {
181
227
  bookmark: response.bookmark || null,
182
228
  hasMore: response.next !== undefined ? response.next : state.hasMore,
183
- count: response.meta && response.meta.count ? response.meta.count : response.data.length,
184
- data: updateQueryDataFromResponse(state, response, documents)
229
+ count: count,
230
+ fetchedPagesCount: fetchedPagesCount,
231
+ data: data
185
232
  });
186
233
  }
187
234
 
@@ -371,20 +418,16 @@ var updateData = function updateData(query, newData, documents) {
371
418
  // It is also faster than union.
372
419
 
373
420
  var updatedData = (0, _difference.default)((0, _concat.default)(originalIds, toAdd), toRemove);
374
-
375
- if (query.definition.sort && documents) {
376
- var sorter = makeSorterFromDefinition(query.definition);
377
- var allDocs = documents[query.definition.doctype];
378
- var docs = updatedData.map(function (_id) {
379
- return allDocs[_id];
380
- });
381
- var sortedDocs = sorter(docs);
382
- updatedData = sortedDocs.map(_helpers.properId);
383
- }
384
-
421
+ var count = query.count,
422
+ fetchedPagesCount = query.fetchedPagesCount;
423
+ var docsIds = sortAndLimitDocsIds(query, documents, updatedData, {
424
+ count: count,
425
+ fetchedPagesCount: fetchedPagesCount
426
+ });
385
427
  return _objectSpread(_objectSpread({}, query), {}, {
386
- data: updatedData,
428
+ data: docsIds,
387
429
  count: updatedData.length,
430
+ fetchedPagesCount: fetchedPagesCount,
388
431
  lastUpdate: changed ? Date.now() : query.lastUpdate
389
432
  });
390
433
  };
@@ -3,7 +3,8 @@ import queries, {
3
3
  receiveQueryResult,
4
4
  convert$gtNullSelectors,
5
5
  makeSorterFromDefinition,
6
- mergeSelectorAndPartialIndex
6
+ mergeSelectorAndPartialIndex,
7
+ sortAndLimitDocsIds
7
8
  } from './queries'
8
9
  import { Q } from '../queries/dsl'
9
10
  import { TODO_1, TODO_2, TODO_3 } from '../__tests__/fixtures'
@@ -332,3 +333,98 @@ describe('mergeSelectorAndPartialIndex', () => {
332
333
  expect(mergeSelectorAndPartialIndex(query)).toMatchObject(result)
333
334
  })
334
335
  })
336
+
337
+ describe('sortAndLimitDocsIds', () => {
338
+ const docs = {
339
+ 'io.cozy.files': {
340
+ doc1: {
341
+ _id: 'doc1',
342
+ name: 'toto'
343
+ },
344
+ doc2: {
345
+ _id: 'doc2',
346
+ name: 'tata'
347
+ },
348
+ doc3: {
349
+ _id: 'doc3',
350
+ name: 'tutu'
351
+ },
352
+ doc4: {
353
+ _id: 'doc4',
354
+ name: 'tutu'
355
+ }
356
+ }
357
+ }
358
+ it('should return ids as is, when no sort', () => {
359
+ const query = Q('io.cozy.files')
360
+ const ids = sortAndLimitDocsIds(
361
+ { definition: query.toDefinition() },
362
+ docs,
363
+ ['doc1', 'doc2', 'doc3'],
364
+ {
365
+ count: 0,
366
+ fetchedPagesCount: 0
367
+ }
368
+ )
369
+ expect(ids).toEqual(['doc1', 'doc2', 'doc3'])
370
+ })
371
+ it('should return ids as is, when no documents in the documents slice', () => {
372
+ const query = Q('io.cozy.files').sortBy([{ name: 'asc' }])
373
+
374
+ const ids = sortAndLimitDocsIds(
375
+ { definition: query.toDefinition() },
376
+ null,
377
+ ['doc1', 'doc2', 'doc3'],
378
+ {
379
+ count: 0,
380
+ fetchedPagesCount: 0
381
+ }
382
+ )
383
+ expect(ids).toEqual(['doc1', 'doc2', 'doc3'])
384
+ })
385
+ it('should return sorted ids', () => {
386
+ const query = Q('io.cozy.files').sortBy([{ name: 'asc' }])
387
+
388
+ const ids = sortAndLimitDocsIds(
389
+ { definition: query.toDefinition() },
390
+ docs,
391
+ ['doc1', 'doc2', 'doc3'],
392
+ {
393
+ count: 3,
394
+ fetchedPagesCount: 1
395
+ }
396
+ )
397
+ expect(ids).toEqual(['doc2', 'doc1', 'doc3'])
398
+ })
399
+ it('should return sorted ids, accordingly to limitBy', () => {
400
+ const query1 = Q('io.cozy.files')
401
+ .sortBy([{ name: 'asc' }])
402
+ .limitBy(2)
403
+
404
+ const ids1 = sortAndLimitDocsIds(
405
+ { definition: query1.toDefinition() },
406
+ docs,
407
+ ['doc1', 'doc2', 'doc3'],
408
+ {
409
+ count: 2,
410
+ fetchedPagesCount: 1
411
+ }
412
+ )
413
+ expect(ids1).toEqual(['doc2', 'doc1'])
414
+
415
+ const query2 = Q('io.cozy.files')
416
+ .sortBy([{ name: 'asc' }])
417
+ .limitBy(1)
418
+
419
+ const ids2 = sortAndLimitDocsIds(
420
+ { definition: query2.toDefinition() },
421
+ docs,
422
+ ['doc1', 'doc2', 'doc3'],
423
+ {
424
+ count: 1,
425
+ fetchedPagesCount: 2
426
+ }
427
+ )
428
+ expect(ids2).toEqual(['doc2', 'doc1'])
429
+ })
430
+ })
@@ -230,6 +230,83 @@ describe('Store', () => {
230
230
  ).toBe(FILE_1.label)
231
231
  })
232
232
 
233
+ it('should respect the query limit', () => {
234
+ const query = new Q({
235
+ doctype: 'io.cozy.todos',
236
+ limit: 2
237
+ })
238
+ let queryResult
239
+ store.dispatch(initQuery('Q1', query))
240
+ store.dispatch(initQuery('Q2', query.offset(2)))
241
+ store.dispatch(
242
+ receiveQueryResult('Q1', {
243
+ data: [TODO_1, TODO_2]
244
+ })
245
+ )
246
+ store.dispatch(
247
+ receiveQueryResult('Q2', {
248
+ data: [TODO_3, TODO_4]
249
+ })
250
+ )
251
+ // There are now 4 docs in the store
252
+ expect(
253
+ Object.keys(store.getState().cozy.documents['io.cozy.todos']).length
254
+ ).toBe(4)
255
+ // Q1 and Q2 only returns 2 todos because of the limit
256
+ queryResult = getQueryFromStore(store, 'Q1')
257
+ expect(queryResult.data.length).toBe(2)
258
+ expect(queryResult.data.map(x => x._id)).toEqual(['todo_1', 'todo_2'])
259
+ queryResult = getQueryFromStore(store, 'Q2')
260
+ expect(queryResult.data.length).toBe(2)
261
+ expect(queryResult.data.map(x => x._id)).toEqual(['todo_3', 'todo_4'])
262
+ })
263
+
264
+ it('should respect the query limit with sort', () => {
265
+ const query = new Q({
266
+ doctype: 'io.cozy.todos',
267
+ limit: 2
268
+ })
269
+ let queryResult
270
+ store.dispatch(initQuery('Q1', query.sortBy([{ label: 'asc' }])))
271
+ store.dispatch(initQuery('Q2', query.sortBy([{ label: 'desc' }])))
272
+
273
+ // Labels' ascending order, as defined in fixtures: TODO_3, TODO_1, TODO_4, TODO_2
274
+ store.dispatch(
275
+ receiveQueryResult('Q2', {
276
+ data: [TODO_2, TODO_4]
277
+ })
278
+ )
279
+ store.dispatch(
280
+ receiveQueryResult('Q1', {
281
+ data: [TODO_3, TODO_1]
282
+ })
283
+ )
284
+
285
+ // There are now 4 docs in the store, ordered by their query arrival
286
+ const todosInStore = store.getState().cozy.documents['io.cozy.todos']
287
+ expect(Object.values(todosInStore)).toEqual([
288
+ TODO_2,
289
+ TODO_4,
290
+ TODO_3,
291
+ TODO_1
292
+ ])
293
+ // Q1 and Q2 retrieves the todos sorted by label, thanks to the sort in the store
294
+ queryResult = getQueryFromStore(store, 'Q1')
295
+ expect(
296
+ queryResult.data.map(x => ({ _id: x._id, label: x.label }))
297
+ ).toEqual([
298
+ { _id: 'todo_3', label: 'Build stuff' },
299
+ { _id: 'todo_1', label: 'Buy bread' }
300
+ ])
301
+ queryResult = getQueryFromStore(store, 'Q2')
302
+ expect(
303
+ queryResult.data.map(x => ({ _id: x._id, label: x.label }))
304
+ ).toEqual([
305
+ { _id: 'todo_4', label: 'Run a semi-marathon' },
306
+ { _id: 'todo_2', label: 'Check email' }
307
+ ])
308
+ })
309
+
233
310
  describe('deletion', () => {
234
311
  let originalWarn
235
312
  beforeEach(() => {
@@ -326,6 +403,7 @@ describe('Store', () => {
326
403
  lastErrorUpdate: null,
327
404
  hasMore: false,
328
405
  count: 0,
406
+ fetchedPagesCount: 0,
329
407
  data: null
330
408
  })
331
409
  })
package/dist/types.js CHANGED
@@ -67,6 +67,7 @@ var _dsl = require("./queries/dsl");
67
67
  * @property {Error} lastError
68
68
  * @property {boolean} hasMore
69
69
  * @property {number} count
70
+ * @property {number} fetchedPagesCount
70
71
  * @property {object|Array} data
71
72
  * @property {string} bookmark
72
73
  * @property {object} [execution_stats]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "31.0.1",
3
+ "version": "32.0.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "@types/jest": "^26.0.20",
19
19
  "@types/lodash": "^4.14.170",
20
20
  "btoa": "^1.2.1",
21
- "cozy-stack-client": "^31.0.0",
21
+ "cozy-stack-client": "^32.0.0",
22
22
  "json-stable-stringify": "^1.0.1",
23
23
  "lodash": "^4.17.13",
24
24
  "microee": "^0.0.6",
@@ -73,5 +73,5 @@
73
73
  "react-native-ios11-devicecheck": "https://github.com/cozy/react-native-devicecheck#app-attest-v0.1"
74
74
  },
75
75
  "sideEffects": false,
76
- "gitHead": "e989cf8c1f026696b4bf0720f3161067f1166d8b"
76
+ "gitHead": "d289d3676de1de89d0ff38d659c188319e73c16f"
77
77
  }
@@ -1,5 +1,9 @@
1
1
  export function isQueryAction(action: any): boolean;
2
2
  export function isReceivingData(action: any): boolean;
3
+ export function sortAndLimitDocsIds(queryState: QueryState, documents: DocumentsStateSlice, ids: Array<string>, { count, fetchedPagesCount }: {
4
+ count: number;
5
+ fetchedPagesCount: number;
6
+ }): Array<string>;
3
7
  export function convert$gtNullSelectors(selector: any): object;
4
8
  export function mergeSelectorAndPartialIndex(queryDefinition: object): object;
5
9
  export function makeSorterFromDefinition(definition: QueryDefinition): (arg0: Array<CozyClientDocument>) => Array<CozyClientDocument>;
@@ -46,6 +50,8 @@ export class QueryIDGenerator {
46
50
  export namespace QueryIDGenerator {
47
51
  const UNNAMED: string;
48
52
  }
53
+ import { QueryState } from "../types";
54
+ import { DocumentsStateSlice } from "../types";
49
55
  import { QueryDefinition } from "../queries/dsl";
50
56
  import { CozyClientDocument } from "../types";
51
57
  /**
@@ -58,4 +64,3 @@ import { CozyClientDocument } from "../types";
58
64
  declare function queries(state: QueriesStateSlice, action: object, documents?: DocumentsStateSlice, haveDocumentsChanged?: boolean): QueriesStateSlice;
59
65
  import { QueryOptions } from "../types";
60
66
  import { QueriesStateSlice } from "../types";
61
- import { DocumentsStateSlice } from "../types";
package/types/types.d.ts CHANGED
@@ -41,6 +41,7 @@ export type QueryState = {
41
41
  lastError: Error;
42
42
  hasMore: boolean;
43
43
  count: number;
44
+ fetchedPagesCount: number;
44
45
  data: object | any[];
45
46
  bookmark: string;
46
47
  execution_stats?: object;