cozy-client 57.2.0 → 57.4.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.
- package/dist/CozyClient.js +38 -23
- package/dist/storage.js +205 -0
- package/dist/storage.spec.js +31 -0
- package/dist/store/documents.js +59 -27
- package/dist/store/documents.spec.js +66 -52
- package/package.json +4 -2
- package/types/storage.d.ts +48 -0
- package/types/store/documents.d.ts +1 -1
package/dist/CozyClient.js
CHANGED
|
@@ -85,6 +85,8 @@ var _promiseCache = _interopRequireDefault(require("./promise-cache"));
|
|
|
85
85
|
|
|
86
86
|
var _flagshipCertification = require("./flagship-certification/flagship-certification");
|
|
87
87
|
|
|
88
|
+
var _storage = require("./storage");
|
|
89
|
+
|
|
88
90
|
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; }
|
|
89
91
|
|
|
90
92
|
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; }
|
|
@@ -1618,7 +1620,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1618
1620
|
case 2:
|
|
1619
1621
|
mainResponse = _context11.sent;
|
|
1620
1622
|
_context11.next = 5;
|
|
1621
|
-
return
|
|
1623
|
+
return (0, _storage.persistVirtualDocuments)(this, definition, mainResponse.data);
|
|
1622
1624
|
|
|
1623
1625
|
case 5:
|
|
1624
1626
|
if (definition.includes) {
|
|
@@ -1662,7 +1664,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1662
1664
|
key: "persistVirtualDocuments",
|
|
1663
1665
|
value: function () {
|
|
1664
1666
|
var _persistVirtualDocuments = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee12(definition, data) {
|
|
1665
|
-
var enforceList, enforce, _iterator5, _step5, _document;
|
|
1667
|
+
var enforceList, enforce, documentsToPersist, _iterator5, _step5, _document;
|
|
1666
1668
|
|
|
1667
1669
|
return _regenerator.default.wrap(function _callee12$(_context12) {
|
|
1668
1670
|
while (1) {
|
|
@@ -1697,52 +1699,65 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1697
1699
|
return this.persistVirtualDocument(data, enforce);
|
|
1698
1700
|
|
|
1699
1701
|
case 9:
|
|
1700
|
-
_context12.next =
|
|
1702
|
+
_context12.next = 29;
|
|
1701
1703
|
break;
|
|
1702
1704
|
|
|
1703
1705
|
case 11:
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
+
documentsToPersist = data.filter(function (document) {
|
|
1707
|
+
var _document$meta;
|
|
1708
|
+
|
|
1709
|
+
if (!document || document.cozyLocalOnly) {
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
if (!((_document$meta = document.meta) !== null && _document$meta !== void 0 && _document$meta.rev) && !document._rev || enforce) {
|
|
1714
|
+
return true;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
return false;
|
|
1718
|
+
});
|
|
1719
|
+
_iterator5 = _createForOfIteratorHelper(documentsToPersist);
|
|
1720
|
+
_context12.prev = 13;
|
|
1706
1721
|
|
|
1707
1722
|
_iterator5.s();
|
|
1708
1723
|
|
|
1709
|
-
case
|
|
1724
|
+
case 15:
|
|
1710
1725
|
if ((_step5 = _iterator5.n()).done) {
|
|
1711
|
-
_context12.next =
|
|
1726
|
+
_context12.next = 21;
|
|
1712
1727
|
break;
|
|
1713
1728
|
}
|
|
1714
1729
|
|
|
1715
1730
|
_document = _step5.value;
|
|
1716
|
-
_context12.next =
|
|
1731
|
+
_context12.next = 19;
|
|
1717
1732
|
return this.persistVirtualDocument(_document, enforce);
|
|
1718
1733
|
|
|
1719
|
-
case
|
|
1720
|
-
_context12.next =
|
|
1734
|
+
case 19:
|
|
1735
|
+
_context12.next = 15;
|
|
1721
1736
|
break;
|
|
1722
1737
|
|
|
1723
|
-
case
|
|
1724
|
-
_context12.next =
|
|
1738
|
+
case 21:
|
|
1739
|
+
_context12.next = 26;
|
|
1725
1740
|
break;
|
|
1726
1741
|
|
|
1727
|
-
case
|
|
1728
|
-
_context12.prev =
|
|
1729
|
-
_context12.t0 = _context12["catch"](
|
|
1742
|
+
case 23:
|
|
1743
|
+
_context12.prev = 23;
|
|
1744
|
+
_context12.t0 = _context12["catch"](13);
|
|
1730
1745
|
|
|
1731
1746
|
_iterator5.e(_context12.t0);
|
|
1732
1747
|
|
|
1733
|
-
case
|
|
1734
|
-
_context12.prev =
|
|
1748
|
+
case 26:
|
|
1749
|
+
_context12.prev = 26;
|
|
1735
1750
|
|
|
1736
1751
|
_iterator5.f();
|
|
1737
1752
|
|
|
1738
|
-
return _context12.finish(
|
|
1753
|
+
return _context12.finish(26);
|
|
1739
1754
|
|
|
1740
|
-
case
|
|
1755
|
+
case 29:
|
|
1741
1756
|
case "end":
|
|
1742
1757
|
return _context12.stop();
|
|
1743
1758
|
}
|
|
1744
1759
|
}
|
|
1745
|
-
}, _callee12, this, [[
|
|
1760
|
+
}, _callee12, this, [[13, 23, 26, 29]]);
|
|
1746
1761
|
}));
|
|
1747
1762
|
|
|
1748
1763
|
function persistVirtualDocuments(_x14, _x15) {
|
|
@@ -1764,7 +1779,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1764
1779
|
key: "persistVirtualDocument",
|
|
1765
1780
|
value: function () {
|
|
1766
1781
|
var _persistVirtualDocument = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee13(document, enforce) {
|
|
1767
|
-
var _document$
|
|
1782
|
+
var _document$meta2;
|
|
1768
1783
|
|
|
1769
1784
|
return _regenerator.default.wrap(function _callee13$(_context13) {
|
|
1770
1785
|
while (1) {
|
|
@@ -1778,7 +1793,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1778
1793
|
return _context13.abrupt("return");
|
|
1779
1794
|
|
|
1780
1795
|
case 2:
|
|
1781
|
-
if (!(!((_document$
|
|
1796
|
+
if (!(!((_document$meta2 = document.meta) !== null && _document$meta2 !== void 0 && _document$meta2.rev) && !document._rev || enforce)) {
|
|
1782
1797
|
_context13.next = 5;
|
|
1783
1798
|
break;
|
|
1784
1799
|
}
|
|
@@ -3097,7 +3112,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
3097
3112
|
CozyClient.hooks = CozyClient.hooks || {};
|
|
3098
3113
|
CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
|
|
3099
3114
|
|
|
3100
|
-
CozyClient.version = "57.
|
|
3115
|
+
CozyClient.version = "57.4.0";
|
|
3101
3116
|
|
|
3102
3117
|
_microee.default.mixin(CozyClient);
|
|
3103
3118
|
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.persistVirtualDocuments = exports.shouldDocumentBePersisted = exports.shouldEnforcePersist = exports.ENFORCE_LIST = void 0;
|
|
9
|
+
|
|
10
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
|
+
|
|
12
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
13
|
+
|
|
14
|
+
var _CozyClient = _interopRequireDefault(require("./CozyClient"));
|
|
15
|
+
|
|
16
|
+
var _dsl = require("./queries/dsl");
|
|
17
|
+
|
|
18
|
+
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; } } }; }
|
|
19
|
+
|
|
20
|
+
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); }
|
|
21
|
+
|
|
22
|
+
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; }
|
|
23
|
+
|
|
24
|
+
var ENFORCE_LIST = ['io.cozy.files.shortcuts'];
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {import("./types").CozyClientDocument} CozyClientDocument
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
exports.ENFORCE_LIST = ENFORCE_LIST;
|
|
30
|
+
|
|
31
|
+
var shouldEnforcePersist = function shouldEnforcePersist(definition) {
|
|
32
|
+
return ENFORCE_LIST.includes(definition.doctype);
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Whether or not a document should be locally persisted
|
|
36
|
+
*
|
|
37
|
+
* @param {CozyClientDocument} document - The document to evaluate
|
|
38
|
+
* @returns {boolean} whether or not the doc should be persisted
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
exports.shouldEnforcePersist = shouldEnforcePersist;
|
|
43
|
+
|
|
44
|
+
var shouldDocumentBePersisted = function shouldDocumentBePersisted(document) {
|
|
45
|
+
var _document$meta;
|
|
46
|
+
|
|
47
|
+
var shouldEnforce = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
48
|
+
|
|
49
|
+
if (!document || document.cozyLocalOnly) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!((_document$meta = document.meta) !== null && _document$meta !== void 0 && _document$meta.rev) && !document._rev || shouldEnforce) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Save the document or array of documents into the persisted storage (if any)
|
|
61
|
+
*
|
|
62
|
+
* @param {CozyClient} client - Cozy client instance
|
|
63
|
+
* @param {QueryDefinition} definition - The query definition
|
|
64
|
+
* @param {CozyClientDocument | Array<CozyClientDocument>} data - Document or array of documents to be saved
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
exports.shouldDocumentBePersisted = shouldDocumentBePersisted;
|
|
70
|
+
|
|
71
|
+
var persistVirtualDocuments = /*#__PURE__*/function () {
|
|
72
|
+
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(client, definition, data) {
|
|
73
|
+
var enforce, documentsToPersist, _iterator, _step, document;
|
|
74
|
+
|
|
75
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
76
|
+
while (1) {
|
|
77
|
+
switch (_context.prev = _context.next) {
|
|
78
|
+
case 0:
|
|
79
|
+
enforce = shouldEnforcePersist(definition);
|
|
80
|
+
|
|
81
|
+
if (!(definition.doctype === 'io.cozy.apps_registry')) {
|
|
82
|
+
_context.next = 5;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_context.next = 4;
|
|
87
|
+
return persistVirtualDocument(client, {
|
|
88
|
+
_type: 'io.cozy.apps_registry',
|
|
89
|
+
_id: definition.id,
|
|
90
|
+
// @ts-ignore
|
|
91
|
+
cozyPouchData: data
|
|
92
|
+
}, enforce);
|
|
93
|
+
|
|
94
|
+
case 4:
|
|
95
|
+
return _context.abrupt("return", _context.sent);
|
|
96
|
+
|
|
97
|
+
case 5:
|
|
98
|
+
if (Array.isArray(data)) {
|
|
99
|
+
_context.next = 10;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_context.next = 8;
|
|
104
|
+
return persistVirtualDocument(client, data, enforce);
|
|
105
|
+
|
|
106
|
+
case 8:
|
|
107
|
+
_context.next = 28;
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case 10:
|
|
111
|
+
documentsToPersist = data.filter(function (document) {
|
|
112
|
+
return shouldDocumentBePersisted(document, enforce);
|
|
113
|
+
});
|
|
114
|
+
_iterator = _createForOfIteratorHelper(documentsToPersist);
|
|
115
|
+
_context.prev = 12;
|
|
116
|
+
|
|
117
|
+
_iterator.s();
|
|
118
|
+
|
|
119
|
+
case 14:
|
|
120
|
+
if ((_step = _iterator.n()).done) {
|
|
121
|
+
_context.next = 20;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
document = _step.value;
|
|
126
|
+
_context.next = 18;
|
|
127
|
+
return persistVirtualDocument(client, document, enforce);
|
|
128
|
+
|
|
129
|
+
case 18:
|
|
130
|
+
_context.next = 14;
|
|
131
|
+
break;
|
|
132
|
+
|
|
133
|
+
case 20:
|
|
134
|
+
_context.next = 25;
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
case 22:
|
|
138
|
+
_context.prev = 22;
|
|
139
|
+
_context.t0 = _context["catch"](12);
|
|
140
|
+
|
|
141
|
+
_iterator.e(_context.t0);
|
|
142
|
+
|
|
143
|
+
case 25:
|
|
144
|
+
_context.prev = 25;
|
|
145
|
+
|
|
146
|
+
_iterator.f();
|
|
147
|
+
|
|
148
|
+
return _context.finish(25);
|
|
149
|
+
|
|
150
|
+
case 28:
|
|
151
|
+
case "end":
|
|
152
|
+
return _context.stop();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}, _callee, null, [[12, 22, 25, 28]]);
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
return function persistVirtualDocuments(_x, _x2, _x3) {
|
|
159
|
+
return _ref.apply(this, arguments);
|
|
160
|
+
};
|
|
161
|
+
}();
|
|
162
|
+
/**
|
|
163
|
+
* Save the document or array of documents into the persisted storage (if any)
|
|
164
|
+
*
|
|
165
|
+
* This relies on the fact that there are some "virtual" documents returned
|
|
166
|
+
* by the stack, in the sense that they are not CouchDB documents, but rather
|
|
167
|
+
* are computed on the fly by the server.
|
|
168
|
+
* To ensure we can use those documents locally, i.e. without the stack,
|
|
169
|
+
* we allow the possibility to persist them.
|
|
170
|
+
*
|
|
171
|
+
* @param {CozyClient} client - Cozy client instance
|
|
172
|
+
* @param {CozyClientDocument} document - Document to be saved
|
|
173
|
+
* @param {boolean} enforce - When true, save the document no matter its content
|
|
174
|
+
* @returns {Promise<void>}
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
exports.persistVirtualDocuments = persistVirtualDocuments;
|
|
179
|
+
|
|
180
|
+
var persistVirtualDocument = /*#__PURE__*/function () {
|
|
181
|
+
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(client, document, enforce) {
|
|
182
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
183
|
+
while (1) {
|
|
184
|
+
switch (_context2.prev = _context2.next) {
|
|
185
|
+
case 0:
|
|
186
|
+
if (!shouldDocumentBePersisted(document, enforce)) {
|
|
187
|
+
_context2.next = 3;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
_context2.next = 3;
|
|
192
|
+
return client.chain.persistCozyData(document);
|
|
193
|
+
|
|
194
|
+
case 3:
|
|
195
|
+
case "end":
|
|
196
|
+
return _context2.stop();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}, _callee2);
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
return function persistVirtualDocument(_x4, _x5, _x6) {
|
|
203
|
+
return _ref2.apply(this, arguments);
|
|
204
|
+
};
|
|
205
|
+
}();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { shouldDocumentBePersisted } from './storage'
|
|
2
|
+
|
|
3
|
+
const BASE_DOC = {
|
|
4
|
+
_id: '123',
|
|
5
|
+
name: 'saymy'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe('shouldDocumentBePersisted', () => {
|
|
9
|
+
it('should not persist a doc with cozyLocalOnly flag', () => {
|
|
10
|
+
const doc = { ...BASE_DOC, cozyLocalOnly: true }
|
|
11
|
+
expect(shouldDocumentBePersisted(doc)).toBe(false)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should not persist a doc with rev', () => {
|
|
15
|
+
const doc1 = { ...BASE_DOC, _rev: '123' }
|
|
16
|
+
expect(shouldDocumentBePersisted(doc1)).toBe(false)
|
|
17
|
+
|
|
18
|
+
const doc2 = { ...BASE_DOC, meta: { rev: '123' } }
|
|
19
|
+
expect(shouldDocumentBePersisted(doc2)).toBe(false)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should persist if we enforce it', () => {
|
|
23
|
+
const doc = { ...BASE_DOC, _rev: '123' }
|
|
24
|
+
expect(shouldDocumentBePersisted(doc, true)).toBe(true)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should persist if there is not revision', () => {
|
|
28
|
+
const doc = { ...BASE_DOC }
|
|
29
|
+
expect(shouldDocumentBePersisted(doc)).toBe(true)
|
|
30
|
+
})
|
|
31
|
+
})
|
package/dist/store/documents.js
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
-
|
|
208
|
-
|
|
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(
|
|
223
|
-
var doctype =
|
|
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',
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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.
|
|
3
|
+
"version": "57.4.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": "
|
|
77
|
+
"gitHead": "97e956957de48f36a29d0d55adf3cb0e248f0141"
|
|
76
78
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const ENFORCE_LIST: string[];
|
|
2
|
+
export function shouldEnforcePersist(definition: any): boolean;
|
|
3
|
+
export function shouldDocumentBePersisted(document: CozyClientDocument, shouldEnforce?: boolean): boolean;
|
|
4
|
+
export function persistVirtualDocuments(client: CozyClient, definition: QueryDefinition, data: CozyClientDocument | Array<CozyClientDocument>): Promise<void>;
|
|
5
|
+
export type CozyClientDocument = {
|
|
6
|
+
/**
|
|
7
|
+
* - Id of the document
|
|
8
|
+
*/
|
|
9
|
+
_id?: string;
|
|
10
|
+
/**
|
|
11
|
+
* - Id of the document
|
|
12
|
+
*/
|
|
13
|
+
id?: string;
|
|
14
|
+
/**
|
|
15
|
+
* - Type of the document
|
|
16
|
+
*/
|
|
17
|
+
_type?: string;
|
|
18
|
+
/**
|
|
19
|
+
* - Current revision of the document
|
|
20
|
+
*/
|
|
21
|
+
_rev?: string;
|
|
22
|
+
/**
|
|
23
|
+
* - When the document has been deleted
|
|
24
|
+
*/
|
|
25
|
+
_deleted?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* - Relationships of the document
|
|
28
|
+
*/
|
|
29
|
+
relationships?: import("./types").ReferencedByRelationship;
|
|
30
|
+
/**
|
|
31
|
+
* - referenced by of another document
|
|
32
|
+
*/
|
|
33
|
+
referenced_by?: import("./types").Reference[];
|
|
34
|
+
/**
|
|
35
|
+
* - Cozy Metadata
|
|
36
|
+
*/
|
|
37
|
+
cozyMetadata?: import("./types").CozyMetadata;
|
|
38
|
+
/**
|
|
39
|
+
* - Pouch Metadata
|
|
40
|
+
*/
|
|
41
|
+
meta?: import("./types").CozyClientDocumentMeta;
|
|
42
|
+
/**
|
|
43
|
+
* - When true the document should NOT be replicated to the remote database
|
|
44
|
+
*/
|
|
45
|
+
cozyLocalOnly?: boolean;
|
|
46
|
+
};
|
|
47
|
+
import CozyClient from "./CozyClient";
|
|
48
|
+
import { QueryDefinition } from "./queries/dsl";
|
|
@@ -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(
|
|
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;
|