cozy-client 59.3.0 → 60.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -152,7 +152,7 @@ var DOC_UPDATE = 'update';
152
152
  * @property {string} [uri]
153
153
  * @property {object} [stackClient]
154
154
  * @property {boolean} [warningForCustomHandlers]
155
- * @property {boolean} [autoHydrate]
155
+ * @property {boolean} [autoHydrate] - If set to true, all documents will be hydrated w.r.t. the provided schema's relationships, even if the relationship does not exist on the doc.
156
156
  * @property {boolean} [backgroundFetching] - If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won't be updated during future fetches. Instead, a `isFetching` attribute will be used to indicate when background fetching is started.
157
157
  * @property {object} [oauth]
158
158
  * @property {Function} [onTokenRefresh]
@@ -163,8 +163,7 @@ var DOC_UPDATE = 'update';
163
163
  * @property {import("./types").AppMetadata} [appMetadata] - Metadata about the application that will be used in ensureCozyMetadata
164
164
  * @property {import("./types").ClientCapabilities} [capabilities] - Capabilities sent by the stack
165
165
  * @property {boolean} [useCustomStore=false] - If set to true, 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. Note will have to call `setStore` eventually. See [here](https://docs.cozy.io/en/cozy-client/react-integration/#1b-use-your-own-redux-store) for more information.
166
- * @property {boolean} [disableStoreForQueries=false] - If set to true, the client will not leverage the redux store to execute queries and store data.
167
-
166
+ * @property {boolean} [disableStoreForQueries=false] - If set to true, the client will not leverage the redux store to execute queries and store data.
168
167
  * @property {import('./performances/types').PerformanceAPI} [performanceApi] - The performance API that can be used to measure performances
169
168
  */
170
169
 
@@ -317,6 +316,7 @@ var CozyClient = /*#__PURE__*/function () {
317
316
  this.ensureStore();
318
317
  }
319
318
 
319
+ this.autoHydrate = _options.autoHydrate || false;
320
320
  this.disableStoreForQueries = _options.disableStoreForQueries || false;
321
321
  }
322
322
  /**
@@ -2017,7 +2017,7 @@ var CozyClient = /*#__PURE__*/function () {
2017
2017
  if (queryDef instanceof _dsl.QueryDefinition) {
2018
2018
  definitions.push(queryDef);
2019
2019
  } else {
2020
- documents.push(queryDef);
2020
+ documents.push(doc);
2021
2021
  }
2022
2022
  } catch (_unused) {// eslint-disable-next-line
2023
2023
  // We do not crash completely if one the relationship behaves badly and
@@ -2159,10 +2159,6 @@ var CozyClient = /*#__PURE__*/function () {
2159
2159
  value: function hydrateDocuments(doctype, documents) {
2160
2160
  var _this8 = this;
2161
2161
 
2162
- if (this.options.autoHydrate === false) {
2163
- return documents;
2164
- }
2165
-
2166
2162
  var schema = this.schema.getDoctypeSchema(doctype);
2167
2163
  var relationships = schema.relationships;
2168
2164
 
@@ -2193,29 +2189,22 @@ var CozyClient = /*#__PURE__*/function () {
2193
2189
  }
2194
2190
 
2195
2191
  var schema = schemaArg || this.schema.getDoctypeSchema(document._type);
2196
- return _objectSpread(_objectSpread({}, document), this.hydrateRelationships(document, schema.relationships));
2192
+ var hydratedRelationships = this.hydrateRelationships(document, schema.relationships);
2193
+ return _objectSpread(_objectSpread({}, document), hydratedRelationships);
2197
2194
  }
2198
2195
  }, {
2199
2196
  key: "hydrateRelationships",
2200
2197
  value: function hydrateRelationships(document, schemaRelationships) {
2198
+ var _this9 = this;
2199
+
2201
2200
  var methods = this.getRelationshipStoreAccessors();
2202
2201
  return (0, _mapValues.default)(schemaRelationships, function (assoc, name) {
2203
- return (0, _associations.create)(document, assoc, methods);
2204
- });
2205
- }
2206
- /**
2207
- * Creates (locally) a new document for the given doctype.
2208
- * This document is hydrated : its relationships are there
2209
- * and working.
2210
- */
2202
+ var _this9$options, _document$relationshi;
2211
2203
 
2212
- }, {
2213
- key: "makeNewDocument",
2214
- value: function makeNewDocument(doctype) {
2215
- var obj = {
2216
- _type: doctype
2217
- };
2218
- return this.hydrateDocument(obj);
2204
+ if ((_this9$options = _this9.options) !== null && _this9$options !== void 0 && _this9$options.autoHydrate || (_document$relationshi = document.relationships) !== null && _document$relationshi !== void 0 && _document$relationshi[name]) {
2205
+ return (0, _associations.create)(document, assoc, methods);
2206
+ }
2207
+ });
2219
2208
  }
2220
2209
  }, {
2221
2210
  key: "generateRandomId",
@@ -2243,20 +2232,20 @@ var CozyClient = /*#__PURE__*/function () {
2243
2232
  }, {
2244
2233
  key: "getRelationshipStoreAccessors",
2245
2234
  value: function getRelationshipStoreAccessors() {
2246
- var _this9 = this;
2235
+ var _this10 = this;
2247
2236
 
2248
2237
  if (!this.storeAccesors) {
2249
2238
  this.storeAccessors = {
2250
2239
  get: this.getDocumentFromState.bind(this),
2251
2240
  save: function save(document, opts) {
2252
- return _this9.save.call(_this9, document, opts);
2241
+ return _this10.save.call(_this10, document, opts);
2253
2242
  },
2254
2243
  dispatch: this.dispatch.bind(this),
2255
2244
  query: function query(def, opts) {
2256
- return _this9.query.call(_this9, def, opts);
2245
+ return _this10.query.call(_this10, def, opts);
2257
2246
  },
2258
2247
  mutate: function mutate(def, opts) {
2259
- return _this9.mutate.call(_this9, def, opts);
2248
+ return _this10.mutate.call(_this10, def, opts);
2260
2249
  }
2261
2250
  };
2262
2251
  }
@@ -2307,7 +2296,7 @@ var CozyClient = /*#__PURE__*/function () {
2307
2296
  *
2308
2297
  * @param {string} id - Id of the query (set via Query.props.as)
2309
2298
  * @param {object} options - Options
2310
- * @param {boolean} [options.hydrated] - Whether documents should be returned already hydrated (default: false)
2299
+ * @param {boolean} [options.hydrated] - Whether documents should be returned already hydrated
2311
2300
  * @param {object} [options.singleDocData] - If true, the "data" returned will be
2312
2301
  * a single doc instead of an array for single doc queries. Defaults to false for backward
2313
2302
  * compatibility but will be set to true in the future.
@@ -2319,22 +2308,33 @@ var CozyClient = /*#__PURE__*/function () {
2319
2308
  key: "getQueryFromState",
2320
2309
  value: function getQueryFromState(id) {
2321
2310
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2322
- var hydrated = options.hydrated || false;
2323
- var singleDocData = options.singleDocData || false;
2311
+ var singleDocData = options.singleDocData || false; // `hydrated` has priority over global `autoHydrate`
2312
+
2313
+ var shouldHydrate = options.hydrated !== undefined ? options.hydrated : this.options.autoHydrate;
2324
2314
 
2325
2315
  try {
2316
+ var _this$schema$getDocty;
2317
+
2326
2318
  var queryResults = (0, _store.getQueryFromState)(this.store.getState(), id);
2327
2319
  var doctype = queryResults.definition && queryResults.definition.doctype;
2328
2320
  var isSingleDocQuery = queryResults.definition && queryResults.definition.id;
2329
2321
 
2330
- if (!hydrated && !singleDocData) {
2322
+ if (!shouldHydrate && !singleDocData) {
2331
2323
  // Early return let's us preserve reference equality in the simple case
2332
2324
  return queryResults;
2333
2325
  }
2334
2326
 
2335
- var data = hydrated && doctype ? this.hydrateDocuments(doctype, queryResults.data) : queryResults.data;
2327
+ var hydratedData = shouldHydrate && doctype ? this.hydrateDocuments(doctype, queryResults.data) : queryResults.data;
2328
+ var relationships = (_this$schema$getDocty = this.schema.getDoctypeSchema(doctype)) === null || _this$schema$getDocty === void 0 ? void 0 : _this$schema$getDocty.relationships;
2329
+ var relationshipNames = relationships ? Object.keys(relationships) : null; // The `data` array contains the hydrated data with the relationships, if any.
2330
+ // The `storeData` array contains the documents from the store: this is useful to preserve
2331
+ // referential equality, to be later evaluated to determine whether or not the
2332
+ // documents had changed.
2333
+
2336
2334
  return _objectSpread(_objectSpread({}, queryResults), {}, {
2337
- data: isSingleDocQuery && singleDocData ? data[0] : data
2335
+ data: isSingleDocQuery && singleDocData ? hydratedData[0] : hydratedData,
2336
+ storeData: isSingleDocQuery && singleDocData ? queryResults.data[0] : queryResults.data,
2337
+ relationshipNames: relationshipNames
2338
2338
  });
2339
2339
  } catch (e) {
2340
2340
  _logger.default.warn("Could not get query from state. queryId: ".concat(id, ", error: ").concat(e.message));
@@ -2838,7 +2838,7 @@ var CozyClient = /*#__PURE__*/function () {
2838
2838
  }, {
2839
2839
  key: "setData",
2840
2840
  value: function setData(data) {
2841
- var _this10 = this;
2841
+ var _this11 = this;
2842
2842
 
2843
2843
  this.ensureStore();
2844
2844
  Object.entries(data).forEach(function (_ref9) {
@@ -2846,7 +2846,7 @@ var CozyClient = /*#__PURE__*/function () {
2846
2846
  doctype = _ref10[0],
2847
2847
  data = _ref10[1];
2848
2848
 
2849
- _this10.dispatch((0, _store.receiveQueryResult)(null, {
2849
+ _this11.dispatch((0, _store.receiveQueryResult)(null, {
2850
2850
  data: data
2851
2851
  }));
2852
2852
  });
@@ -3264,7 +3264,7 @@ var CozyClient = /*#__PURE__*/function () {
3264
3264
  CozyClient.hooks = CozyClient.hooks || {};
3265
3265
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
3266
3266
 
3267
- CozyClient.version = "59.3.0";
3267
+ CozyClient.version = "60.0.0";
3268
3268
 
3269
3269
  _microee.default.mixin(CozyClient);
3270
3270
 
@@ -11,7 +11,8 @@ import {
11
11
  APP_VERSION,
12
12
  SOURCE_ACCOUNT_ID,
13
13
  SOURCE_ACCOUNT_IDENTIFIER,
14
- FILE_1
14
+ FILE_1,
15
+ TODO_WITH_NONEXISTING_RELATIONSHIP
15
16
  } from './__tests__/fixtures'
16
17
  import { withIgnoreConsoleWarn } from './__tests__/console'
17
18
 
@@ -34,7 +35,7 @@ import {
34
35
  resetQuery,
35
36
  executeQueryFromState
36
37
  } from './store'
37
- import { HasManyFiles, Association, HasMany } from './associations'
38
+ import { HasManyFiles, Association } from './associations'
38
39
  import mapValues from 'lodash/mapValues'
39
40
  import FileCollection from 'cozy-stack-client/dist/FileCollection'
40
41
  import logger from './logger'
@@ -1016,7 +1017,16 @@ describe('CozyClient', () => {
1016
1017
  const NEW_TODO = {
1017
1018
  _type: 'io.cozy.todos',
1018
1019
  label: 'Buy RAM',
1019
- attachments: [{ _id: 12345, _type: 'io.cozy.files' }]
1020
+ relationships: {
1021
+ attachments: {
1022
+ data: [
1023
+ {
1024
+ _type: 'io.cozy.files',
1025
+ _id: 1
1026
+ }
1027
+ ]
1028
+ }
1029
+ }
1020
1030
  }
1021
1031
  const EXPECTED_CREATED_TODO = { _id: 67890, ...NEW_TODO }
1022
1032
  const mutation = client.getDocumentSavePlan(NEW_TODO, {
@@ -1040,9 +1050,14 @@ describe('CozyClient', () => {
1040
1050
  id: 67890,
1041
1051
  type: 'io.cozy.files'
1042
1052
  }
1043
- ]
1053
+ ],
1054
+ relationships: { icons: [{ _id: 67890, _type: 'io.cozy.files' }] }
1055
+ }
1056
+ const EXPECTED_CREATED_FILE = {
1057
+ _id: 12345,
1058
+ _type: 'io.cozy.files',
1059
+ relationships: { icons: [{ _id: 67890, _type: 'io.cozy.files' }] }
1044
1060
  }
1045
- const EXPECTED_CREATED_FILE = { _id: 12345, _type: 'io.cozy.files' }
1046
1061
  const mutation = client.getDocumentSavePlan(NEW_FILE, {
1047
1062
  icons: [
1048
1063
  {
@@ -1907,14 +1922,6 @@ describe('CozyClient', () => {
1907
1922
  )
1908
1923
  .shift()
1909
1924
  expect(doc.attachments).toBeInstanceOf(HasManyFiles)
1910
- expect(doc.authors).toBeInstanceOf(HasMany)
1911
- })
1912
-
1913
- it('makes new documents', () => {
1914
- const newTodo = client.makeNewDocument('io.cozy.todos')
1915
- expect(newTodo._type).toBe('io.cozy.todos')
1916
- expect(newTodo.attachments).not.toBe(undefined)
1917
- expect(newTodo.attachments instanceof HasManyFiles).toBe(true)
1918
1925
  })
1919
1926
 
1920
1927
  it('should not fail on null (when getting absent documents from the store)', () => {
@@ -1923,6 +1930,53 @@ describe('CozyClient', () => {
1923
1930
  .shift()
1924
1931
  expect(doc).toBe(null)
1925
1932
  })
1933
+
1934
+ it('should hydrate relationships if the relationship exists', () => {
1935
+ const resp = client.hydrateDocument(TODO_WITH_AUTHOR)
1936
+ expect(resp.authors).not.toBe(undefined)
1937
+ expect(resp.attachments).toBe(undefined)
1938
+ })
1939
+
1940
+ it('should not hydrate relationships if the relationship does not exist', () => {
1941
+ const resp = client.hydrateDocument(TODO_WITH_NONEXISTING_RELATIONSHIP)
1942
+ expect(resp.authors).toBe(undefined)
1943
+ expect(resp.attachments).toBe(undefined)
1944
+ expect(resp.broken).toBe(undefined)
1945
+ })
1946
+
1947
+ it('should not hydrate relationships if not specified', () => {
1948
+ getQueryFromState.mockReturnValueOnce({
1949
+ definition: { doctype: 'io.cozy.todos' },
1950
+ data: [TODO_WITH_AUTHOR]
1951
+ })
1952
+ const resp = client.getQueryFromState('allTodos')
1953
+ expect(resp.data[0].authors).toBe(undefined)
1954
+ expect(resp.data[0].attachments).toBe(undefined)
1955
+ })
1956
+
1957
+ it('should hydrate relationships only if the relationship does exist ', () => {
1958
+ getQueryFromState.mockReturnValueOnce({
1959
+ definition: { doctype: 'io.cozy.todos' },
1960
+ data: [TODO_WITH_AUTHOR]
1961
+ })
1962
+ const resp = client.getQueryFromState('allTodos', { hydrated: true })
1963
+ expect(resp.data[0].authors).not.toBe(undefined)
1964
+ expect(resp.data[0].attachments).toBe(undefined)
1965
+ })
1966
+
1967
+ it('should hydrate relationships if the relationship does not exist but hydration is forced', () => {
1968
+ const newClient = new CozyClient({
1969
+ schema: SCHEMA,
1970
+ autoHydrate: true
1971
+ })
1972
+ getQueryFromState.mockReturnValueOnce({
1973
+ definition: { doctype: 'io.cozy.todos' },
1974
+ data: [TODO_WITH_AUTHOR]
1975
+ })
1976
+ const resp = newClient.getQueryFromState('allTodos')
1977
+ expect(resp.data[0].authors).not.toBe(undefined)
1978
+ expect(resp.data[0].attachments).not.toBe(undefined)
1979
+ })
1926
1980
  })
1927
1981
 
1928
1982
  describe('serialization', () => {
@@ -2122,7 +2176,8 @@ describe('file creation', () => {
2122
2176
  .fn()
2123
2177
  .mockResolvedValueOnce({
2124
2178
  data: {
2125
- _id: '1337'
2179
+ _id: '1337',
2180
+ relationships: { icons: [{ _id: 1, _type: 'io.cozy.files' }] }
2126
2181
  }
2127
2182
  })
2128
2183
  .mockResolvedValueOnce({
@@ -195,6 +195,8 @@ describe('Query', () => {
195
195
  count: 0,
196
196
  fetchedPagesCount: 0,
197
197
  data: [],
198
+ storeData: [],
199
+ relationshipNames: null,
198
200
  definition: { doctype: 'io.cozy.todos' },
199
201
  fetch: expect.any(Function),
200
202
  fetchMore: expect.any(Function),
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SCHEMA = exports.SOURCE_ACCOUNT_IDENTIFIER = exports.SOURCE_ACCOUNT_ID = exports.DOCTYPE_VERSION = exports.APP_VERSION = exports.APP_NAME = exports.FILE_2 = exports.FILE_1 = exports.TODO_WITH_AUTHOR = exports.AUTHORS = exports.TODO_WITH_RELATION = exports.TODOS = exports.TODO_4 = exports.TODO_3 = exports.TODO_2 = exports.TODO_1 = void 0;
6
+ exports.SCHEMA = exports.SOURCE_ACCOUNT_IDENTIFIER = exports.SOURCE_ACCOUNT_ID = exports.DOCTYPE_VERSION = exports.APP_VERSION = exports.APP_NAME = exports.FILE_2 = exports.FILE_1 = exports.TODO_WITH_NONEXISTING_RELATIONSHIP = exports.TODO_WITH_AUTHOR = exports.AUTHORS = exports.TODO_WITH_RELATION = exports.TODOS = exports.TODO_4 = exports.TODO_3 = exports.TODO_2 = exports.TODO_1 = void 0;
7
7
  var TODO_1 = {
8
8
  _id: 'todo_1',
9
9
  _rev: '4-43bdf4f7123f4d748645ba9536a46daa',
@@ -88,6 +88,22 @@ var TODO_WITH_AUTHOR = {
88
88
  }
89
89
  };
90
90
  exports.TODO_WITH_AUTHOR = TODO_WITH_AUTHOR;
91
+ var TODO_WITH_NONEXISTING_RELATIONSHIP = {
92
+ _id: 5,
93
+ _rev: '1-7f02bbb542fb4eb0805b130a80b9be1a',
94
+ _type: 'io.cozy.todos',
95
+ label: 'Todo with several authors',
96
+ relationships: {
97
+ broken: {
98
+ doctype: 'io.cozy.persons',
99
+ data: [{
100
+ _type: 'io.cozy.persons',
101
+ _id: 1
102
+ }]
103
+ }
104
+ }
105
+ };
106
+ exports.TODO_WITH_NONEXISTING_RELATIONSHIP = TODO_WITH_NONEXISTING_RELATIONSHIP;
91
107
  var FILE_1 = {
92
108
  _id: 1,
93
109
  _rev: '3-bd9bb7286a094842b954d9e86429090d',
@@ -25,6 +25,8 @@ var _context = require("../context");
25
25
 
26
26
  var _dsl = require("../queries/dsl");
27
27
 
28
+ var _selector = require("../store/selector");
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; }
@@ -83,7 +85,7 @@ var useQuery = function useQuery(queryDefinition, options) {
83
85
  hydrated: (0, _get.default)(options, 'hydrated', true),
84
86
  singleDocData: (0, _get.default)(options, 'singleDocData', false)
85
87
  });
86
- });
88
+ }, _selector.equalityCheckForQuery);
87
89
  (0, _react.useEffect)(function () {
88
90
  if (enabled === false) {
89
91
  return;
@@ -107,7 +107,7 @@ describe('use query', () => {
107
107
  })
108
108
 
109
109
  expect(Object.keys(current)).toEqual(
110
- expect.objectContaining([
110
+ expect.arrayContaining([
111
111
  'id',
112
112
  'definition',
113
113
  'fetchStatus',
@@ -120,6 +120,8 @@ describe('use query', () => {
120
120
  'count',
121
121
  'fetchedPagesCount',
122
122
  'data',
123
+ 'storeData',
124
+ 'relationshipNames',
123
125
  'bookmark',
124
126
  'options',
125
127
  'fetchMore',
@@ -32,6 +32,8 @@ Object {
32
32
  "lastFetch": null,
33
33
  "lastUpdate": null,
34
34
  "options": null,
35
+ "relationshipNames": Array [],
36
+ "storeData": Array [],
35
37
  },
36
38
  }
37
39
  `;
@@ -71,6 +73,8 @@ Object {
71
73
  "lastFetch": 1337,
72
74
  "lastUpdate": 1337,
73
75
  "options": null,
76
+ "relationshipNames": Array [],
77
+ "storeData": Array [],
74
78
  },
75
79
  }
76
80
  `;
@@ -109,6 +113,8 @@ Object {
109
113
  "lastFetch": 1337,
110
114
  "lastUpdate": 1337,
111
115
  "options": null,
116
+ "relationshipNames": Array [],
117
+ "storeData": Array [],
112
118
  },
113
119
  "b": Object {
114
120
  "bookmark": null,
@@ -147,6 +153,8 @@ Object {
147
153
  "lastFetch": null,
148
154
  "lastUpdate": 1337,
149
155
  "options": null,
156
+ "relationshipNames": Array [],
157
+ "storeData": Array [],
150
158
  },
151
159
  }
152
160
  `;
@@ -185,6 +193,8 @@ Object {
185
193
  "lastFetch": 1337,
186
194
  "lastUpdate": 1337,
187
195
  "options": null,
196
+ "relationshipNames": Array [],
197
+ "storeData": Array [],
188
198
  },
189
199
  "b": Object {
190
200
  "bookmark": null,
@@ -220,6 +230,8 @@ Object {
220
230
  "lastFetch": null,
221
231
  "lastUpdate": 1337,
222
232
  "options": null,
233
+ "relationshipNames": Array [],
234
+ "storeData": Array [],
223
235
  },
224
236
  }
225
237
  `;
@@ -264,6 +276,8 @@ Object {
264
276
  "lastFetch": 1337,
265
277
  "lastUpdate": 1337,
266
278
  "options": null,
279
+ "relationshipNames": Array [],
280
+ "storeData": Array [],
267
281
  },
268
282
  "b": Object {
269
283
  "bookmark": null,
@@ -297,6 +311,8 @@ Object {
297
311
  "lastFetch": null,
298
312
  "lastUpdate": null,
299
313
  "options": null,
314
+ "relationshipNames": Array [],
315
+ "storeData": Array [],
300
316
  },
301
317
  }
302
318
  `;
@@ -336,6 +352,8 @@ Object {
336
352
  "lastFetch": 1337,
337
353
  "lastUpdate": 1337,
338
354
  "options": null,
355
+ "relationshipNames": Array [],
356
+ "storeData": Array [],
339
357
  },
340
358
  "b": Object {
341
359
  "bookmark": null,
@@ -370,6 +388,8 @@ Object {
370
388
  "lastFetch": null,
371
389
  "lastUpdate": 1337,
372
390
  "options": null,
391
+ "relationshipNames": Array [],
392
+ "storeData": Array [],
373
393
  },
374
394
  }
375
395
  `;
@@ -408,6 +428,8 @@ Object {
408
428
  "lastFetch": 1337,
409
429
  "lastUpdate": 1337,
410
430
  "options": null,
431
+ "relationshipNames": Array [],
432
+ "storeData": Array [],
411
433
  },
412
434
  "b": Object {
413
435
  "bookmark": null,
@@ -445,6 +467,8 @@ Object {
445
467
  "add": false,
446
468
  },
447
469
  },
470
+ "relationshipNames": Array [],
471
+ "storeData": Array [],
448
472
  },
449
473
  }
450
474
  `;
@@ -481,6 +505,8 @@ Object {
481
505
  "lastFetch": null,
482
506
  "lastUpdate": null,
483
507
  "options": null,
508
+ "relationshipNames": Array [],
509
+ "storeData": Array [],
484
510
  },
485
511
  "b": Object {
486
512
  "bookmark": null,
@@ -512,6 +538,8 @@ Object {
512
538
  "lastFetch": 1337,
513
539
  "lastUpdate": 1337,
514
540
  "options": null,
541
+ "relationshipNames": Array [],
542
+ "storeData": Array [],
515
543
  },
516
544
  }
517
545
  `;
@@ -550,6 +578,8 @@ Object {
550
578
  "lastFetch": 1337,
551
579
  "lastUpdate": 1337,
552
580
  "options": null,
581
+ "relationshipNames": Array [],
582
+ "storeData": Array [],
553
583
  },
554
584
  "b": Object {
555
585
  "bookmark": null,
@@ -589,6 +619,8 @@ Object {
589
619
  "remove": false,
590
620
  },
591
621
  },
622
+ "relationshipNames": Array [],
623
+ "storeData": Array [],
592
624
  },
593
625
  }
594
626
  `;
@@ -627,6 +659,8 @@ Object {
627
659
  "lastFetch": 1337,
628
660
  "lastUpdate": 1337,
629
661
  "options": null,
662
+ "relationshipNames": Array [],
663
+ "storeData": Array [],
630
664
  },
631
665
  "b": Object {
632
666
  "bookmark": null,
@@ -660,6 +694,8 @@ Object {
660
694
  "lastFetch": null,
661
695
  "lastUpdate": null,
662
696
  "options": null,
697
+ "relationshipNames": Array [],
698
+ "storeData": Array [],
663
699
  },
664
700
  }
665
701
  `;
@@ -700,6 +736,8 @@ Object {
700
736
  "lastFetch": 1337,
701
737
  "lastUpdate": 1337,
702
738
  "options": null,
739
+ "relationshipNames": Array [],
740
+ "storeData": Array [],
703
741
  },
704
742
  "b": Object {
705
743
  "bookmark": null,
@@ -736,6 +774,8 @@ Object {
736
774
  "lastFetch": null,
737
775
  "lastUpdate": 1337,
738
776
  "options": null,
777
+ "relationshipNames": Array [],
778
+ "storeData": Array [],
739
779
  },
740
780
  }
741
781
  `;
@@ -94,7 +94,9 @@ var queryInitialState = {
94
94
  count: 0,
95
95
  fetchedPagesCount: 0,
96
96
  data: [],
97
- bookmark: null
97
+ storeData: [],
98
+ bookmark: null,
99
+ relationshipNames: []
98
100
  };
99
101
  /**
100
102
  * Return the docs ids accordingly to the given sort and fetched docs
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.equalityCheckForQuery = void 0;
7
+
8
+ 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; } } }; }
9
+
10
+ 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); }
11
+
12
+ 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; }
13
+
14
+ /**
15
+ * Perform an equality check to determine whether or not two query results are equal.
16
+ *
17
+ * This is typically called by a `useSelector`, to determine if a render should be made because
18
+ * the query result has changed.
19
+ * See https://react-redux.js.org/api/hooks#equality-comparisons-and-updates
20
+ *
21
+ * We cannot use the default strict reference comparison here, because a new reference for the query
22
+ * result is made every time. However, the query result itself, in `storeData`, preserves references.
23
+ *
24
+ * Note we do not make a shallow equality check on documents, as it is much less efficient.
25
+ * It is however different for relationships: because of their hydratation, the references change
26
+ * even if the data is the same.
27
+ *
28
+ * @param {import("../types").QueryState} queryResA - A query result to compare
29
+ * @param {import("../types").QueryState} queryResB - A query result to compare
30
+ * @returns {boolean} whether or not the two query are equal
31
+ */
32
+ var equalityCheckForQuery = function equalityCheckForQuery(queryResA, queryResB) {
33
+ if (queryResA === queryResB) {
34
+ // Referential equality
35
+ return true;
36
+ }
37
+
38
+ if (typeof queryResA !== 'object' || queryResA === null || typeof queryResB !== 'object' || queryResB === null) {
39
+ // queryResA or queryResB is not an object or null
40
+ return false;
41
+ }
42
+
43
+ if (queryResA.id !== queryResB.id) {
44
+ return false;
45
+ }
46
+
47
+ if (queryResA.fetchStatus !== queryResB.fetchStatus) {
48
+ return false;
49
+ }
50
+
51
+ var docsA = queryResA.storeData;
52
+ var docsB = queryResB.storeData;
53
+
54
+ if (!docsA || !docsB) {
55
+ // No data to check
56
+ return false;
57
+ }
58
+
59
+ if (!Array.isArray(docsA) && !Array.isArray(docsB) && docsA !== docsB) {
60
+ // Only one doc
61
+ return false;
62
+ }
63
+
64
+ if (Array.isArray(docsA) && Array.isArray(docsB) && !arraysHaveSameLength(docsA, docsB)) {
65
+ // A document was added or removed
66
+ return false;
67
+ }
68
+
69
+ if (Array.isArray(docsA) && Array.isArray(docsB)) {
70
+ for (var i = 0; i < docsA.length; i++) {
71
+ if (docsA[i] !== docsB[i]) {
72
+ // References should be the same for non-updated documents
73
+ return false;
74
+ }
75
+ }
76
+ }
77
+
78
+ if (queryResA.relationshipNames) {
79
+ // In case of relationships, we cannot check referential equality, because we
80
+ // "hydrate" the data by creating a new instance of the related relationship class.
81
+ // Thus, we check the document revision instead.
82
+ var hydratedDataA = queryResA.data;
83
+ var hydratedDataB = queryResB.data;
84
+
85
+ if (!Array.isArray(hydratedDataA) && !Array.isArray(hydratedDataB)) {
86
+ // One doc with changed relationship
87
+ return revsAreEqual(hydratedDataA, hydratedDataB);
88
+ }
89
+
90
+ if (!arraysHaveSameLength(hydratedDataA, hydratedDataB)) {
91
+ // A relationship have been added or removed
92
+ return false;
93
+ }
94
+
95
+ if (Array.isArray(hydratedDataA) && Array.isArray(hydratedDataB)) {
96
+ for (var _i = 0; _i < hydratedDataA.length; _i++) {
97
+ var _iterator = _createForOfIteratorHelper(queryResA.relationshipNames),
98
+ _step;
99
+
100
+ try {
101
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
102
+ var name = _step.value;
103
+ // Check hydrated relationship
104
+ var includedA = hydratedDataA[_i][name];
105
+ var includedB = hydratedDataB[_i][name];
106
+
107
+ if (includedA && includedB) {
108
+ if (!revsAreEqual(includedA, includedB)) {
109
+ return false;
110
+ }
111
+ }
112
+ }
113
+ } catch (err) {
114
+ _iterator.e(err);
115
+ } finally {
116
+ _iterator.f();
117
+ }
118
+ }
119
+ }
120
+ } // The query results are indeed equal
121
+
122
+
123
+ return true;
124
+ };
125
+
126
+ exports.equalityCheckForQuery = equalityCheckForQuery;
127
+
128
+ var revsAreEqual = function revsAreEqual(docA, docB) {
129
+ if (!docA._rev || !docB._rev) {
130
+ return false;
131
+ }
132
+
133
+ return (docA === null || docA === void 0 ? void 0 : docA._rev) === (docB === null || docB === void 0 ? void 0 : docB._rev);
134
+ };
135
+
136
+ var arraysHaveSameLength = function arraysHaveSameLength(arrayA, arrayB) {
137
+ return Array.isArray(arrayA) && Array.isArray(arrayB) && arrayA.length === arrayB.length;
138
+ };
@@ -0,0 +1,238 @@
1
+ import { equalityCheckForQuery } from './selector'
2
+
3
+ const mapIdsToDocuments = (state, doctype, ids) => {
4
+ return ids.map(id => state[doctype][id])
5
+ }
6
+
7
+ const state = {
8
+ documents: {
9
+ 'io.cozy.files': {
10
+ doc1: {
11
+ _id: 'doc1'
12
+ },
13
+ doc2: {
14
+ _id: 'doc2'
15
+ },
16
+ doc3: {
17
+ _id: 'doc3'
18
+ }
19
+ }
20
+ },
21
+ queries: {
22
+ query1: {
23
+ id: 'query1',
24
+ data: ['doc1', 'doc2']
25
+ },
26
+ query2: {
27
+ id: 'query2',
28
+ data: ['doc2']
29
+ }
30
+ }
31
+ }
32
+
33
+ const defaultQueryResult = {
34
+ id: 1,
35
+ data: [],
36
+ fetchStatus: 'loaded',
37
+ relationshipNames: null
38
+ }
39
+
40
+ describe('equalityCheckForQuery', () => {
41
+ const queryResultA1 = {
42
+ id: 1,
43
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
44
+ 'doc1',
45
+ 'doc2'
46
+ ]),
47
+ ...defaultQueryResult
48
+ }
49
+ const queryResultA2 = {
50
+ id: 1,
51
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
52
+ 'doc1',
53
+ 'doc2'
54
+ ]),
55
+ ...defaultQueryResult
56
+ }
57
+ const queryResultA3 = {
58
+ id: 1,
59
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
60
+ 'doc1',
61
+ 'doc2',
62
+ 'doc3'
63
+ ]),
64
+ ...defaultQueryResult
65
+ }
66
+ const queryResultA4 = {
67
+ id: 1,
68
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
69
+ 'doc2',
70
+ 'doc3'
71
+ ]),
72
+ ...defaultQueryResult
73
+ }
74
+ const queryResultB1 = {
75
+ id: 2,
76
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc2']),
77
+ ...defaultQueryResult
78
+ }
79
+
80
+ const queryResultB2 = {
81
+ id: 2,
82
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc3']),
83
+ ...defaultQueryResult
84
+ }
85
+
86
+ const queryResultC1 = {
87
+ id: 3,
88
+ storeData: state.documents['io.cozy.files'].doc1,
89
+ data: {},
90
+ ...defaultQueryResult
91
+ }
92
+
93
+ const queryResultC2 = {
94
+ id: 3,
95
+ storeData: state.documents['io.cozy.files'].doc1,
96
+ data: {},
97
+ ...defaultQueryResult
98
+ }
99
+
100
+ const queryResultC3 = {
101
+ id: 3,
102
+ storeData: state.documents['io.cozy.files'].doc2,
103
+ data: {},
104
+ ...defaultQueryResult
105
+ }
106
+
107
+ it('should return true for referential equality', () => {
108
+ expect(equalityCheckForQuery(queryResultA1, queryResultA1)).toBe(true)
109
+ expect(equalityCheckForQuery(null, null)).toBe(true)
110
+ })
111
+
112
+ it('should return false if one object is null', () => {
113
+ expect(equalityCheckForQuery(null, queryResultA1)).toBe(false)
114
+ expect(equalityCheckForQuery(queryResultA1, null)).toBe(false)
115
+ })
116
+
117
+ it('should return false if one or both objects are not objects', () => {
118
+ // @ts-ignore
119
+ expect(equalityCheckForQuery('notAnObject', queryResultA1)).toBe(false)
120
+ // @ts-ignore
121
+ expect(equalityCheckForQuery(queryResultA1, 'notAnObject')).toBe(false)
122
+ })
123
+
124
+ it('should return false if `id` properties are different', () => {
125
+ expect(equalityCheckForQuery(queryResultA1, queryResultB1)).toBe(false)
126
+ })
127
+
128
+ it('should return false if one or both objects lack `data`', () => {
129
+ // @ts-ignore
130
+ expect(equalityCheckForQuery({ id: 1 }, queryResultA1)).toBe(false)
131
+ // @ts-ignore
132
+ expect(equalityCheckForQuery(queryResultA1, { id: 1 })).toBe(false)
133
+ })
134
+
135
+ it('should return false if `data` lengths are different', () => {
136
+ expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false)
137
+ })
138
+
139
+ it('should return false if elements in `data` are different', () => {
140
+ expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false)
141
+ expect(equalityCheckForQuery(queryResultA3, queryResultA4)).toBe(false)
142
+ expect(equalityCheckForQuery(queryResultB1, queryResultB2)).toBe(false)
143
+ })
144
+
145
+ it('should return true for matching data array, with equal references ', () => {
146
+ expect(equalityCheckForQuery(queryResultA1, queryResultA2)).toBe(true)
147
+ })
148
+
149
+ it('should return false for matching data array, with different references ', () => {
150
+ const queryResShallowCopyA1 = {
151
+ ...queryResultA1,
152
+ storeData: JSON.parse(JSON.stringify(queryResultA1.storeData)) // Deep copy
153
+ }
154
+ expect(equalityCheckForQuery(queryResultA1, queryResShallowCopyA1)).toBe(
155
+ false
156
+ )
157
+ })
158
+
159
+ it('should return true for matching object data', () => {
160
+ expect(equalityCheckForQuery(queryResultC1, queryResultC2)).toBe(true)
161
+ })
162
+ it('should return false for different object data', () => {
163
+ expect(equalityCheckForQuery(queryResultC1, queryResultC3)).toBe(false)
164
+ })
165
+ })
166
+
167
+ describe('equalityCheckForQuery with relationships', () => {
168
+ const queryResA = {
169
+ ...defaultQueryResult,
170
+ relationshipNames: ['relation1'],
171
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
172
+ 'doc1',
173
+ 'doc2'
174
+ ]),
175
+ data: [{ relation1: { _rev: 'rev1' } }]
176
+ }
177
+
178
+ const queryResB = {
179
+ ...defaultQueryResult,
180
+ relationshipNames: ['relation1'],
181
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
182
+ 'doc1',
183
+ 'doc2'
184
+ ]),
185
+ data: [{ relation1: { _rev: 'rev2' } }]
186
+ }
187
+
188
+ const queryResC = {
189
+ ...defaultQueryResult,
190
+ relationshipNames: ['relation1'],
191
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
192
+ 'doc1',
193
+ 'doc2'
194
+ ]),
195
+ data: [{ relation1: { _rev: 'rev1' } }, { relation1: { _rev: 'rev2' } }]
196
+ }
197
+
198
+ const queryResD = {
199
+ ...defaultQueryResult,
200
+ relationshipNames: ['relation1', 'relation2'],
201
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', [
202
+ 'doc1',
203
+ 'doc2'
204
+ ]),
205
+ data: [{ relation1: { _rev: 'rev1' } }, { relation2: { _rev: 'rev2' } }]
206
+ }
207
+
208
+ const queryResE = {
209
+ ...defaultQueryResult,
210
+ relationshipNames: ['relation1'],
211
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1']),
212
+ data: [{ relation1: { _id: '123' } }]
213
+ }
214
+
215
+ const queryResF = {
216
+ ...defaultQueryResult,
217
+ relationshipNames: ['relation1'],
218
+ storeData: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1']),
219
+ data: [{ relation1: { _id: '123' } }]
220
+ }
221
+
222
+ it('returns true when data and relationship revisions match', () => {
223
+ expect(equalityCheckForQuery(queryResA, queryResA)).toBe(true)
224
+ expect(equalityCheckForQuery(queryResD, queryResD)).toBe(true)
225
+ })
226
+
227
+ it('returns false when relationship revisions differ', () => {
228
+ expect(equalityCheckForQuery(queryResA, queryResB)).toBe(false)
229
+ })
230
+
231
+ it('returns false when relationship revisions are missing', () => {
232
+ expect(equalityCheckForQuery(queryResE, queryResF)).toBe(false)
233
+ })
234
+
235
+ it('returns false when data lengths differ', () => {
236
+ expect(equalityCheckForQuery(queryResA, queryResC)).toBe(false)
237
+ })
238
+ })
@@ -408,7 +408,9 @@ describe('Store', () => {
408
408
  hasMore: false,
409
409
  count: 0,
410
410
  fetchedPagesCount: 0,
411
- data: null
411
+ data: null,
412
+ storeData: [],
413
+ relationshipNames: []
412
414
  })
413
415
  })
414
416
 
package/dist/types.js CHANGED
@@ -276,16 +276,22 @@ var _dsl = require("./queries/dsl");
276
276
  * @property {number} fetchedPagesCount
277
277
  * @property {string} bookmark
278
278
  * @property {object} [execution_stats]
279
+ * @property {Array<string>} relationshipNames - The relationships names, used to check hydrated documents
279
280
  * @property {QueryOptions} [options]
280
281
  */
281
282
 
282
283
  /**
283
284
  * @typedef {object} QueryStateData
284
- * @property {object|Array} data
285
+ * @property {object|Array} data - Collection of hydrated documents
285
286
  */
286
287
 
287
288
  /**
288
- * @typedef {QueryStateWithoutData & QueryStateData} QueryState
289
+ * @typedef {object} QueryStateStoreData
290
+ * @property {object|Array} storeData - Collection of store's documents
291
+ */
292
+
293
+ /**
294
+ * @typedef {QueryStateWithoutData & QueryStateData & QueryStateStoreData} QueryState
289
295
  */
290
296
 
291
297
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "59.3.0",
3
+ "version": "60.0.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -19,7 +19,7 @@
19
19
  "@types/jest": "^26.0.20",
20
20
  "@types/lodash": "^4.14.170",
21
21
  "btoa": "^1.2.1",
22
- "cozy-stack-client": "^59.3.0",
22
+ "cozy-stack-client": "^60.0.0",
23
23
  "date-fns": "2.29.3",
24
24
  "fast-deep-equal": "^3.1.3",
25
25
  "json-stable-stringify": "^1.0.1",
@@ -74,5 +74,5 @@
74
74
  "react-native-ios11-devicecheck": "^0.0.3"
75
75
  },
76
76
  "sideEffects": false,
77
- "gitHead": "baea78d5c14a8135d40a5eec689fa9be4aceaec8"
77
+ "gitHead": "a89eb840497357fb366bc97d92e4a5880fd55099"
78
78
  }
@@ -49,6 +49,9 @@ export type ClientOptions = {
49
49
  uri?: string;
50
50
  stackClient?: object;
51
51
  warningForCustomHandlers?: boolean;
52
+ /**
53
+ * - If set to true, all documents will be hydrated w.r.t. the provided schema's relationships, even if the relationship does not exist on the doc.
54
+ */
52
55
  autoHydrate?: boolean;
53
56
  /**
54
57
  * - If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won't be updated during future fetches. Instead, a `isFetching` attribute will be used to indicate when background fetching is started.
@@ -96,7 +99,7 @@ export type ClientOptions = {
96
99
  * @property {string} [uri]
97
100
  * @property {object} [stackClient]
98
101
  * @property {boolean} [warningForCustomHandlers]
99
- * @property {boolean} [autoHydrate]
102
+ * @property {boolean} [autoHydrate] - If set to true, all documents will be hydrated w.r.t. the provided schema's relationships, even if the relationship does not exist on the doc.
100
103
  * @property {boolean} [backgroundFetching] - If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won't be updated during future fetches. Instead, a `isFetching` attribute will be used to indicate when background fetching is started.
101
104
  * @property {object} [oauth]
102
105
  * @property {Function} [onTokenRefresh]
@@ -108,7 +111,6 @@ export type ClientOptions = {
108
111
  * @property {import("./types").ClientCapabilities} [capabilities] - Capabilities sent by the stack
109
112
  * @property {boolean} [useCustomStore=false] - If set to true, 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. Note will have to call `setStore` eventually. See [here](https://docs.cozy.io/en/cozy-client/react-integration/#1b-use-your-own-redux-store) for more information.
110
113
  * @property {boolean} [disableStoreForQueries=false] - If set to true, the client will not leverage the redux store to execute queries and store data.
111
-
112
114
  * @property {import('./performances/types').PerformanceAPI} [performanceApi] - The performance API that can be used to measure performances
113
115
  */
114
116
  /**
@@ -210,6 +212,9 @@ declare class CozyClient {
210
212
  uri?: string;
211
213
  stackClient?: object;
212
214
  warningForCustomHandlers?: boolean;
215
+ /**
216
+ * - If set to true, all documents will be hydrated w.r.t. the provided schema's relationships, even if the relationship does not exist on the doc.
217
+ */
213
218
  autoHydrate?: boolean;
214
219
  /**
215
220
  * - If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won't be updated during future fetches. Instead, a `isFetching` attribute will be used to indicate when background fetching is started.
@@ -255,6 +260,7 @@ declare class CozyClient {
255
260
  */
256
261
  storeAccesors: object;
257
262
  useCustomStore: boolean;
263
+ autoHydrate: boolean;
258
264
  disableStoreForQueries: boolean;
259
265
  /**
260
266
  * Gets overrided by MicroEE.mixin
@@ -607,12 +613,6 @@ declare class CozyClient {
607
613
  hydrateRelationships(document: any, schemaRelationships: any): {
608
614
  [x: string]: any;
609
615
  };
610
- /**
611
- * Creates (locally) a new document for the given doctype.
612
- * This document is hydrated : its relationships are there
613
- * and working.
614
- */
615
- makeNewDocument(doctype: any): any;
616
616
  generateRandomId(): string;
617
617
  /**
618
618
  * Creates an association that is linked to the store.
@@ -662,7 +662,7 @@ declare class CozyClient {
662
662
  *
663
663
  * @param {string} id - Id of the query (set via Query.props.as)
664
664
  * @param {object} options - Options
665
- * @param {boolean} [options.hydrated] - Whether documents should be returned already hydrated (default: false)
665
+ * @param {boolean} [options.hydrated] - Whether documents should be returned already hydrated
666
666
  * @param {object} [options.singleDocData] - If true, the "data" returned will be
667
667
  * a single doc instead of an array for single doc queries. Defaults to false for backward
668
668
  * compatibility but will be set to true in the future.
@@ -94,7 +94,7 @@ export namespace TODO_WITH_AUTHOR {
94
94
  }
95
95
  export { relationships_1 as relationships };
96
96
  }
97
- export namespace FILE_1 {
97
+ export namespace TODO_WITH_NONEXISTING_RELATIONSHIP {
98
98
  const _id_6: number;
99
99
  export { _id_6 as _id };
100
100
  const _rev_6: string;
@@ -103,9 +103,20 @@ export namespace FILE_1 {
103
103
  export { _type_6 as _type };
104
104
  const label_6: string;
105
105
  export { label_6 as label };
106
- export const name: string;
106
+ export namespace relationships_2 {
107
+ namespace broken {
108
+ const doctype_2: string;
109
+ export { doctype_2 as doctype };
110
+ const data_1: {
111
+ _type: string;
112
+ _id: number;
113
+ }[];
114
+ export { data_1 as data };
115
+ }
116
+ }
117
+ export { relationships_2 as relationships };
107
118
  }
108
- export namespace FILE_2 {
119
+ export namespace FILE_1 {
109
120
  const _id_7: number;
110
121
  export { _id_7 as _id };
111
122
  const _rev_7: string;
@@ -114,6 +125,17 @@ export namespace FILE_2 {
114
125
  export { _type_7 as _type };
115
126
  const label_7: string;
116
127
  export { label_7 as label };
128
+ export const name: string;
129
+ }
130
+ export namespace FILE_2 {
131
+ const _id_8: number;
132
+ export { _id_8 as _id };
133
+ const _rev_8: string;
134
+ export { _rev_8 as _rev };
135
+ const _type_8: string;
136
+ export { _type_8 as _type };
137
+ const label_8: string;
138
+ export { label_8 as label };
117
139
  }
118
140
  export const APP_NAME: "cozy-client-test";
119
141
  export const APP_VERSION: 2;
@@ -122,38 +144,38 @@ export const SOURCE_ACCOUNT_ID: "123-456-abc";
122
144
  export const SOURCE_ACCOUNT_IDENTIFIER: "testSourceAccountIdentifier";
123
145
  export namespace SCHEMA {
124
146
  export namespace todos {
125
- const doctype_2: string;
126
- export { doctype_2 as doctype };
147
+ const doctype_3: string;
148
+ export { doctype_3 as doctype };
127
149
  export { DOCTYPE_VERSION as doctypeVersion };
128
- export namespace relationships_2 {
150
+ export namespace relationships_3 {
129
151
  export namespace attachments_1 {
130
152
  export const type: string;
131
- const doctype_3: string;
132
- export { doctype_3 as doctype };
153
+ const doctype_4: string;
154
+ export { doctype_4 as doctype };
133
155
  }
134
156
  export { attachments_1 as attachments };
135
157
  export namespace authors_1 {
136
158
  const type_1: string;
137
159
  export { type_1 as type };
138
- const doctype_4: string;
139
- export { doctype_4 as doctype };
160
+ const doctype_5: string;
161
+ export { doctype_5 as doctype };
140
162
  }
141
163
  export { authors_1 as authors };
142
164
  }
143
- export { relationships_2 as relationships };
165
+ export { relationships_3 as relationships };
144
166
  }
145
167
  export namespace files_1 {
146
- const doctype_5: string;
147
- export { doctype_5 as doctype };
148
- export namespace relationships_3 {
168
+ const doctype_6: string;
169
+ export { doctype_6 as doctype };
170
+ export namespace relationships_4 {
149
171
  namespace icons {
150
172
  const type_2: string;
151
173
  export { type_2 as type };
152
- const doctype_6: string;
153
- export { doctype_6 as doctype };
174
+ const doctype_7: string;
175
+ export { doctype_7 as doctype };
154
176
  }
155
177
  }
156
- export { relationships_3 as relationships };
178
+ export { relationships_4 as relationships };
157
179
  }
158
180
  export { files_1 as files };
159
181
  }
@@ -0,0 +1 @@
1
+ export function equalityCheckForQuery(queryResA: import("../types").QueryState, queryResB: import("../types").QueryState): boolean;
package/types/types.d.ts CHANGED
@@ -503,12 +503,25 @@ export type QueryStateWithoutData = {
503
503
  fetchedPagesCount: number;
504
504
  bookmark: string;
505
505
  execution_stats?: object;
506
+ /**
507
+ * - The relationships names, used to check hydrated documents
508
+ */
509
+ relationshipNames: Array<string>;
506
510
  options?: QueryOptions;
507
511
  };
508
512
  export type QueryStateData = {
513
+ /**
514
+ * - Collection of hydrated documents
515
+ */
509
516
  data: object | any[];
510
517
  };
511
- export type QueryState = QueryStateWithoutData & QueryStateData;
518
+ export type QueryStateStoreData = {
519
+ /**
520
+ * - Collection of store's documents
521
+ */
522
+ storeData: object | any[];
523
+ };
524
+ export type QueryState = QueryStateWithoutData & QueryStateData & QueryStateStoreData;
512
525
  export type AutoUpdateOptions = any;
513
526
  export type QueryOptions = {
514
527
  /**
@@ -568,7 +581,7 @@ export type FetchMoreAble = {
568
581
  export type FetchAble = {
569
582
  fetch: Function;
570
583
  };
571
- export type UseQueryReturnValue = QueryStateWithoutData & QueryStateData & FetchMoreAble & FetchAble;
584
+ export type UseQueryReturnValue = QueryStateWithoutData & QueryStateData & QueryStateStoreData & FetchMoreAble & FetchAble;
572
585
  export type UseMutationWithoutMutate = {
573
586
  /**
574
587
  * - Status of the current mutation