cozy-client 60.28.2 → 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.
- package/dist/CozyClient.js +1 -1
- package/dist/index.js +9 -0
- package/dist/index.node.js +11 -2
- package/dist/links/CozyLink.js +11 -0
- package/dist/links/CozyLink.spec.js +5 -0
- package/dist/links/DataProxyLink.js +21 -3
- package/dist/links/DataProxyLink.spec.js +48 -0
- package/dist/links/StackLink.js +40 -22
- package/dist/links/StackLink.spec.js +57 -0
- package/dist/links/forceLink.js +48 -0
- package/dist/store/queries.js +110 -10
- package/dist/store/queries.spec.js +59 -0
- package/dist/types.js +2 -1
- package/package.json +2 -2
- package/types/index.d.ts +1 -0
- package/types/index.node.d.ts +1 -0
- package/types/links/CozyLink.d.ts +6 -0
- package/types/links/forceLink.d.ts +5 -0
- package/types/store/queries.d.ts +4 -0
- package/types/types.d.ts +5 -1
package/dist/CozyClient.js
CHANGED
|
@@ -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.
|
|
3129
|
+
CozyClient.version = "60.30.0";
|
|
3130
3130
|
|
|
3131
3131
|
_microee.default.mixin(CozyClient);
|
|
3132
3132
|
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ var _exportNames = {
|
|
|
12
12
|
StackLink: true,
|
|
13
13
|
WebFlagshipLink: true,
|
|
14
14
|
DataProxyLink: true,
|
|
15
|
+
resolveForceLink: true,
|
|
15
16
|
compose: true,
|
|
16
17
|
QueryDefinition: true,
|
|
17
18
|
Q: true,
|
|
@@ -94,6 +95,12 @@ Object.defineProperty(exports, "DataProxyLink", {
|
|
|
94
95
|
return _DataProxyLink.default;
|
|
95
96
|
}
|
|
96
97
|
});
|
|
98
|
+
Object.defineProperty(exports, "resolveForceLink", {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
get: function get() {
|
|
101
|
+
return _forceLink.resolveForceLink;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
97
104
|
Object.defineProperty(exports, "compose", {
|
|
98
105
|
enumerable: true,
|
|
99
106
|
get: function get() {
|
|
@@ -400,6 +407,8 @@ var _WebFlagshipLink = _interopRequireDefault(require("./links/WebFlagshipLink")
|
|
|
400
407
|
|
|
401
408
|
var _DataProxyLink = _interopRequireDefault(require("./links/DataProxyLink"));
|
|
402
409
|
|
|
410
|
+
var _forceLink = require("./links/forceLink");
|
|
411
|
+
|
|
403
412
|
var _flow = _interopRequireDefault(require("lodash/flow"));
|
|
404
413
|
|
|
405
414
|
var _dsl = require("./queries/dsl");
|
package/dist/index.node.js
CHANGED
|
@@ -40,7 +40,8 @@ var _exportNames = {
|
|
|
40
40
|
models: true,
|
|
41
41
|
fetchPolicies: true,
|
|
42
42
|
webPerformanceApi: true,
|
|
43
|
-
defaultPerformanceApi: true
|
|
43
|
+
defaultPerformanceApi: true,
|
|
44
|
+
resolveForceLink: true
|
|
44
45
|
};
|
|
45
46
|
Object.defineProperty(exports, "default", {
|
|
46
47
|
enumerable: true,
|
|
@@ -234,6 +235,12 @@ Object.defineProperty(exports, "defaultPerformanceApi", {
|
|
|
234
235
|
return _defaultPerformanceApi.defaultPerformanceApi;
|
|
235
236
|
}
|
|
236
237
|
});
|
|
238
|
+
Object.defineProperty(exports, "resolveForceLink", {
|
|
239
|
+
enumerable: true,
|
|
240
|
+
get: function get() {
|
|
241
|
+
return _forceLink.resolveForceLink;
|
|
242
|
+
}
|
|
243
|
+
});
|
|
237
244
|
exports.models = exports.manifest = void 0;
|
|
238
245
|
|
|
239
246
|
var _CozyClient = _interopRequireDefault(require("./CozyClient"));
|
|
@@ -300,4 +307,6 @@ var _policies = _interopRequireDefault(require("./policies"));
|
|
|
300
307
|
|
|
301
308
|
var _webPerformanceApi = require("./performances/webPerformanceApi");
|
|
302
309
|
|
|
303
|
-
var _defaultPerformanceApi = require("./performances/defaultPerformanceApi");
|
|
310
|
+
var _defaultPerformanceApi = require("./performances/defaultPerformanceApi");
|
|
311
|
+
|
|
312
|
+
var _forceLink = require("./links/forceLink");
|
package/dist/links/CozyLink.js
CHANGED
|
@@ -126,6 +126,17 @@ var CozyLink = /*#__PURE__*/function () {
|
|
|
126
126
|
|
|
127
127
|
return reset;
|
|
128
128
|
}()
|
|
129
|
+
/**
|
|
130
|
+
* Stable name used to target this link via the `forceLink` query option.
|
|
131
|
+
*
|
|
132
|
+
* @returns {string|undefined}
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
}, {
|
|
136
|
+
key: "name",
|
|
137
|
+
get: function get() {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
129
140
|
}]);
|
|
130
141
|
return CozyLink;
|
|
131
142
|
}();
|
|
@@ -16,6 +16,11 @@ describe('CozyLink', () => {
|
|
|
16
16
|
expect(link.request('dummyOperation')).toBe('foobarbaz')
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
+
it('has name === undefined by default', () => {
|
|
20
|
+
const link = new CozyLink()
|
|
21
|
+
expect(link.name).toBe(undefined)
|
|
22
|
+
})
|
|
23
|
+
|
|
19
24
|
describe('default last link', () => {
|
|
20
25
|
it('should throw an error when called without result', () => {
|
|
21
26
|
const link = chain([
|
|
@@ -29,6 +29,8 @@ var _CozyLink2 = _interopRequireDefault(require("./CozyLink"));
|
|
|
29
29
|
|
|
30
30
|
var _cozyLogger = _interopRequireDefault(require("cozy-logger"));
|
|
31
31
|
|
|
32
|
+
var _forceLink = require("./forceLink");
|
|
33
|
+
|
|
32
34
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
33
35
|
|
|
34
36
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
@@ -124,18 +126,29 @@ var DataProxyLink = /*#__PURE__*/function (_CozyLink) {
|
|
|
124
126
|
var _this$dataproxy,
|
|
125
127
|
_this2 = this;
|
|
126
128
|
|
|
129
|
+
var forceLink;
|
|
127
130
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
128
131
|
while (1) {
|
|
129
132
|
switch (_context2.prev = _context2.next) {
|
|
130
133
|
case 0:
|
|
134
|
+
forceLink = (0, _forceLink.resolveForceLink)(options);
|
|
135
|
+
|
|
136
|
+
if (!(forceLink && forceLink !== this.name)) {
|
|
137
|
+
_context2.next = 3;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return _context2.abrupt("return", forward(operation, options));
|
|
142
|
+
|
|
143
|
+
case 3:
|
|
131
144
|
if (!((_this$dataproxy = this.dataproxy) !== null && _this$dataproxy !== void 0 && _this$dataproxy.requestLink)) {
|
|
132
|
-
_context2.next =
|
|
145
|
+
_context2.next = 5;
|
|
133
146
|
break;
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
return _context2.abrupt("return", this.doRequest(operation, options));
|
|
137
150
|
|
|
138
|
-
case
|
|
151
|
+
case 5:
|
|
139
152
|
return _context2.abrupt("return", new Promise(function (resolve, reject) {
|
|
140
153
|
_this2._queue.push({
|
|
141
154
|
operation: operation,
|
|
@@ -145,7 +158,7 @@ var DataProxyLink = /*#__PURE__*/function (_CozyLink) {
|
|
|
145
158
|
});
|
|
146
159
|
}));
|
|
147
160
|
|
|
148
|
-
case
|
|
161
|
+
case 6:
|
|
149
162
|
case "end":
|
|
150
163
|
return _context2.stop();
|
|
151
164
|
}
|
|
@@ -295,6 +308,11 @@ var DataProxyLink = /*#__PURE__*/function (_CozyLink) {
|
|
|
295
308
|
|
|
296
309
|
return _flushQueue;
|
|
297
310
|
}()
|
|
311
|
+
}, {
|
|
312
|
+
key: "name",
|
|
313
|
+
get: function get() {
|
|
314
|
+
return 'dataproxy';
|
|
315
|
+
}
|
|
298
316
|
}]);
|
|
299
317
|
return DataProxyLink;
|
|
300
318
|
}(_CozyLink2.default);
|
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
2
|
import DataProxyLink from './DataProxyLink'
|
|
3
3
|
|
|
4
|
+
describe('DataProxyLink name', () => {
|
|
5
|
+
it('should expose a stable name', () => {
|
|
6
|
+
expect(new DataProxyLink().name).toBe('dataproxy')
|
|
7
|
+
})
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('DataProxyLink forceLink', () => {
|
|
11
|
+
it('forwards a forceStack:true query (routes away from dataproxy)', async () => {
|
|
12
|
+
const link = new DataProxyLink()
|
|
13
|
+
const forwardFn = jest.fn().mockResolvedValue(null)
|
|
14
|
+
await link.request(
|
|
15
|
+
{ doctype: 'io.cozy.files' },
|
|
16
|
+
{ forceStack: true },
|
|
17
|
+
null,
|
|
18
|
+
forwardFn
|
|
19
|
+
)
|
|
20
|
+
expect(forwardFn).toHaveBeenCalled()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('handles when forceLink targets it', async () => {
|
|
24
|
+
const link = new DataProxyLink()
|
|
25
|
+
link.registerDataProxy({
|
|
26
|
+
requestLink: jest.fn().mockResolvedValue({ data: [{ _id: '1' }] })
|
|
27
|
+
})
|
|
28
|
+
const forward = jest.fn()
|
|
29
|
+
const res = await link.request(
|
|
30
|
+
{ doctype: 'io.cozy.files' },
|
|
31
|
+
{ forceLink: 'dataproxy' },
|
|
32
|
+
undefined,
|
|
33
|
+
forward
|
|
34
|
+
)
|
|
35
|
+
expect(forward).not.toHaveBeenCalled()
|
|
36
|
+
expect(res).toEqual({ data: [{ _id: '1' }] })
|
|
37
|
+
})
|
|
38
|
+
it('forwards when forceLink targets another link', async () => {
|
|
39
|
+
const link = new DataProxyLink()
|
|
40
|
+
const forward = jest.fn().mockResolvedValue('forwarded')
|
|
41
|
+
expect(
|
|
42
|
+
await link.request(
|
|
43
|
+
{ doctype: 'io.cozy.files' },
|
|
44
|
+
{ forceLink: 'stack' },
|
|
45
|
+
undefined,
|
|
46
|
+
forward
|
|
47
|
+
)
|
|
48
|
+
).toBe('forwarded')
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
4
52
|
describe('DataProxyLink queueing', () => {
|
|
5
53
|
it('should directly call dataproxy requestLink if available', async () => {
|
|
6
54
|
const requestLink = jest.fn().mockResolvedValue('OK')
|
package/dist/links/StackLink.js
CHANGED
|
@@ -41,6 +41,8 @@ var _utils = require("../utils");
|
|
|
41
41
|
|
|
42
42
|
var _defaultPerformanceApi = require("../performances/defaultPerformanceApi");
|
|
43
43
|
|
|
44
|
+
var _forceLink = require("./forceLink");
|
|
45
|
+
|
|
44
46
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
45
47
|
|
|
46
48
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
@@ -176,72 +178,83 @@ var StackLink = /*#__PURE__*/function (_CozyLink) {
|
|
|
176
178
|
key: "request",
|
|
177
179
|
value: function () {
|
|
178
180
|
var _request = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(operation, options, result, forward) {
|
|
181
|
+
var forceLink;
|
|
179
182
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
180
183
|
while (1) {
|
|
181
184
|
switch (_context2.prev = _context2.next) {
|
|
182
185
|
case 0:
|
|
183
|
-
|
|
186
|
+
forceLink = (0, _forceLink.resolveForceLink)(options);
|
|
187
|
+
|
|
188
|
+
if (!(forceLink && forceLink !== this.name)) {
|
|
189
|
+
_context2.next = 3;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return _context2.abrupt("return", forward(operation, options));
|
|
194
|
+
|
|
195
|
+
case 3:
|
|
196
|
+
_context2.t0 = forceLink !== 'stack' && this.isOnline;
|
|
184
197
|
|
|
185
198
|
if (!_context2.t0) {
|
|
186
|
-
_context2.next =
|
|
199
|
+
_context2.next = 8;
|
|
187
200
|
break;
|
|
188
201
|
}
|
|
189
202
|
|
|
190
|
-
_context2.next =
|
|
203
|
+
_context2.next = 7;
|
|
191
204
|
return this.isOnline();
|
|
192
205
|
|
|
193
|
-
case
|
|
206
|
+
case 7:
|
|
194
207
|
_context2.t0 = !_context2.sent;
|
|
195
208
|
|
|
196
|
-
case
|
|
209
|
+
case 8:
|
|
197
210
|
if (!_context2.t0) {
|
|
198
|
-
_context2.next =
|
|
211
|
+
_context2.next = 10;
|
|
199
212
|
break;
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
return _context2.abrupt("return", forward(operation, options));
|
|
203
216
|
|
|
204
|
-
case
|
|
205
|
-
_context2.prev =
|
|
217
|
+
case 10:
|
|
218
|
+
_context2.prev = 10;
|
|
206
219
|
|
|
207
220
|
if (!operation.mutationType) {
|
|
208
|
-
_context2.next =
|
|
221
|
+
_context2.next = 15;
|
|
209
222
|
break;
|
|
210
223
|
}
|
|
211
224
|
|
|
212
|
-
_context2.next =
|
|
225
|
+
_context2.next = 14;
|
|
213
226
|
return this.executeMutation(operation, options, result, forward);
|
|
214
227
|
|
|
215
|
-
case
|
|
228
|
+
case 14:
|
|
216
229
|
return _context2.abrupt("return", _context2.sent);
|
|
217
230
|
|
|
218
|
-
case
|
|
219
|
-
_context2.next =
|
|
231
|
+
case 15:
|
|
232
|
+
_context2.next = 17;
|
|
220
233
|
return this.executeQuery(operation);
|
|
221
234
|
|
|
222
|
-
case
|
|
235
|
+
case 17:
|
|
223
236
|
return _context2.abrupt("return", _context2.sent);
|
|
224
237
|
|
|
225
|
-
case
|
|
226
|
-
_context2.prev =
|
|
227
|
-
_context2.t1 = _context2["catch"](
|
|
238
|
+
case 20:
|
|
239
|
+
_context2.prev = 20;
|
|
240
|
+
_context2.t1 = _context2["catch"](10);
|
|
228
241
|
|
|
229
|
-
if (!(
|
|
230
|
-
_context2.next =
|
|
242
|
+
if (!(forceLink !== 'stack' && (0, _utils.isReactNativeOfflineError)(_context2.t1))) {
|
|
243
|
+
_context2.next = 24;
|
|
231
244
|
break;
|
|
232
245
|
}
|
|
233
246
|
|
|
234
247
|
return _context2.abrupt("return", forward(operation, options));
|
|
235
248
|
|
|
236
|
-
case
|
|
249
|
+
case 24:
|
|
237
250
|
throw _context2.t1;
|
|
238
251
|
|
|
239
|
-
case
|
|
252
|
+
case 25:
|
|
240
253
|
case "end":
|
|
241
254
|
return _context2.stop();
|
|
242
255
|
}
|
|
243
256
|
}
|
|
244
|
-
}, _callee2, this, [[
|
|
257
|
+
}, _callee2, this, [[10, 20]]);
|
|
245
258
|
}));
|
|
246
259
|
|
|
247
260
|
function request(_x, _x2, _x3, _x4) {
|
|
@@ -409,6 +422,11 @@ var StackLink = /*#__PURE__*/function (_CozyLink) {
|
|
|
409
422
|
|
|
410
423
|
return executeMutation;
|
|
411
424
|
}()
|
|
425
|
+
}, {
|
|
426
|
+
key: "name",
|
|
427
|
+
get: function get() {
|
|
428
|
+
return 'stack';
|
|
429
|
+
}
|
|
412
430
|
}]);
|
|
413
431
|
return StackLink;
|
|
414
432
|
}(_CozyLink2.default);
|
|
@@ -2,8 +2,17 @@ import { Q } from '../queries/dsl'
|
|
|
2
2
|
import CozyClient from '../CozyClient'
|
|
3
3
|
import StackLink, { transformBulkDocsResponse } from './StackLink'
|
|
4
4
|
import { SCHEMA } from '../__tests__/fixtures'
|
|
5
|
+
import logger from '../logger'
|
|
6
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
7
|
+
import { _resetForceStackWarning } from './forceLink'
|
|
5
8
|
|
|
6
9
|
describe('StackLink', () => {
|
|
10
|
+
describe('name', () => {
|
|
11
|
+
it('should expose a stable name', () => {
|
|
12
|
+
expect(new StackLink().name).toBe('stack')
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
7
16
|
let stackClient, link, client
|
|
8
17
|
|
|
9
18
|
beforeEach(() => {
|
|
@@ -12,6 +21,54 @@ describe('StackLink', () => {
|
|
|
12
21
|
stackClient = client.getStackClient()
|
|
13
22
|
})
|
|
14
23
|
|
|
24
|
+
describe('forceLink', () => {
|
|
25
|
+
let warnSpy
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
_resetForceStackWarning()
|
|
29
|
+
warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
warnSpy.mockRestore()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('forwards when forceLink targets another link', async () => {
|
|
37
|
+
const link = new StackLink()
|
|
38
|
+
const forward = jest.fn().mockResolvedValue('forwarded')
|
|
39
|
+
expect(
|
|
40
|
+
await link.request(
|
|
41
|
+
{ doctype: 'io.cozy.files' },
|
|
42
|
+
{ forceLink: 'dataproxy' },
|
|
43
|
+
undefined,
|
|
44
|
+
forward
|
|
45
|
+
)
|
|
46
|
+
).toBe('forwarded')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('handles a forceStack:true query (legacy: does not forward, emits deprecation warning)', async () => {
|
|
50
|
+
const link = new StackLink()
|
|
51
|
+
link.executeQuery = jest.fn().mockResolvedValue({ data: [] })
|
|
52
|
+
link.isOnline = jest.fn().mockResolvedValue(false) // offline — should NOT bail because forceStack
|
|
53
|
+
const forwardFn = jest.fn()
|
|
54
|
+
const op = { doctype: 'io.cozy.files' }
|
|
55
|
+
await link.request(op, { forceStack: true }, null, forwardFn)
|
|
56
|
+
expect(forwardFn).not.toHaveBeenCalled()
|
|
57
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
58
|
+
expect.stringContaining('forceStack is deprecated')
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('forwards a plain query when offline', async () => {
|
|
63
|
+
const link = new StackLink()
|
|
64
|
+
link.isOnline = jest.fn().mockResolvedValue(false)
|
|
65
|
+
const forwardFn = jest.fn().mockResolvedValue(null)
|
|
66
|
+
const op = { doctype: 'io.cozy.files' }
|
|
67
|
+
await link.request(op, {}, null, forwardFn)
|
|
68
|
+
expect(forwardFn).toHaveBeenCalled()
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
15
72
|
describe('query execution', () => {
|
|
16
73
|
it('should execute queries without a selector', async () => {
|
|
17
74
|
const query = Q('io.cozy.todos')
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.resolveForceLink = exports._resetForceStackWarning = void 0;
|
|
9
|
+
|
|
10
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
11
|
+
|
|
12
|
+
var hasWarnedForceStack = false; // eslint-disable-next-line no-underscore-dangle
|
|
13
|
+
|
|
14
|
+
var _resetForceStackWarning = function _resetForceStackWarning() {
|
|
15
|
+
hasWarnedForceStack = false;
|
|
16
|
+
};
|
|
17
|
+
/* eslint-disable jsdoc/check-tag-names */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the effective forceLink target, mapping the deprecated forceStack option onto forceLink:'stack'.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
* @param {{ forceLink?: string, forceStack?: boolean }} [options] - Query options
|
|
24
|
+
* @returns {string|undefined}
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
exports._resetForceStackWarning = _resetForceStackWarning;
|
|
29
|
+
|
|
30
|
+
var resolveForceLink = function resolveForceLink(options) {
|
|
31
|
+
if (options !== null && options !== void 0 && options.forceLink) return options.forceLink;
|
|
32
|
+
|
|
33
|
+
if (options !== null && options !== void 0 && options.forceStack) {
|
|
34
|
+
if (!hasWarnedForceStack) {
|
|
35
|
+
_logger.default.warn("options.forceStack is deprecated, use forceLink: 'stack' instead");
|
|
36
|
+
|
|
37
|
+
hasWarnedForceStack = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return 'stack';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return undefined;
|
|
44
|
+
};
|
|
45
|
+
/* eslint-enable jsdoc/check-tag-names */
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
exports.resolveForceLink = resolveForceLink;
|
package/dist/store/queries.js
CHANGED
|
@@ -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.
|
|
614
|
+
exports.computeMatchPartition = computeMatchPartition;
|
|
511
615
|
|
|
512
616
|
var updateData = function updateData(query, newData, documents) {
|
|
513
|
-
var
|
|
514
|
-
|
|
515
|
-
|
|
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/dist/types.js
CHANGED
|
@@ -315,7 +315,8 @@ var _dsl = require("./queries/dsl");
|
|
|
315
315
|
* a single doc instead of an array for single doc queries. Defaults to false for backward
|
|
316
316
|
* compatibility but will be set to true in the future.
|
|
317
317
|
* @property {boolean} [executeFromStore=false] - If set to true, the query will be run directly on the current store's state
|
|
318
|
-
* @property {boolean} [forceStack] -
|
|
318
|
+
* @property {boolean} [forceStack] - Deprecated: use forceLink:'stack'. Executes the query through StackLink only.
|
|
319
|
+
* @property {string} [forceLink] - Route this query exclusively to the link whose name matches (e.g. 'dataproxy').
|
|
319
320
|
*/
|
|
320
321
|
|
|
321
322
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-client",
|
|
3
|
-
"version": "60.
|
|
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": "
|
|
77
|
+
"gitHead": "7f9e5753cc1e0b1e1a46e983ec1a556c516a0fc2"
|
|
78
78
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as CozyLink } from "./links/CozyLink";
|
|
|
3
3
|
export { default as StackLink } from "./links/StackLink";
|
|
4
4
|
export { default as WebFlagshipLink } from "./links/WebFlagshipLink";
|
|
5
5
|
export { default as DataProxyLink } from "./links/DataProxyLink";
|
|
6
|
+
export { resolveForceLink } from "./links/forceLink";
|
|
6
7
|
export { default as compose } from "lodash/flow";
|
|
7
8
|
export { default as Registry } from "./registry";
|
|
8
9
|
export { default as RealTimeQueries } from "./RealTimeQueries";
|
package/types/index.node.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { BulkEditError } from "./errors";
|
|
|
12
12
|
export { default as fetchPolicies } from "./policies";
|
|
13
13
|
export { webPerformanceApi } from "./performances/webPerformanceApi";
|
|
14
14
|
export { defaultPerformanceApi } from "./performances/defaultPerformanceApi";
|
|
15
|
+
export { resolveForceLink } from "./links/forceLink";
|
|
15
16
|
import * as manifest from "./models/manifest";
|
|
16
17
|
import * as models from "./models";
|
|
17
18
|
export { manifest, models };
|
|
@@ -24,5 +24,11 @@ export default class CozyLink {
|
|
|
24
24
|
* @returns {Promise<any>}
|
|
25
25
|
*/
|
|
26
26
|
reset(): Promise<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Stable name used to target this link via the `forceLink` query option.
|
|
29
|
+
*
|
|
30
|
+
* @returns {string|undefined}
|
|
31
|
+
*/
|
|
32
|
+
get name(): string;
|
|
27
33
|
}
|
|
28
34
|
export function chain(links: any): any;
|
package/types/store/queries.d.ts
CHANGED
|
@@ -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;
|
package/types/types.d.ts
CHANGED
|
@@ -567,9 +567,13 @@ export type QueryOptions = {
|
|
|
567
567
|
*/
|
|
568
568
|
executeFromStore?: boolean;
|
|
569
569
|
/**
|
|
570
|
-
* -
|
|
570
|
+
* - Deprecated: use forceLink:'stack'. Executes the query through StackLink only.
|
|
571
571
|
*/
|
|
572
572
|
forceStack?: boolean;
|
|
573
|
+
/**
|
|
574
|
+
* - Route this query exclusively to the link whose name matches (e.g. 'dataproxy').
|
|
575
|
+
*/
|
|
576
|
+
forceLink?: string;
|
|
573
577
|
};
|
|
574
578
|
export type Query = {
|
|
575
579
|
definition: QueryDefinition;
|