cozy-client 27.3.0 → 27.5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,51 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [27.5.0](https://github.com/cozy/cozy-client/compare/v27.4.0...v27.5.0) (2021-12-01)
7
+
8
+
9
+ ### Features
10
+
11
+ * Added referencedBy helpers ([2bd77e4](https://github.com/cozy/cozy-client/commit/2bd77e451eab26b85b21b41db522a7da6378672b))
12
+ * Adding types around references ([6d9c8aa](https://github.com/cozy/cozy-client/commit/6d9c8aade0ece644674b9adfee1b08b8eff7482e))
13
+
14
+
15
+
16
+
17
+
18
+ # [27.4.0](https://github.com/cozy/cozy-client/compare/v27.3.2...v27.4.0) (2021-11-25)
19
+
20
+
21
+ ### Features
22
+
23
+ * onError Callback ([c5f65d3](https://github.com/cozy/cozy-client/commit/c5f65d33e0ab29a22b409365151173a3b7645b56))
24
+
25
+
26
+
27
+
28
+
29
+ ## [27.3.2](https://github.com/cozy/cozy-client/compare/v27.3.1...v27.3.2) (2021-11-17)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * Login on RN iOS ([4b85b47](https://github.com/cozy/cozy-client/commit/4b85b475bf0c5b32f94a06e524fa7f0f5011f90e))
35
+
36
+
37
+
38
+
39
+
40
+ ## [27.3.1](https://github.com/cozy/cozy-client/compare/v27.3.0...v27.3.1) (2021-11-16)
41
+
42
+
43
+ ### Bug Fixes
44
+
45
+ * Export Qualification ([3472bce](https://github.com/cozy/cozy-client/commit/3472bcec6ab3e19353a290e79189bf09c34b38b8))
46
+
47
+
48
+
49
+
50
+
6
51
  # [27.3.0](https://github.com/cozy/cozy-client/compare/v27.2.0...v27.3.0) (2021-11-16)
7
52
 
8
53
 
@@ -128,7 +128,7 @@ var DOC_UPDATE = 'update';
128
128
  * @property {boolean} [autoHydrate]
129
129
  * @property {object} [oauth]
130
130
  * @property {Function} [onTokenRefresh]
131
- * @property {Function} [onTokenRefresh]
131
+ * @property {Function} [onError] - Default callback if a query is errored
132
132
  * @property {Link} [link] - Backward compatibility
133
133
  * @property {Array<Link>} [links] - List of links
134
134
  * @property {object} [schema] - Schema description for each doctypes
@@ -1276,10 +1276,32 @@ var CozyClient = /*#__PURE__*/function () {
1276
1276
  case 24:
1277
1277
  _context8.prev = 24;
1278
1278
  _context8.t0 = _context8["catch"](15);
1279
- this.dispatch((0, _store.receiveQueryError)(queryId, _context8.t0));
1279
+ this.dispatch((0, _store.receiveQueryError)(queryId, _context8.t0)); // specific onError
1280
+
1281
+ if (!options.onError) {
1282
+ _context8.next = 31;
1283
+ break;
1284
+ }
1285
+
1286
+ options.onError(_context8.t0); // defaulted onError
1287
+
1288
+ _context8.next = 36;
1289
+ break;
1290
+
1291
+ case 31:
1292
+ if (!this.options.onError) {
1293
+ _context8.next = 35;
1294
+ break;
1295
+ }
1296
+
1297
+ this.options.onError(_context8.t0);
1298
+ _context8.next = 36;
1299
+ break;
1300
+
1301
+ case 35:
1280
1302
  throw _context8.t0;
1281
1303
 
1282
- case 28:
1304
+ case 36:
1283
1305
  case "end":
1284
1306
  return _context8.stop();
1285
1307
  }
@@ -2256,6 +2278,21 @@ var CozyClient = /*#__PURE__*/function () {
2256
2278
  }));
2257
2279
  });
2258
2280
  }
2281
+ /**
2282
+ * At any time put an error function
2283
+ *
2284
+ * @param {Function} [onError] - Set a callback for queries which are errored
2285
+ */
2286
+
2287
+ }, {
2288
+ key: "setOnError",
2289
+ value: function setOnError(onError) {
2290
+ if (this.options && this.options.onError) {
2291
+ throw new Error('On Error is already defined');
2292
+ }
2293
+
2294
+ this.options.onError = onError;
2295
+ }
2259
2296
  }, {
2260
2297
  key: "toJSON",
2261
2298
  value: function toJSON() {
@@ -2415,7 +2452,7 @@ var CozyClient = /*#__PURE__*/function () {
2415
2452
  CozyClient.hooks = CozyClient.hooks || {};
2416
2453
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
2417
2454
 
2418
- CozyClient.version = "27.3.0";
2455
+ CozyClient.version = "27.5.0";
2419
2456
 
2420
2457
  _microee.default.mixin(CozyClient);
2421
2458
 
@@ -162,7 +162,6 @@ describe('CozyClient initialization', () => {
162
162
  })
163
163
  }
164
164
  const client = await CozyClient.fromOldOAuthClient(oldClient)
165
- console.log({ stackClient: client.stackClient })
166
165
  expect(client.stackClient.uri).toBe(url)
167
166
  expect(client.stackClient.oauthOptions.clientID).toBe(oauth.clientID)
168
167
  expect(client.stackClient.token.accessToken).toBe(token.accessToken)
@@ -1402,6 +1401,54 @@ describe('CozyClient', () => {
1402
1401
  receiveQueryResult('allTodos', fakeResponse)
1403
1402
  )
1404
1403
  })
1404
+
1405
+ const setupOnError = () => {
1406
+ const error = new TypeError('Failed to fetch')
1407
+ requestHandler.mockReturnValueOnce(Promise.reject(error))
1408
+ const onError = jest.fn().mockReturnValueOnce(() => true)
1409
+ return onError
1410
+ }
1411
+
1412
+ it('should call onError callback when an error is thrown. Callback passed as argument', async () => {
1413
+ const onError = setupOnError()
1414
+
1415
+ await client.query(query, { as: 'allTodos', onError })
1416
+ expect(onError).toBeCalled()
1417
+ })
1418
+
1419
+ it('should call onError callback when an error is catched. It is passed during instantiation', async () => {
1420
+ const onError = setupOnError()
1421
+ const client = new CozyClient({ onError })
1422
+
1423
+ await client.query(query, { as: 'allTodos' })
1424
+ expect(onError).toBeCalled()
1425
+ })
1426
+
1427
+ it('should call onError callback when an error is catched. It is passed with setOnError', async () => {
1428
+ const onError = setupOnError()
1429
+ client.setOnError(onError)
1430
+
1431
+ await client.query(query, { as: 'allTodos' })
1432
+ expect(onError).toBeCalled()
1433
+ })
1434
+
1435
+ it('should throw an error when we call setOnError twice (or several times)', async () => {
1436
+ const client = new CozyClient({})
1437
+ const onError = () => true
1438
+
1439
+ const funcShouldThrow = () => client.setOnError(onError)
1440
+ expect(funcShouldThrow).not.toThrow()
1441
+ expect(funcShouldThrow).toThrow('On Error is already defined')
1442
+ })
1443
+
1444
+ it('should throw an error when there is no onError callback', async () => {
1445
+ const error = new TypeError('Failed to fetch')
1446
+ requestHandler.mockReturnValueOnce(Promise.reject(error))
1447
+
1448
+ await expect(client.query(query, { as: 'allTodos' })).rejects.toThrow(
1449
+ 'Failed to fetch'
1450
+ )
1451
+ })
1405
1452
  })
1406
1453
 
1407
1454
  describe('queryAll', () => {
@@ -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.create = exports.resolveClass = exports.attachRelationships = exports.responseToRelationship = exports.pickTypeAndId = void 0;
8
+ exports.getReferencedById = exports.getReferencedBy = exports.isReferencedById = exports.isReferencedBy = exports.create = exports.resolveClass = exports.attachRelationships = exports.responseToRelationship = exports.pickTypeAndId = void 0;
9
9
 
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
@@ -25,6 +25,8 @@ var _HasManyInPlace = _interopRequireDefault(require("./HasManyInPlace"));
25
25
 
26
26
  var _HasManyFiles = _interopRequireDefault(require("./HasManyFiles"));
27
27
 
28
+ var _types = require("../types");
29
+
28
30
  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; }
29
31
 
30
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; }
@@ -124,5 +126,83 @@ var create = function create(target, _ref, accessors) {
124
126
 
125
127
  return new type(target, name, doctype, accessors);
126
128
  };
129
+ /**
130
+ * Checks if the file is referenced by a specific doctype
131
+ *
132
+ * @param {IOCozyFile} file - io.cozy.files document
133
+ * @param {Doctype} referencedBy - Doctype where document is referenced
134
+ * @returns {boolean} If a reference is found
135
+ */
136
+
137
+
138
+ exports.create = create;
139
+
140
+ var isReferencedBy = function isReferencedBy(file, referencedBy) {
141
+ var _file$relationships, _file$relationships$r;
142
+
143
+ var references = (file === null || file === void 0 ? void 0 : (_file$relationships = file.relationships) === null || _file$relationships === void 0 ? void 0 : (_file$relationships$r = _file$relationships.referenced_by) === null || _file$relationships$r === void 0 ? void 0 : _file$relationships$r.data) || (file === null || file === void 0 ? void 0 : file.referenced_by) || [];
144
+ return references.some(function (reference) {
145
+ return reference.type === referencedBy;
146
+ });
147
+ };
148
+ /**
149
+ * Checks if the file is referenced by a specific doctype and a specific Id of that reference
150
+ *
151
+ * @param {IOCozyFile} file - io.cozy.files document
152
+ * @param {Doctype} referencedBy - Doctype where document is referenced
153
+ * @param {string} referencedId - Id of the referenced document
154
+ * @returns {boolean} If a reference is found
155
+ */
156
+
157
+
158
+ exports.isReferencedBy = isReferencedBy;
159
+
160
+ var isReferencedById = function isReferencedById(file, referencedBy, referencedId) {
161
+ var _file$relationships2, _file$relationships2$;
162
+
163
+ var references = (file === null || file === void 0 ? void 0 : (_file$relationships2 = file.relationships) === null || _file$relationships2 === void 0 ? void 0 : (_file$relationships2$ = _file$relationships2.referenced_by) === null || _file$relationships2$ === void 0 ? void 0 : _file$relationships2$.data) || (file === null || file === void 0 ? void 0 : file.referenced_by) || [];
164
+ return references.some(function (reference) {
165
+ return reference.type === referencedBy && reference.id === referencedId;
166
+ });
167
+ };
168
+ /**
169
+ * Get array of reference by an specific doctype
170
+ *
171
+ * @param {IOCozyFile} file - io.cozy.files document
172
+ * @param {Doctype} referencedBy - Doctype where document is referenced
173
+ * @returns {Reference[]} Array of references found
174
+ */
175
+
176
+
177
+ exports.isReferencedById = isReferencedById;
178
+
179
+ var getReferencedBy = function getReferencedBy(file, referencedBy) {
180
+ var _file$relationships3, _file$relationships3$;
181
+
182
+ var references = (file === null || file === void 0 ? void 0 : (_file$relationships3 = file.relationships) === null || _file$relationships3 === void 0 ? void 0 : (_file$relationships3$ = _file$relationships3.referenced_by) === null || _file$relationships3$ === void 0 ? void 0 : _file$relationships3$.data) || (file === null || file === void 0 ? void 0 : file.referenced_by) || [];
183
+ return references.filter(function (reference) {
184
+ return reference.type === referencedBy;
185
+ });
186
+ };
187
+ /**
188
+ * Get array of reference by an specific doctype and a specific Id of that reference
189
+ *
190
+ * @param {IOCozyFile} file - io.cozy.files document
191
+ * @param {Doctype} referencedBy - Doctype where document is referenced
192
+ * @param {string} referencedId - Id of the referenced document
193
+ * @returns {Reference[]} Array of the reference found
194
+ */
195
+
196
+
197
+ exports.getReferencedBy = getReferencedBy;
198
+
199
+ var getReferencedById = function getReferencedById(file, referencedBy, referencedId) {
200
+ var _file$relationships4, _file$relationships4$;
201
+
202
+ var references = (file === null || file === void 0 ? void 0 : (_file$relationships4 = file.relationships) === null || _file$relationships4 === void 0 ? void 0 : (_file$relationships4$ = _file$relationships4.referenced_by) === null || _file$relationships4$ === void 0 ? void 0 : _file$relationships4$.data) || (file === null || file === void 0 ? void 0 : file.referenced_by) || [];
203
+ return references.filter(function (reference) {
204
+ return reference.type === referencedBy && reference.id === referencedId;
205
+ });
206
+ };
127
207
 
128
- exports.create = create;
208
+ exports.getReferencedById = getReferencedById;
@@ -1,123 +1,237 @@
1
- import { attachRelationships } from './helpers'
2
-
3
- describe('Attaching relationships', () => {
4
- const tasks = {
5
- data: [
6
- { _id: 1, _type: 'io.cozy.tasks' },
7
- { _id: 2, _type: 'io.cozy.tasks' }
8
- ]
9
- }
10
- const todos = {
11
- data: [
12
- { _id: 3, _type: 'io.cozy.todos' },
13
- { _id: 4, _type: 'io.cozy.todos' }
14
- ]
15
- }
16
-
17
- it('should attach to a single document', () => {
18
- const doc = {
19
- _id: 1
1
+ import {
2
+ attachRelationships,
3
+ isReferencedBy,
4
+ isReferencedById,
5
+ getReferencedBy,
6
+ getReferencedById
7
+ } from './helpers'
8
+
9
+ describe('Associations helpers', () => {
10
+ describe('Attaching relationships', () => {
11
+ const tasks = {
12
+ data: [
13
+ { _id: 1, _type: 'io.cozy.tasks' },
14
+ { _id: 2, _type: 'io.cozy.tasks' }
15
+ ]
20
16
  }
21
- const relationships = {
22
- 1: {
23
- tasks
24
- }
17
+ const todos = {
18
+ data: [
19
+ { _id: 3, _type: 'io.cozy.todos' },
20
+ { _id: 4, _type: 'io.cozy.todos' }
21
+ ]
25
22
  }
26
- const withRelationships = attachRelationships({ data: doc }, relationships)
27
- expect(withRelationships.data.relationships).toEqual({
28
- tasks
29
- })
30
- })
31
23
 
32
- it('should attach to multiple document', () => {
33
- const docs = [
34
- {
24
+ it('should attach to a single document', () => {
25
+ const doc = {
35
26
  _id: 1
36
- },
37
- {
38
- _id: 2
39
27
  }
40
- ]
41
- const relationships = {
42
- 1: {
28
+ const relationships = {
29
+ 1: {
30
+ tasks
31
+ }
32
+ }
33
+ const withRelationships = attachRelationships(
34
+ { data: doc },
35
+ relationships
36
+ )
37
+ expect(withRelationships.data.relationships).toEqual({
43
38
  tasks
44
- },
45
- 2: {
46
- todos
39
+ })
40
+ })
41
+
42
+ it('should attach to multiple document', () => {
43
+ const docs = [
44
+ {
45
+ _id: 1
46
+ },
47
+ {
48
+ _id: 2
49
+ }
50
+ ]
51
+ const relationships = {
52
+ 1: {
53
+ tasks
54
+ },
55
+ 2: {
56
+ todos
57
+ }
47
58
  }
48
- }
49
- const withRelationships = attachRelationships({ data: docs }, relationships)
50
- expect(withRelationships.data[0].relationships).toEqual({
51
- tasks
59
+ const withRelationships = attachRelationships(
60
+ { data: docs },
61
+ relationships
62
+ )
63
+ expect(withRelationships.data[0].relationships).toEqual({
64
+ tasks
65
+ })
66
+ expect(withRelationships.data[1].relationships).toEqual({
67
+ todos
68
+ })
52
69
  })
53
- expect(withRelationships.data[1].relationships).toEqual({
54
- todos
70
+
71
+ it('should add missing relationships', () => {
72
+ const doc = {
73
+ _id: 1,
74
+ relationships: {
75
+ tasks
76
+ }
77
+ }
78
+ const relationships = {
79
+ 1: {
80
+ tasks,
81
+ todos
82
+ }
83
+ }
84
+ const withRelationships = attachRelationships(
85
+ { data: doc },
86
+ relationships
87
+ )
88
+ expect(withRelationships.data.relationships.tasks).toEqual(tasks)
89
+ expect(withRelationships.data.relationships.todos).toEqual(todos)
55
90
  })
56
- })
57
91
 
58
- it('should add missing relationships', () => {
59
- const doc = {
60
- _id: 1,
61
- relationships: {
62
- tasks
92
+ it('should preserve existing relationships', () => {
93
+ const doc = {
94
+ _id: 1,
95
+ relationships: {
96
+ tasks
97
+ }
63
98
  }
64
- }
65
- const relationships = {
66
- 1: {
67
- tasks,
68
- todos
99
+ const relationships = {
100
+ 1: {
101
+ todos
102
+ }
69
103
  }
70
- }
71
- const withRelationships = attachRelationships({ data: doc }, relationships)
72
- expect(withRelationships.data.relationships.tasks).toEqual(tasks)
73
- expect(withRelationships.data.relationships.todos).toEqual(todos)
74
- })
104
+ const withRelationships = attachRelationships(
105
+ { data: doc },
106
+ relationships
107
+ )
108
+ expect(withRelationships.data.relationships.tasks).toEqual(tasks)
109
+ expect(withRelationships.data.relationships.todos).toEqual(todos)
110
+ })
75
111
 
76
- it('should preserve existing relationships', () => {
77
- const doc = {
78
- _id: 1,
79
- relationships: {
80
- tasks
112
+ it('should work when there are no new relationships', () => {
113
+ const doc = {
114
+ _id: 1,
115
+ relationships: {
116
+ tasks
117
+ }
81
118
  }
82
- }
83
- const relationships = {
84
- 1: {
85
- todos
119
+ const relationships = {
120
+ 2: {
121
+ todos
122
+ }
86
123
  }
87
- }
88
- const withRelationships = attachRelationships({ data: doc }, relationships)
89
- expect(withRelationships.data.relationships.tasks).toEqual(tasks)
90
- expect(withRelationships.data.relationships.todos).toEqual(todos)
91
- })
124
+ const withRelationships = attachRelationships(
125
+ { data: doc },
126
+ relationships
127
+ )
128
+ expect(withRelationships.data.relationships.tasks).toEqual(tasks)
129
+ expect(Object.keys(withRelationships.data.relationships).length).toEqual(
130
+ 1
131
+ )
132
+ })
92
133
 
93
- it('should work when there are no new relationships', () => {
94
- const doc = {
95
- _id: 1,
96
- relationships: {
97
- tasks
134
+ it('should attach relationships when the document has an empty relationship object', () => {
135
+ const doc = {
136
+ _id: 1,
137
+ relationships: {}
98
138
  }
99
- }
100
- const relationships = {
101
- 2: {
102
- todos
139
+ const relationships = {
140
+ 1: {
141
+ tasks
142
+ }
103
143
  }
104
- }
105
- const withRelationships = attachRelationships({ data: doc }, relationships)
106
- expect(withRelationships.data.relationships.tasks).toEqual(tasks)
107
- expect(Object.keys(withRelationships.data.relationships).length).toEqual(1)
144
+ const withRelationships = attachRelationships(
145
+ { data: doc },
146
+ relationships
147
+ )
148
+ expect(withRelationships.data.relationships.tasks).toEqual(tasks)
149
+ })
108
150
  })
109
151
 
110
- it('should attach relationships when the document has an empty relationship object', () => {
111
- const doc = {
112
- _id: 1,
113
- relationships: {}
114
- }
115
- const relationships = {
116
- 1: {
117
- tasks
152
+ describe('referencedBy', () => {
153
+ const mockFile = {
154
+ _id: '123',
155
+ name: 'fakeFile',
156
+ relationships: {
157
+ referenced_by: {
158
+ data: [
159
+ {
160
+ id: '123',
161
+ type: 'io.cozy.contacts'
162
+ },
163
+ {
164
+ id: '456',
165
+ type: 'io.cozy.contacts'
166
+ }
167
+ ]
168
+ }
118
169
  }
119
170
  }
120
- const withRelationships = attachRelationships({ data: doc }, relationships)
121
- expect(withRelationships.data.relationships.tasks).toEqual(tasks)
171
+ describe('isReferencedBy', () => {
172
+ it('should return "true"', () => {
173
+ const result = isReferencedBy(mockFile, 'io.cozy.contacts')
174
+
175
+ expect(result).toBe(true)
176
+ })
177
+ it('should return "false"', () => {
178
+ const result = isReferencedBy(mockFile, 'io.cozy.xxx')
179
+
180
+ expect(result).toBe(false)
181
+ })
182
+ })
183
+
184
+ describe('isReferencedById', () => {
185
+ it('should return "true"', () => {
186
+ const result = isReferencedById(mockFile, 'io.cozy.contacts', '123')
187
+
188
+ expect(result).toBe(true)
189
+ })
190
+ it('should return "false"', () => {
191
+ const result = isReferencedById(mockFile, 'io.cozy.contacts', '789')
192
+
193
+ expect(result).toBe(false)
194
+ })
195
+ })
196
+
197
+ describe('getReferencedBy', () => {
198
+ it('should return correct array of reference', () => {
199
+ const result = getReferencedBy(mockFile, 'io.cozy.contacts')
200
+
201
+ expect(result).toEqual([
202
+ {
203
+ id: '123',
204
+ type: 'io.cozy.contacts'
205
+ },
206
+ {
207
+ id: '456',
208
+ type: 'io.cozy.contacts'
209
+ }
210
+ ])
211
+ })
212
+ it('should return empty array', () => {
213
+ const result = getReferencedBy(mockFile, 'io.cozy.xxx')
214
+
215
+ expect(result).toEqual([])
216
+ })
217
+ })
218
+
219
+ describe('getReferencedById', () => {
220
+ it('should return array of reference with only the reference with id "123"', () => {
221
+ const result = getReferencedById(mockFile, 'io.cozy.contacts', '123')
222
+
223
+ expect(result).toEqual([
224
+ {
225
+ id: '123',
226
+ type: 'io.cozy.contacts'
227
+ }
228
+ ])
229
+ })
230
+ it('should return empty array', () => {
231
+ const result = getReferencedById(mockFile, 'io.cozy.contacts', '789')
232
+
233
+ expect(result).toEqual([])
234
+ })
235
+ })
122
236
  })
123
237
  })
@@ -59,6 +59,30 @@ Object.defineProperty(exports, "create", {
59
59
  return _helpers.create;
60
60
  }
61
61
  });
62
+ Object.defineProperty(exports, "isReferencedBy", {
63
+ enumerable: true,
64
+ get: function get() {
65
+ return _helpers.isReferencedBy;
66
+ }
67
+ });
68
+ Object.defineProperty(exports, "isReferencedById", {
69
+ enumerable: true,
70
+ get: function get() {
71
+ return _helpers.isReferencedById;
72
+ }
73
+ });
74
+ Object.defineProperty(exports, "getReferencedBy", {
75
+ enumerable: true,
76
+ get: function get() {
77
+ return _helpers.getReferencedBy;
78
+ }
79
+ });
80
+ Object.defineProperty(exports, "getReferencedById", {
81
+ enumerable: true,
82
+ get: function get() {
83
+ return _helpers.getReferencedById;
84
+ }
85
+ });
62
86
 
63
87
  var _HasManyFiles = _interopRequireDefault(require("./HasManyFiles"));
64
88
 
@@ -64,11 +64,26 @@ var authenticateWithReactNativeInAppBrowser = /*#__PURE__*/function () {
64
64
 
65
65
  var linkListener = function linkListener(_ref2) {
66
66
  var url = _ref2.url;
67
+ var sanitizedUrl = url;
67
68
  var accessCode = /\?access_code=(.+)$/.test(url);
68
69
  var state = /\?state=(.+)$/.test(url);
69
70
 
70
71
  if (accessCode || state) {
71
- resolve(url);
72
+ if (_reactNative.Platform.OS === 'ios') {
73
+ // On iOS, the # added to the URL by the stack for security
74
+ // reason is encoded to %23. Because of this, URL().searchParams
75
+ // is not working as expected since %23 is added to the param
76
+ // instead of being ignored and assigned to the hash.
77
+ // Let's convert back %23 to # manually.
78
+ // I think the issue is related to Linking component but didn't
79
+ // find any issues on github about it. Need to make a simple
80
+ // reproduction case to create the issue.
81
+ if (url.endsWith('%23')) {
82
+ sanitizedUrl = url.replace(/%23$/, '#');
83
+ }
84
+ }
85
+
86
+ resolve(sanitizedUrl);
72
87
  removeListener();
73
88
 
74
89
  _reactNativeInappbrowserReborn.InAppBrowser.close();
@@ -25,6 +25,8 @@ var _types = require("../types");
25
25
 
26
26
  var _context = require("../context");
27
27
 
28
+ var _dsl = require("../queries/dsl");
29
+
28
30
  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; }
29
31
 
30
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; }
@@ -41,15 +43,16 @@ var generateFetchMoreQueryDefinition = function generateFetchMoreQueryDefinition
41
43
  /**
42
44
  * Fetches a queryDefinition and returns the queryState
43
45
  *
44
- * @param {object} queryDefinition - Definition created with Q()
46
+ * @param {QueryDefinition} queryDefinition - Definition created with Q()
45
47
  *
46
- * @param {object} options - Options
47
- * @param {object} options.as - Name for the query [required]
48
- * @param {boolean} options.enabled - If set to false, the query won't be executed
49
- * @param {object} options.fetchPolicy - Fetch policy
50
- * @param {object} options.singleDocData - If true, the "data" returned will be
48
+ * @typedef {object} UseQueryOptions
49
+ * @property {object} as - Name for the query [required]
50
+ * @property {boolean} enabled - If set to false, the query won't be executed
51
+ * @property {object} fetchPolicy - Fetch policy
52
+ * @property {object} singleDocData - If true, the "data" returned will be
51
53
  * a single doc instead of an array for single doc queries. Defaults to false for backward
52
54
  * compatibility but will be set to true in the future.
55
+ * @property {Function} onError - Callback if the query is errored
53
56
  *
54
57
  * @returns {UseQueryReturnValue}
55
58
  */
@@ -1,13 +1,20 @@
1
1
  import { renderHook } from '@testing-library/react-hooks'
2
2
 
3
+ import CozyClient from '../CozyClient'
4
+ import CozyLink from '../CozyLink'
3
5
  import useQuery, { useQueries } from './useQuery'
4
6
  import { Q } from '../queries/dsl'
5
7
 
6
8
  import { setupClient, makeWrapper } from '../testing/utils'
7
9
  import simpsonsFixture from '../testing/simpsons.json'
8
10
 
9
- const setupQuery = ({ queryDefinition, queryOptions, storeQueries }) => {
10
- const client = setupClient({ queries: storeQueries })
11
+ const setupQuery = ({
12
+ customClient,
13
+ queryDefinition,
14
+ queryOptions,
15
+ storeQueries
16
+ }) => {
17
+ const client = customClient || setupClient({ queries: storeQueries })
11
18
  const hookResult = renderHook(() => useQuery(queryDefinition, queryOptions), {
12
19
  wrapper: makeWrapper(client)
13
20
  })
@@ -159,6 +166,30 @@ describe('use query', () => {
159
166
  expect(lastCallArgs).toMatchObject({ skip: current.data.length })
160
167
  expect(fetchMoreResult).toEqual({ data: null })
161
168
  })
169
+
170
+ it('should call onError callback when an error is thrown. Callback passed as argument', async () => {
171
+ jest.spyOn(console, 'error').mockImplementation(() => null)
172
+ const requestHandler = jest.fn()
173
+ const client = new CozyClient({
174
+ links: [new CozyLink(requestHandler)]
175
+ })
176
+ const error = new TypeError('Failed to fetch')
177
+ requestHandler.mockReturnValue(Promise.reject(error))
178
+ const onError = jest.fn().mockReturnValue(() => true)
179
+ setupQuery({
180
+ customClient: client,
181
+ queryOptions: {
182
+ as: 'fake-query',
183
+ onError
184
+ },
185
+ queryDefinition: () => Q('io.cozy.todos')
186
+ })
187
+
188
+ // TODO find a better alternative
189
+ setTimeout(() => {
190
+ expect(onError).toBeCalled()
191
+ }, 100)
192
+ })
162
193
  })
163
194
 
164
195
  describe('use queries', () => {
@@ -5,9 +5,27 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.helpers = exports.themes = exports.locales = exports.default = void 0;
8
+ Object.defineProperty(exports, "Qualification", {
9
+ enumerable: true,
10
+ get: function get() {
11
+ return _qualification.Qualification;
12
+ }
13
+ });
14
+ Object.defineProperty(exports, "setQualification", {
15
+ enumerable: true,
16
+ get: function get() {
17
+ return _qualification.setQualification;
18
+ }
19
+ });
20
+ Object.defineProperty(exports, "getQualification", {
21
+ enumerable: true,
22
+ get: function get() {
23
+ return _qualification.getQualification;
24
+ }
25
+ });
26
+ exports.helpers = exports.themes = exports.locales = void 0;
9
27
 
10
- var qualification = _interopRequireWildcard(require("./qualification"));
28
+ var _qualification = require("./qualification");
11
29
 
12
30
  var locales = _interopRequireWildcard(require("./locales"));
13
31
 
@@ -19,6 +37,4 @@ exports.themes = themes;
19
37
 
20
38
  var helpers = _interopRequireWildcard(require("./documentTypeDataHelpers"));
21
39
 
22
- exports.helpers = helpers;
23
- var _default = qualification;
24
- exports.default = _default;
40
+ exports.helpers = helpers;
@@ -47,7 +47,7 @@ var contact = _interopRequireWildcard(require("./contact"));
47
47
 
48
48
  exports.contact = contact;
49
49
 
50
- var document = _interopRequireWildcard(require("./document/index"));
50
+ var document = _interopRequireWildcard(require("./document"));
51
51
 
52
52
  exports.document = document;
53
53
 
package/dist/types.js CHANGED
@@ -85,7 +85,8 @@ var _dsl = require("./queries/dsl");
85
85
  * @property {string} [as] - Name of the query
86
86
  * @property {Function} [fetchPolicy] - Fetch policy to bypass fetching based on what's already inside the state. See "Fetch policies"
87
87
  * @property {AutoUpdateOptions} [autoUpdate] - Options for the query auto update
88
- * @property {string} [options.update] - Does not seem to be used
88
+ * @property {string} [update] - Does not seem to be used
89
+ * @property {Function} [onError] - Callback when the query is errored
89
90
  */
90
91
 
91
92
  /**
@@ -98,12 +99,32 @@ var _dsl = require("./queries/dsl");
98
99
  */
99
100
 
100
101
  /**
101
- * A reference to a document (special case of a relationship used between photos and albums)
102
+ * A reference to a document
103
+ *
104
+ * @typedef {object} ReferencedByRelationship
105
+ * @property {RelationshipParent} [parent]
106
+ * @property {ReferencedBy} [referenced_by]
107
+ */
108
+
109
+ /**
110
+ * @typedef {object} RelationshipParent
111
+ * @property {{related: string}} links
112
+ * @property {Reference} [data]
113
+ */
114
+
115
+ /**
116
+ * @typedef {object} ReferencedBy
117
+ * @property {{self: string}} links
118
+ * @property {Reference[]|null} data
119
+ */
120
+
121
+ /**
122
+ * A reference to a document
102
123
  * https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.files/#references
103
124
  *
104
125
  * @typedef {object} Reference
105
- * @property {string} _id - id of the document
106
- * @property {string} _type - doctype of the document
126
+ * @property {string} id - id of the document
127
+ * @property {string} type - doctype of the document
107
128
  */
108
129
 
109
130
  /**
@@ -124,7 +145,8 @@ var _dsl = require("./queries/dsl");
124
145
  * @property {string} [_type] - Type of the document
125
146
  * @property {string} [_rev] - Current revision of the document
126
147
  * @property {boolean} [_deleted] - When the document has been deleted
127
- * @property {object} [relationships] - Relationships of the document
148
+ * @property {ReferencedByRelationship} [relationships] - Relationships of the document
149
+ * @property {Reference[]} [referenced_by] - referenced by of another document
128
150
  */
129
151
 
130
152
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "27.3.0",
3
+ "version": "27.5.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -69,5 +69,5 @@
69
69
  "react-native-inappbrowser-reborn": "^3.5.1"
70
70
  },
71
71
  "sideEffects": false,
72
- "gitHead": "a425c10bf4937c815beee378cfeca7a13ce728c2"
72
+ "gitHead": "4d49dc4e8d6fcb949cc5d28b5bc1f5bda126560d"
73
73
  }
@@ -10,6 +10,10 @@ export type ClientOptions = {
10
10
  autoHydrate?: boolean;
11
11
  oauth?: object;
12
12
  onTokenRefresh?: Function;
13
+ /**
14
+ * - Default callback if a query is errored
15
+ */
16
+ onError?: Function;
13
17
  /**
14
18
  * - Schema description for each doctypes
15
19
  */
@@ -39,7 +43,7 @@ export type ClientOptions = {
39
43
  * @property {boolean} [autoHydrate]
40
44
  * @property {object} [oauth]
41
45
  * @property {Function} [onTokenRefresh]
42
- * @property {Function} [onTokenRefresh]
46
+ * @property {Function} [onError] - Default callback if a query is errored
43
47
  * @property {Link} [link] - Backward compatibility
44
48
  * @property {Array<Link>} [links] - List of links
45
49
  * @property {object} [schema] - Schema description for each doctypes
@@ -146,6 +150,10 @@ declare class CozyClient {
146
150
  autoHydrate?: boolean;
147
151
  oauth?: object;
148
152
  onTokenRefresh?: Function;
153
+ /**
154
+ * - Default callback if a query is errored
155
+ */
156
+ onError?: Function;
149
157
  /**
150
158
  * - If set to false, the client will not instantiate a Redux store automatically. Use this if you want to merge cozy-client's store with your own redux store. See [here](https://docs.cozy.io/en/cozy-client/react-integration/#1b-use-your-own-redux-store) for more information.
151
159
  */
@@ -640,6 +648,12 @@ declare class CozyClient {
640
648
  * @param {object} data - Data that is inserted in the store. Shape: { doctype: [data] }
641
649
  */
642
650
  setData(data: object): void;
651
+ /**
652
+ * At any time put an error function
653
+ *
654
+ * @param {Function} [onError] - Set a callback for queries which are errored
655
+ */
656
+ setOnError(onError?: Function): void;
643
657
  toJSON(): SnapshotClient;
644
658
  }
645
659
  declare namespace CozyClient {
@@ -7,3 +7,10 @@ export function create(target: any, { name, type, doctype }: {
7
7
  type: any;
8
8
  doctype: any;
9
9
  }, accessors: any): any;
10
+ export function isReferencedBy(file: IOCozyFile, referencedBy: Doctype): boolean;
11
+ export function isReferencedById(file: IOCozyFile, referencedBy: Doctype, referencedId: string): boolean;
12
+ export function getReferencedBy(file: IOCozyFile, referencedBy: Doctype): Reference[];
13
+ export function getReferencedById(file: IOCozyFile, referencedBy: Doctype, referencedId: string): Reference[];
14
+ import { IOCozyFile } from "../types";
15
+ import { Doctype } from "../types";
16
+ import { Reference } from "../types";
@@ -6,4 +6,4 @@ import HasOneInPlace from "./HasOneInPlace";
6
6
  import HasManyInPlace from "./HasManyInPlace";
7
7
  import HasManyTriggers from "./HasManyTriggers";
8
8
  export { Association, HasManyFiles, HasMany, HasOne, HasOneInPlace, HasManyInPlace, HasManyTriggers };
9
- export { resolveClass, create } from "./helpers";
9
+ export { resolveClass, create, isReferencedBy, isReferencedById, getReferencedBy, getReferencedById } from "./helpers";
@@ -1,24 +1,48 @@
1
1
  export function useQueries(querySpecs: any): {};
2
2
  export default useQuery;
3
+ /**
4
+ * Fetches a queryDefinition and returns the queryState
5
+ */
6
+ export type UseQueryOptions = {
7
+ /**
8
+ * - Name for the query [required]
9
+ */
10
+ as: object;
11
+ /**
12
+ * - If set to false, the query won't be executed
13
+ */
14
+ enabled: boolean;
15
+ /**
16
+ * - Fetch policy
17
+ */
18
+ fetchPolicy: object;
19
+ /**
20
+ * - If true, the "data" returned will be
21
+ * a single doc instead of an array for single doc queries. Defaults to false for backward
22
+ * compatibility but will be set to true in the future.
23
+ */
24
+ singleDocData: object;
25
+ /**
26
+ * - Callback if the query is errored
27
+ */
28
+ onError: Function;
29
+ };
3
30
  /**
4
31
  * Fetches a queryDefinition and returns the queryState
5
32
  *
6
- * @param {object} queryDefinition - Definition created with Q()
33
+ * @param {QueryDefinition} queryDefinition - Definition created with Q()
7
34
  *
8
- * @param {object} options - Options
9
- * @param {object} options.as - Name for the query [required]
10
- * @param {boolean} options.enabled - If set to false, the query won't be executed
11
- * @param {object} options.fetchPolicy - Fetch policy
12
- * @param {object} options.singleDocData - If true, the "data" returned will be
35
+ * @typedef {object} UseQueryOptions
36
+ * @property {object} as - Name for the query [required]
37
+ * @property {boolean} enabled - If set to false, the query won't be executed
38
+ * @property {object} fetchPolicy - Fetch policy
39
+ * @property {object} singleDocData - If true, the "data" returned will be
13
40
  * a single doc instead of an array for single doc queries. Defaults to false for backward
14
41
  * compatibility but will be set to true in the future.
42
+ * @property {Function} onError - Callback if the query is errored
15
43
  *
16
44
  * @returns {UseQueryReturnValue}
17
45
  */
18
- declare function useQuery(queryDefinition: object, options: {
19
- as: object;
20
- enabled: boolean;
21
- fetchPolicy: object;
22
- singleDocData: object;
23
- }): UseQueryReturnValue;
46
+ declare function useQuery(queryDefinition: QueryDefinition, options: any): UseQueryReturnValue;
47
+ import { QueryDefinition } from "../queries/dsl";
24
48
  import { UseQueryReturnValue } from "../types";
@@ -1,6 +1,7 @@
1
- export default qualification;
2
- import * as qualification from "./qualification";
1
+ import { Qualification } from "./qualification";
2
+ import { setQualification } from "./qualification";
3
+ import { getQualification } from "./qualification";
3
4
  import * as locales from "./locales";
4
5
  import * as themes from "./documentTypeData";
5
6
  import * as helpers from "./documentTypeDataHelpers";
6
- export { locales, themes, helpers };
7
+ export { Qualification, setQualification, getQualification, locales, themes, helpers };
@@ -0,0 +1,7 @@
1
+ export function isReferencedBy(file: IOCozyFile, referencedBy: Doctype): boolean;
2
+ export function isReferencedById(file: IOCozyFile, referencedBy: Doctype, referencedId: string): boolean;
3
+ export function getReferencedBy(file: IOCozyFile, referencedBy: Doctype): Reference[];
4
+ export function getReferencedById(file: IOCozyFile, referencedBy: Doctype, referencedId: string): Reference[];
5
+ import { IOCozyFile } from "../types";
6
+ import { Doctype } from "../types";
7
+ import { Reference } from "../types";
package/types/types.d.ts CHANGED
@@ -64,24 +64,47 @@ export type QueryOptions = {
64
64
  * - Does not seem to be used
65
65
  */
66
66
  update?: string;
67
+ /**
68
+ * - Callback when the query is errored
69
+ */
70
+ onError?: Function;
67
71
  };
68
72
  export type FetchMoreAble = {
69
73
  fetchMore: Function;
70
74
  };
71
75
  export type UseQueryReturnValue = QueryState & FetchMoreAble;
72
76
  /**
73
- * A reference to a document (special case of a relationship used between photos and albums)
77
+ * A reference to a document
78
+ */
79
+ export type ReferencedByRelationship = {
80
+ parent?: RelationshipParent;
81
+ referenced_by?: ReferencedBy;
82
+ };
83
+ export type RelationshipParent = {
84
+ links: {
85
+ related: string;
86
+ };
87
+ data?: Reference;
88
+ };
89
+ export type ReferencedBy = {
90
+ links: {
91
+ self: string;
92
+ };
93
+ data: Reference[] | null;
94
+ };
95
+ /**
96
+ * A reference to a document
74
97
  * https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.files/#references
75
98
  */
76
99
  export type Reference = {
77
100
  /**
78
101
  * - id of the document
79
102
  */
80
- _id: string;
103
+ id: string;
81
104
  /**
82
105
  * - doctype of the document
83
106
  */
84
- _type: string;
107
+ type: string;
85
108
  };
86
109
  export type ReferenceMap = {
87
110
  [x: string]: Reference[];
@@ -118,7 +141,11 @@ export type CozyClientDocument = {
118
141
  /**
119
142
  * - Relationships of the document
120
143
  */
121
- relationships?: object;
144
+ relationships?: ReferencedByRelationship;
145
+ /**
146
+ * - referenced by of another document
147
+ */
148
+ referenced_by?: Reference[];
122
149
  };
123
150
  /**
124
151
  * - An io.cozy.files document