cozy-client 60.29.0 → 60.30.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.
@@ -3126,7 +3126,7 @@ var CozyClient = /*#__PURE__*/function () {
3126
3126
  CozyClient.hooks = CozyClient.hooks || {};
3127
3127
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
3128
3128
 
3129
- CozyClient.version = "60.29.0";
3129
+ CozyClient.version = "60.30.0";
3130
3130
 
3131
3131
  _microee.default.mixin(CozyClient);
3132
3132
 
@@ -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.mapIdsToDocuments = exports.resetQuery = exports.receiveQueryError = exports.receiveQueryResult = exports.loadQuery = exports.initQuery = exports.default = exports.updateData = exports.makeSorterFromDefinition = exports.executeQueryFromState = exports.mergeSelectorAndPartialIndex = exports.convert$gtNullSelectors = exports.sortAndLimitDocsIds = exports.isReceivingData = exports.isQueryAction = void 0;
8
+ exports.QueryIDGenerator = exports.getQueryFromSlice = exports.mapIdsToDocuments = exports.resetQuery = exports.receiveQueryError = exports.receiveQueryResult = exports.loadQuery = exports.initQuery = exports.default = exports.updateData = exports.computeMatchPartition = exports.makeSorterFromDefinition = exports.executeQueryFromState = 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
 
@@ -53,6 +53,12 @@ var _logger = _interopRequireDefault(require("../logger"));
53
53
 
54
54
  var _stateHelpers = require("./stateHelpers");
55
55
 
56
+ 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; } } }; }
57
+
58
+ 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); }
59
+
60
+ 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; }
61
+
56
62
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
57
63
 
58
64
  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; }
@@ -497,6 +503,104 @@ var makeSorterFromDefinition = function makeSorterFromDefinition(definition) {
497
503
  };
498
504
  }
499
505
  };
506
+
507
+ exports.makeSorterFromDefinition = makeSorterFromDefinition;
508
+ var dedupNewData = null;
509
+ var dedupCache = null;
510
+ var dedupIdIndex = null;
511
+
512
+ var makeDefinitionKey = function makeDefinitionKey(def) {
513
+ return JSON.stringify([def.doctype, def.selector, def.partialFilter, def.id, def.ids]);
514
+ };
515
+
516
+ var getDedupIdIndex = function getDedupIdIndex(newData) {
517
+ if (dedupIdIndex) return dedupIdIndex;
518
+ var idx = new Map();
519
+
520
+ var _iterator = _createForOfIteratorHelper(newData),
521
+ _step;
522
+
523
+ try {
524
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
525
+ var doc = _step.value;
526
+ if (doc && doc._id != null) idx.set(doc._id, doc);
527
+ }
528
+ } catch (err) {
529
+ _iterator.e(err);
530
+ } finally {
531
+ _iterator.f();
532
+ }
533
+
534
+ dedupIdIndex = idx;
535
+ return idx;
536
+ };
537
+ /**
538
+ * Splits `newData` into the ids matching a query definition and the ids that do not
539
+ *
540
+ * @param {QueryDefinition} definition - Definition of the query
541
+ * @param {Array<import("../types").CozyClientDocument>} newData - New documents
542
+ * @returns {{ matchedIds: Array<string>, unmatchedIds: Array<string> }}
543
+ */
544
+
545
+
546
+ var computeMatchPartition = function computeMatchPartition(definition, newData) {
547
+ if (dedupNewData !== newData) {
548
+ dedupNewData = newData;
549
+ dedupCache = {};
550
+ dedupIdIndex = null;
551
+ }
552
+
553
+ var key = makeDefinitionKey(definition);
554
+ var cached = dedupCache[key];
555
+ if (cached) return cached;
556
+ var partition;
557
+
558
+ if (definition.id || definition.ids) {
559
+ var idx = getDedupIdIndex(newData);
560
+ var wanted = definition.id ? [definition.id] : definition.ids;
561
+ var matchedIds = [];
562
+ var unmatchedIds = [];
563
+
564
+ var _iterator2 = _createForOfIteratorHelper(wanted),
565
+ _step2;
566
+
567
+ try {
568
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
569
+ var id = _step2.value;
570
+ var doc = idx.get(id);
571
+
572
+ if (doc) {
573
+ if (!doc._deleted && doc._type === definition.doctype) {
574
+ matchedIds.push((0, _helpers.properId)(doc));
575
+ } else {
576
+ unmatchedIds.push((0, _helpers.properId)(doc));
577
+ }
578
+ }
579
+ }
580
+ } catch (err) {
581
+ _iterator2.e(err);
582
+ } finally {
583
+ _iterator2.f();
584
+ }
585
+
586
+ partition = {
587
+ matchedIds: matchedIds,
588
+ unmatchedIds: unmatchedIds
589
+ };
590
+ } else {
591
+ var belongsToQuery = makeFilterDocumentFn(definition);
592
+ var res = (0, _mapValues.default)((0, _groupBy.default)(newData, belongsToQuery), function (docs) {
593
+ return docs.map(_helpers.properId);
594
+ });
595
+ partition = {
596
+ matchedIds: res.true === undefined ? [] : res.true,
597
+ unmatchedIds: res.false === undefined ? [] : res.false
598
+ };
599
+ }
600
+
601
+ dedupCache[key] = partition;
602
+ return partition;
603
+ };
500
604
  /**
501
605
  * Updates query state when new data comes in
502
606
  *
@@ -507,17 +611,13 @@ var makeSorterFromDefinition = function makeSorterFromDefinition(definition) {
507
611
  */
508
612
 
509
613
 
510
- exports.makeSorterFromDefinition = makeSorterFromDefinition;
614
+ exports.computeMatchPartition = computeMatchPartition;
511
615
 
512
616
  var updateData = function updateData(query, newData, documents) {
513
- var belongsToQuery = makeFilterDocumentFn(query.definition);
514
- var res = (0, _mapValues.default)((0, _groupBy.default)(newData, belongsToQuery), function (docs) {
515
- return docs.map(_helpers.properId);
516
- });
517
- var _res$true = res.true,
518
- matchedIds = _res$true === void 0 ? [] : _res$true,
519
- _res$false = res.false,
520
- unmatchedIds = _res$false === void 0 ? [] : _res$false;
617
+ var _computeMatchPartitio = computeMatchPartition(query.definition, newData),
618
+ matchedIds = _computeMatchPartitio.matchedIds,
619
+ unmatchedIds = _computeMatchPartitio.unmatchedIds;
620
+
521
621
  var originalIds = query.data;
522
622
  var autoUpdate = query.options && query.options.autoUpdate;
523
623
  var shouldRemove = !autoUpdate || autoUpdate.remove !== false;
@@ -9,6 +9,7 @@ import queries, {
9
9
  loadQuery,
10
10
  receiveQueryError,
11
11
  updateData,
12
+ computeMatchPartition,
12
13
  executeQueryFromState,
13
14
  mapIdsToDocuments
14
15
  } from './queries'
@@ -675,6 +676,64 @@ describe('updateData', () => {
675
676
  })
676
677
  })
677
678
 
679
+ describe('computeMatchPartition', () => {
680
+ it('should resolve a getById query without scanning the whole newData', () => {
681
+ const newData = [TODO_1, TODO_2, TODO_3]
682
+ const definition = Q('io.cozy.todos').getById(TODO_2._id)
683
+ const { matchedIds, unmatchedIds } = computeMatchPartition(
684
+ definition,
685
+ newData
686
+ )
687
+ expect(matchedIds).toEqual([TODO_2._id])
688
+ expect(unmatchedIds).toEqual([])
689
+ })
690
+
691
+ it('should not match a getById query for a missing or wrong-doctype id', () => {
692
+ const newData = [TODO_1, { ...TODO_2, _type: 'io.cozy.other' }]
693
+ expect(
694
+ computeMatchPartition(Q('io.cozy.todos').getById('missing'), newData)
695
+ ).toEqual({ matchedIds: [], unmatchedIds: [] })
696
+ expect(
697
+ computeMatchPartition(Q('io.cozy.todos').getById(TODO_2._id), newData)
698
+ ).toEqual({ matchedIds: [], unmatchedIds: [TODO_2._id] })
699
+ })
700
+
701
+ it('should treat a deleted document as unmatched for a getById query', () => {
702
+ const newData = [{ ...TODO_1, _deleted: true }]
703
+ expect(
704
+ computeMatchPartition(Q('io.cozy.todos').getById(TODO_1._id), newData)
705
+ ).toEqual({ matchedIds: [], unmatchedIds: [TODO_1._id] })
706
+ })
707
+
708
+ it('should resolve a getByIds query', () => {
709
+ const newData = [TODO_1, TODO_2, TODO_3]
710
+ const definition = Q('io.cozy.todos').getByIds([TODO_1._id, 'missing'])
711
+ expect(computeMatchPartition(definition, newData)).toEqual({
712
+ matchedIds: [TODO_1._id],
713
+ unmatchedIds: []
714
+ })
715
+ })
716
+
717
+ it('should partition a selector query with the sift scan', () => {
718
+ const newData = [TODO_1, TODO_2, TODO_3]
719
+ const definition = Q('io.cozy.todos').where({ done: true })
720
+ const { matchedIds, unmatchedIds } = computeMatchPartition(
721
+ definition,
722
+ newData
723
+ )
724
+ expect(matchedIds).toEqual([TODO_3._id])
725
+ expect(unmatchedIds.sort()).toEqual([TODO_1._id, TODO_2._id].sort())
726
+ })
727
+
728
+ it('should memoize the partition per definition within the same newData', () => {
729
+ const newData = [TODO_1, TODO_2]
730
+ const definition = Q('io.cozy.todos').getById(TODO_1._id)
731
+ const first = computeMatchPartition(definition, newData)
732
+ const second = computeMatchPartition(definition, newData)
733
+ expect(second).toBe(first)
734
+ })
735
+ })
736
+
678
737
  describe('execute query from state', () => {
679
738
  const docState = {
680
739
  'io.cozy.files': {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "60.29.0",
3
+ "version": "60.30.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -74,5 +74,5 @@
74
74
  "react-native-ios11-devicecheck": "^0.0.3"
75
75
  },
76
76
  "sideEffects": false,
77
- "gitHead": "0e624ae6b3ba93c2618ba9d26f4d4f48945bf5c8"
77
+ "gitHead": "7f9e5753cc1e0b1e1a46e983ec1a556c516a0fc2"
78
78
  }
@@ -8,6 +8,10 @@ export function convert$gtNullSelectors(selector: any): object;
8
8
  export function mergeSelectorAndPartialIndex(queryDefinition: object): object;
9
9
  export function executeQueryFromState(state: import('../types').CozyStore, queryDefinition: QueryDefinition): import("../types").QueryStateData;
10
10
  export function makeSorterFromDefinition(definition: QueryDefinition): (arg0: Array<import("../types").CozyClientDocument>) => Array<import("../types").CozyClientDocument>;
11
+ export function computeMatchPartition(definition: QueryDefinition, newData: Array<import("../types").CozyClientDocument>): {
12
+ matchedIds: Array<string>;
13
+ unmatchedIds: Array<string>;
14
+ };
11
15
  export function updateData(query: import("../types").QueryState, newData: Array<import("../types").CozyClientDocument>, documents: import("../types").DocumentsStateSlice): import("../types").QueryState;
12
16
  export default queries;
13
17
  export function initQuery(queryId: string, queryDefinition: QueryDefinition, options?: import("../types").QueryOptions): object;