cozy-pouch-link 57.5.0 → 57.6.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.
Files changed (43) hide show
  1. package/dist/CozyPouchLink.js +221 -469
  2. package/dist/CozyPouchLink.spec.js +6 -147
  3. package/dist/PouchManager.js +43 -8
  4. package/dist/PouchManager.spec.js +21 -12
  5. package/dist/__mocks__/@op-engineering/op-sqlite.js +11 -0
  6. package/dist/db/dbInterface.js +190 -0
  7. package/dist/db/helpers.js +106 -0
  8. package/dist/db/pouchdb/getDocs.js +157 -0
  9. package/dist/db/pouchdb/getDocs.spec.js +63 -0
  10. package/dist/db/pouchdb/pouchdb.js +264 -0
  11. package/dist/db/pouchdb/pouchdb.spec.js +151 -0
  12. package/dist/db/sqlite/sql.js +418 -0
  13. package/dist/db/sqlite/sql.spec.js +363 -0
  14. package/dist/db/sqlite/sqliteDb.js +319 -0
  15. package/dist/errors.js +17 -2
  16. package/dist/helpers.js +21 -147
  17. package/dist/helpers.spec.js +1 -98
  18. package/dist/index.js +9 -1
  19. package/dist/jsonapi.js +49 -10
  20. package/dist/jsonapi.spec.js +105 -32
  21. package/dist/mango.js +146 -3
  22. package/dist/migrations/pouchdb.js +32 -0
  23. package/dist/replicateOnce.js +25 -23
  24. package/dist/types.js +5 -0
  25. package/dist/utils.js +33 -3
  26. package/package.json +4 -3
  27. package/types/CozyPouchLink.d.ts +4 -60
  28. package/types/PouchManager.d.ts +6 -1
  29. package/types/__mocks__/@op-engineering/op-sqlite.d.ts +1 -0
  30. package/types/db/dbInterface.d.ts +117 -0
  31. package/types/db/helpers.d.ts +3 -0
  32. package/types/db/pouchdb/getDocs.d.ts +18 -0
  33. package/types/db/pouchdb/pouchdb.d.ts +8 -0
  34. package/types/db/sqlite/sql.d.ts +45 -0
  35. package/types/db/sqlite/sqliteDb.d.ts +7 -0
  36. package/types/errors.d.ts +2 -0
  37. package/types/helpers.d.ts +1 -4
  38. package/types/index.d.ts +1 -0
  39. package/types/jsonapi.d.ts +2 -0
  40. package/types/mango.d.ts +19 -1
  41. package/types/migrations/pouchdb.d.ts +1 -0
  42. package/types/types.d.ts +2 -0
  43. package/types/utils.d.ts +3 -0
package/dist/errors.js CHANGED
@@ -3,10 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isExpiredTokenError = void 0;
6
+ exports.isMissingPouchDBIndexError = exports.isMissingSQLiteIndexError = exports.isExpiredTokenError = void 0;
7
7
  var EXPIRED_TOKEN_ERROR = /Expired token/;
8
8
  var INVALID_TOKEN_ERROR = /Invalid JWT token/;
9
9
  var INVALID_TOKEN_ALT_ERROR = /Invalid token/;
10
+ var SQLITE_MISSING_INDEX_ERROR = /no such index/;
11
+ var POUCHDB_MISSING_INDEX_ERROR = /Could not find that index/;
12
+ var POUCHDB_MISSING_INDEX_ERROR_ALT = /no index/;
10
13
 
11
14
  var expiredTokenError = function expiredTokenError(error) {
12
15
  var errorMsg = error.message;
@@ -26,4 +29,16 @@ var isExpiredTokenError = function isExpiredTokenError(error) {
26
29
  return expiredTokenError(error);
27
30
  };
28
31
 
29
- exports.isExpiredTokenError = isExpiredTokenError;
32
+ exports.isExpiredTokenError = isExpiredTokenError;
33
+
34
+ var isMissingSQLiteIndexError = function isMissingSQLiteIndexError(error) {
35
+ return SQLITE_MISSING_INDEX_ERROR.test(error.message);
36
+ };
37
+
38
+ exports.isMissingSQLiteIndexError = isMissingSQLiteIndexError;
39
+
40
+ var isMissingPouchDBIndexError = function isMissingPouchDBIndexError(error) {
41
+ return POUCHDB_MISSING_INDEX_ERROR.test(error.message) || POUCHDB_MISSING_INDEX_ERROR_ALT.test(error.message);
42
+ };
43
+
44
+ exports.isMissingPouchDBIndexError = isMissingPouchDBIndexError;
package/dist/helpers.js CHANGED
@@ -5,166 +5,40 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.default = void 0;
8
+ exports.default = exports.LIMIT_BUG = void 0;
9
9
 
10
- var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
12
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
12
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
13
13
 
14
14
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
15
15
 
16
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
17
-
18
16
  var _merge = _interopRequireDefault(require("lodash/merge"));
19
17
 
20
18
  var _startsWith = _interopRequireDefault(require("lodash/startsWith"));
21
19
 
22
20
  var _logger = _interopRequireDefault(require("./logger"));
23
21
 
22
+ 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; }
23
+
24
+ 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; }
25
+
24
26
  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; } } }; }
25
27
 
26
28
  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); }
27
29
 
28
30
  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; }
29
31
 
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; }
31
-
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; }
33
-
34
32
  var helpers = {}; // https://github.com/pouchdb/pouchdb/issues/7011
35
33
 
36
34
  var LIMIT_BUG = 999;
35
+ exports.LIMIT_BUG = LIMIT_BUG;
37
36
  var ADAPTERS_WITH_LIMIT_BUG = ['websql'];
38
37
 
39
38
  helpers.isAdapterBugged = function (adapterName) {
40
39
  return ADAPTERS_WITH_LIMIT_BUG.includes(adapterName);
41
40
  };
42
41
 
43
- helpers.withoutDesignDocuments = function (res) {
44
- var rows = res.rows.filter(function (doc) {
45
- return !(0, _startsWith.default)(doc.id, '_design/');
46
- });
47
- return _objectSpread(_objectSpread({}, res), {}, {
48
- rows: rows,
49
- total_rows: rows.length
50
- });
51
- };
52
-
53
- helpers.getDocs = /*#__PURE__*/function () {
54
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(db, fct) {
55
- var options,
56
- limit,
57
- field,
58
- data,
59
- next,
60
- _args = arguments;
61
- return _regenerator.default.wrap(function _callee$(_context) {
62
- while (1) {
63
- switch (_context.prev = _context.next) {
64
- case 0:
65
- options = _args.length > 2 && _args[2] !== undefined ? _args[2] : {};
66
- // allDocs return an error when limit is null
67
- if (options.limit === null) delete options.limit;
68
- limit = options.limit;
69
- field = fct === 'allDocs' ? 'rows' : 'docs';
70
-
71
- if (helpers.isAdapterBugged(db.adapter)) {
72
- if (limit === undefined || limit > LIMIT_BUG) {
73
- options.limit = LIMIT_BUG;
74
- options.skip = options.skip || 0;
75
- }
76
- }
77
-
78
- _context.next = 7;
79
- return db[fct](options);
80
-
81
- case 7:
82
- data = _context.sent;
83
-
84
- if (!(data[field].length === options.limit)) {
85
- _context.next = 16;
86
- break;
87
- }
88
-
89
- options.skip = (options.skip ? options.skip : 0) + options.limit;
90
- options.limit = limit ? limit - options.limit : undefined;
91
-
92
- if (!(options.limit > 0 || options.limit === undefined)) {
93
- _context.next = 16;
94
- break;
95
- }
96
-
97
- _context.next = 14;
98
- return helpers.getDocs(db, fct, options);
99
-
100
- case 14:
101
- next = _context.sent;
102
- return _context.abrupt("return", _objectSpread(_objectSpread({}, data), {}, (0, _defineProperty2.default)({}, field, [].concat((0, _toConsumableArray2.default)(data[field]), (0, _toConsumableArray2.default)(next[field])))));
103
-
104
- case 16:
105
- return _context.abrupt("return", data);
106
-
107
- case 17:
108
- case "end":
109
- return _context.stop();
110
- }
111
- }
112
- }, _callee);
113
- }));
114
-
115
- return function (_x, _x2) {
116
- return _ref.apply(this, arguments);
117
- };
118
- }();
119
-
120
- helpers.allDocs = /*#__PURE__*/function () {
121
- var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(db) {
122
- var options,
123
- _args2 = arguments;
124
- return _regenerator.default.wrap(function _callee2$(_context2) {
125
- while (1) {
126
- switch (_context2.prev = _context2.next) {
127
- case 0:
128
- options = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : {};
129
- return _context2.abrupt("return", helpers.getDocs(db, 'allDocs', options));
130
-
131
- case 2:
132
- case "end":
133
- return _context2.stop();
134
- }
135
- }
136
- }, _callee2);
137
- }));
138
-
139
- return function (_x3) {
140
- return _ref2.apply(this, arguments);
141
- };
142
- }();
143
-
144
- helpers.find = /*#__PURE__*/function () {
145
- var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(db) {
146
- var options,
147
- _args3 = arguments;
148
- return _regenerator.default.wrap(function _callee3$(_context3) {
149
- while (1) {
150
- switch (_context3.prev = _context3.next) {
151
- case 0:
152
- options = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : {};
153
- return _context3.abrupt("return", helpers.getDocs(db, 'find', options));
154
-
155
- case 2:
156
- case "end":
157
- return _context3.stop();
158
- }
159
- }
160
- }, _callee3);
161
- }));
162
-
163
- return function (_x4) {
164
- return _ref3.apply(this, arguments);
165
- };
166
- }();
167
-
168
42
  helpers.isDesignDocument = function (doc) {
169
43
  return (0, _startsWith.default)(doc._id, '_design');
170
44
  };
@@ -174,33 +48,33 @@ helpers.isDeletedDocument = function (doc) {
174
48
  };
175
49
 
176
50
  helpers.insertBulkDocs = /*#__PURE__*/function () {
177
- var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(db, docs) {
178
- return _regenerator.default.wrap(function _callee4$(_context4) {
51
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(db, docs) {
52
+ return _regenerator.default.wrap(function _callee$(_context) {
179
53
  while (1) {
180
- switch (_context4.prev = _context4.next) {
54
+ switch (_context.prev = _context.next) {
181
55
  case 0:
182
- return _context4.abrupt("return", db.bulkDocs(docs, {
56
+ return _context.abrupt("return", db.bulkDocs(docs, {
183
57
  new_edits: false
184
58
  }));
185
59
 
186
60
  case 1:
187
61
  case "end":
188
- return _context4.stop();
62
+ return _context.stop();
189
63
  }
190
64
  }
191
- }, _callee4);
65
+ }, _callee);
192
66
  }));
193
67
 
194
- return function (_x5, _x6) {
195
- return _ref4.apply(this, arguments);
68
+ return function (_x, _x2) {
69
+ return _ref.apply(this, arguments);
196
70
  };
197
71
  }();
198
72
 
199
- helpers.normalizeFindSelector = function (_ref5) {
200
- var selector = _ref5.selector,
201
- sort = _ref5.sort,
202
- indexedFields = _ref5.indexedFields,
203
- partialFilter = _ref5.partialFilter;
73
+ helpers.normalizeFindSelector = function (_ref2) {
74
+ var selector = _ref2.selector,
75
+ sort = _ref2.sort,
76
+ indexedFields = _ref2.indexedFields,
77
+ partialFilter = _ref2.partialFilter;
204
78
  var findSelector = selector || {};
205
79
 
206
80
  if (indexedFields) {
@@ -1,104 +1,7 @@
1
1
  import helpers from './helpers'
2
- const {
3
- withoutDesignDocuments,
4
- isDeletedDocument,
5
- isDesignDocument,
6
- normalizeFindSelector
7
- } = helpers
8
-
9
- import PouchDB from 'pouchdb-browser'
10
- import PouchDBFind from 'pouchdb-find'
11
- import adapter from 'pouchdb-adapter-memory'
12
- PouchDB.plugin(PouchDBFind)
13
- PouchDB.plugin(adapter)
14
-
15
- const insertData = async (db, number) => {
16
- const docs = []
17
- for (let i = 0; i < number; i++) {
18
- docs.push({ _id: `doc${i}`, status: true })
19
- }
20
- await db.bulkDocs(docs)
21
- }
2
+ const { isDeletedDocument, isDesignDocument, normalizeFindSelector } = helpers
22
3
 
23
4
  describe('Helpers', () => {
24
- describe('withoutDesignDocuments', () => {
25
- let response
26
- beforeEach(() => {
27
- response = {
28
- offset: 0,
29
- rows: [{ id: 'goodId' }, { id: '_design/wrongId' }],
30
- total_rows: 2
31
- }
32
- jest.setTimeout(10000)
33
- })
34
- it('should remove design document', () => {
35
- const filteredResponse = withoutDesignDocuments(response)
36
- expect(filteredResponse.rows.length).toEqual(1)
37
- expect(filteredResponse.rows[0].id).toEqual('goodId')
38
- })
39
- it('should update total rows number', () => {
40
- const filteredResponse = withoutDesignDocuments(response)
41
- expect(filteredResponse.total_rows).toEqual(1)
42
- })
43
- it('should not mutate response', () => {
44
- const responseCopy = { ...response }
45
- withoutDesignDocuments(response)
46
- expect(response).toEqual(responseCopy)
47
- })
48
- })
49
-
50
- for (const getDocs of ['find', 'allDocs']) {
51
- describe(getDocs, () => {
52
- let db, options, field
53
-
54
- beforeEach(async () => {
55
- db = new PouchDB('test', { adapter: 'memory' })
56
- if (getDocs === 'find') {
57
- options = { selector: { status: { $eq: true } } }
58
- await db.createIndex({ index: { fields: ['status'] } })
59
- field = 'docs'
60
- } else {
61
- options = {}
62
- field = 'rows'
63
- }
64
- })
65
-
66
- afterEach(async () => {
67
- await db.destroy()
68
- })
69
-
70
- it('should find 200 docs', async () => {
71
- await insertData(db, 200)
72
- const data = await helpers[getDocs](db, options)
73
- expect(data[field]).toHaveLength(200)
74
- })
75
-
76
- it('should find 20 docs with limit', async () => {
77
- await insertData(db, 200)
78
- const data = await helpers[getDocs](db, { ...options, limit: 20 })
79
- expect(data[field]).toHaveLength(20)
80
- })
81
-
82
- it('should find 2000 docs', async () => {
83
- jest.spyOn(helpers, 'isAdapterBugged').mockReturnValue(true)
84
- jest.spyOn(db, getDocs)
85
- await insertData(db, 2000)
86
- const data = await helpers[getDocs](db, options)
87
- expect(data[field]).toHaveLength(2000)
88
- expect(db[getDocs]).toHaveBeenCalledTimes(3)
89
- })
90
-
91
- it('should find 1000 docs', async () => {
92
- jest.spyOn(helpers, 'isAdapterBugged').mockReturnValue(true)
93
- jest.spyOn(db, getDocs)
94
- await insertData(db, 2000)
95
- const data = await helpers[getDocs](db, { ...options, limit: 1000 })
96
- expect(data[field]).toHaveLength(1000)
97
- expect(db[getDocs]).toHaveBeenCalledTimes(2)
98
- })
99
- })
100
- }
101
-
102
5
  describe('isDesignDocument', () => {
103
6
  it('should return true when given a design document', () => {
104
7
  expect(isDesignDocument({ _id: '_design/something' })).toBe(true)
package/dist/index.js CHANGED
@@ -11,5 +11,13 @@ Object.defineProperty(exports, "default", {
11
11
  return _CozyPouchLink.default;
12
12
  }
13
13
  });
14
+ Object.defineProperty(exports, "SQLiteQuery", {
15
+ enumerable: true,
16
+ get: function get() {
17
+ return _sqliteDb.default;
18
+ }
19
+ });
20
+
21
+ var _CozyPouchLink = _interopRequireDefault(require("./CozyPouchLink"));
14
22
 
15
- var _CozyPouchLink = _interopRequireDefault(require("./CozyPouchLink"));
23
+ var _sqliteDb = _interopRequireDefault(require("./db/sqlite/sqliteDb"));
package/dist/jsonapi.js CHANGED
@@ -2,13 +2,25 @@
2
2
 
3
3
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
4
 
5
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
+
5
7
  Object.defineProperty(exports, "__esModule", {
6
8
  value: true
7
9
  });
8
- exports.fromPouchResult = exports.normalizeDoc = exports.normalizeDocs = void 0;
10
+ exports.sanitizeJsonApi = exports.sanitized = exports.fromPouchResult = exports.normalizeDoc = exports.normalizeDocs = void 0;
11
+
12
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
13
 
10
14
  var _cozyClient = _interopRequireWildcard(require("cozy-client"));
11
15
 
16
+ var _omit = _interopRequireDefault(require("lodash/omit"));
17
+
18
+ var _startsWith = _interopRequireDefault(require("lodash/startsWith"));
19
+
20
+ 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; }
21
+
22
+ 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; }
23
+
12
24
  /**
13
25
  * Normalize several PouchDB document
14
26
  *
@@ -25,6 +37,11 @@ var normalizeDocs = function normalizeDocs(client, doctype, docs) {
25
37
  continue;
26
38
  }
27
39
 
40
+ if ((0, _startsWith.default)(doc.id, '_design/')) {
41
+ docs.splice(i, 1);
42
+ continue;
43
+ }
44
+
28
45
  normalizeDoc(client, doctype, doc);
29
46
  }
30
47
  };
@@ -48,12 +65,15 @@ var normalizeDoc = function normalizeDoc(client, doctype, doc) {
48
65
  doc._rev = doc._rev || doc.rev;
49
66
  doc._type = doctype;
50
67
 
51
- if (doc.relationships) {
52
- doc.relationships.referenced_by = doc.referenced_by;
53
- } else {
54
- doc.relationships = {
55
- referenced_by: doc.referenced_by
56
- };
68
+ if (doc.referenced_by) {
69
+ // TODO: should we remove referenced_by at the doc root?
70
+ // For now, we keep it for safety
71
+ doc.relationships = _objectSpread(_objectSpread({}, doc.relationships), {}, {
72
+ referenced_by: {
73
+ links: undefined,
74
+ data: doc.referenced_by
75
+ }
76
+ });
57
77
  }
58
78
 
59
79
  if (doc.rev) {
@@ -93,7 +113,9 @@ var fromPouchResult = function fromPouchResult(_ref) {
93
113
  doctype = _ref.doctype,
94
114
  client = _ref.client;
95
115
 
96
- // Sometimes, queries are transformed by Collections and they call a dedicated
116
+ if (!res) {
117
+ return null;
118
+ } // Sometimes, queries are transformed by Collections and they call a dedicated
97
119
  // cozy-stack route. When this is the case, we want to be able to replicate the same
98
120
  // query from cozy-pouch-link. It is not possible as-is because the received data
99
121
  // is not the same as the one stored in the Couch database
@@ -101,6 +123,8 @@ var fromPouchResult = function fromPouchResult(_ref) {
101
123
  // we store the query result in a `cozyPouchData` attribute
102
124
  // So when `cozyPouchData` attribute exists, we know that we want to return its content
103
125
  // as the result of the query
126
+
127
+
104
128
  if (res.cozyPouchData) {
105
129
  return {
106
130
  data: res.cozyPouchData
@@ -112,6 +136,7 @@ var fromPouchResult = function fromPouchResult(_ref) {
112
136
  return row.doc;
113
137
  }) : res.docs;
114
138
  var offset = res.offset || 0;
139
+ var next = offset + docs.length < res.total_rows || docs.length >= res.limit;
115
140
  normalizeDocs(client, doctype, docs);
116
141
  var result = {
117
142
  data: docs,
@@ -119,7 +144,7 @@ var fromPouchResult = function fromPouchResult(_ref) {
119
144
  count: docs.length
120
145
  },
121
146
  skip: offset,
122
- next: offset + docs.length < res.total_rows || docs.length >= res.limit
147
+ next: next
123
148
  };
124
149
  return result;
125
150
  } else {
@@ -130,4 +155,18 @@ var fromPouchResult = function fromPouchResult(_ref) {
130
155
  }
131
156
  };
132
157
 
133
- exports.fromPouchResult = fromPouchResult;
158
+ exports.fromPouchResult = fromPouchResult;
159
+
160
+ var sanitized = function sanitized(doc) {
161
+ return (0, _omit.default)(doc, '_type');
162
+ };
163
+
164
+ exports.sanitized = sanitized;
165
+
166
+ var sanitizeJsonApi = function sanitizeJsonApi(doc) {
167
+ var docWithoutType = sanitized(doc);
168
+ var sanitizedDoc = (0, _omit.default)(docWithoutType, ['attributes', 'meta']);
169
+ return sanitizedDoc;
170
+ };
171
+
172
+ exports.sanitizeJsonApi = sanitizeJsonApi;
@@ -34,24 +34,99 @@ const client = new CozyClient({ token, uri })
34
34
  client.capabilities = { flat_subdomains: true }
35
35
 
36
36
  describe('doc normalization', () => {
37
+ it('should correctly normalize simple doc', () => {
38
+ const doc = {
39
+ _id: '1234',
40
+ _rev: '1-1234',
41
+ name: 'Simple doc'
42
+ }
43
+ normalizeDoc(client, 'io.cozy.todos', doc)
44
+ expect(doc).toEqual({
45
+ _id: '1234',
46
+ id: '1234',
47
+ _rev: '1-1234',
48
+ _type: 'io.cozy.todos',
49
+ name: 'Simple doc'
50
+ })
51
+ })
52
+
53
+ it('should handle wrong rev format', () => {
54
+ const doc = {
55
+ _id: '1234',
56
+ rev: '1-1234',
57
+ name: 'Simple doc'
58
+ }
59
+ normalizeDoc(client, 'io.cozy.todos', doc)
60
+ expect(doc).toEqual({
61
+ _id: '1234',
62
+ id: '1234',
63
+ _rev: '1-1234',
64
+ _type: 'io.cozy.todos',
65
+ name: 'Simple doc'
66
+ })
67
+ })
68
+
69
+ it('should normalize relationships', () => {
70
+ const doc = {
71
+ _id: '1234',
72
+ rev: '1-1234',
73
+ name: 'Simple doc',
74
+ relationships: {
75
+ contact: {
76
+ data: {
77
+ _id: '4567',
78
+ _type: 'io.cozy.contacts'
79
+ }
80
+ }
81
+ },
82
+ referenced_by: [
83
+ {
84
+ type: 'io.cozy.albums',
85
+ id: 'thegreatalbum'
86
+ }
87
+ ]
88
+ }
89
+ normalizeDoc(client, 'io.cozy.todos', doc)
90
+ expect(doc).toMatchObject({
91
+ _id: '1234',
92
+ id: '1234',
93
+ _rev: '1-1234',
94
+ _type: 'io.cozy.todos',
95
+ name: 'Simple doc',
96
+ relationships: {
97
+ contact: {
98
+ data: {
99
+ _id: '4567',
100
+ _type: 'io.cozy.contacts'
101
+ }
102
+ },
103
+ referenced_by: {
104
+ data: [
105
+ {
106
+ type: 'io.cozy.albums',
107
+ id: 'thegreatalbum'
108
+ }
109
+ ]
110
+ }
111
+ }
112
+ })
113
+ })
114
+
37
115
  it('should normalize apps links', () => {
38
116
  const doc = {
39
- _id: 1234,
117
+ _id: '1234',
40
118
  _rev: '3-deadbeef',
41
119
  slug: 'contact',
42
120
  version: '1.2.0'
43
121
  }
44
122
  normalizeDoc(client, 'io.cozy.apps', doc)
45
123
  expect(doc).toEqual({
46
- _id: 1234,
47
- id: 1234,
124
+ _id: '1234',
125
+ id: '1234',
48
126
  _rev: '3-deadbeef',
49
127
  _type: 'io.cozy.apps',
50
128
  slug: 'contact',
51
129
  version: '1.2.0',
52
- relationships: {
53
- referenced_by: undefined
54
- },
55
130
  links: {
56
131
  icon: '/apps/contact/icon/1.2.0',
57
132
  related: 'https://claude-contact.mycozy.cloud/#/',
@@ -188,9 +263,6 @@ describe('jsonapi', () => {
188
263
  links: {
189
264
  self: '/settings/flags'
190
265
  },
191
- relationships: {
192
- referenced_by: undefined
193
- },
194
266
  'some.boolean.flag': true,
195
267
  'some.number.flag': 30,
196
268
  'some.object.flag': {
@@ -214,9 +286,6 @@ describe('jsonapi', () => {
214
286
  expect(normalized).toEqual({
215
287
  data: [
216
288
  {
217
- relationships: {
218
- referenced_by: undefined
219
- },
220
289
  id: '018bdcec-00c8-7155-b352-c8a8f472f882',
221
290
  type: 'file',
222
291
  _type: 'io.cozy.files',
@@ -258,12 +327,14 @@ describe('jsonapi', () => {
258
327
  },
259
328
  {
260
329
  relationships: {
261
- referenced_by: [
262
- {
263
- id: '536bde9aef87dde16630d3c99d26453f',
264
- type: 'io.cozy.photos.albums'
265
- }
266
- ]
330
+ referenced_by: {
331
+ data: [
332
+ {
333
+ id: '536bde9aef87dde16630d3c99d26453f',
334
+ type: 'io.cozy.photos.albums'
335
+ }
336
+ ]
337
+ }
267
338
  },
268
339
  id: '018c7cf1-1d00-73ac-9a7f-ee3190638183',
269
340
  type: 'file',
@@ -315,18 +386,26 @@ describe('jsonapi', () => {
315
386
  _rev: '2-02e800df012ea1cc740e5ad1554cefe6'
316
387
  },
317
388
  {
318
- relationships: {
319
- referenced_by: [
320
- {
321
- id: '536bde9aef87dde16630d3c99d26453f',
322
- type: 'io.cozy.photos.albums'
323
- }
324
- ]
325
- },
326
389
  id: '018ca6a8-8292-7acb-bcaf-a95ccfd83662',
327
390
  _type: 'io.cozy.files',
328
391
  type: 'file',
329
392
  name: 'IMG_0047.jpg',
393
+ relationships: {
394
+ referenced_by: {
395
+ data: [
396
+ {
397
+ id: '536bde9aef87dde16630d3c99d26453f',
398
+ type: 'io.cozy.photos.albums'
399
+ }
400
+ ]
401
+ }
402
+ },
403
+ referenced_by: [
404
+ {
405
+ id: '536bde9aef87dde16630d3c99d26453f',
406
+ type: 'io.cozy.photos.albums'
407
+ }
408
+ ],
330
409
  dir_id: 'io.cozy.files.root-dir',
331
410
  created_at: '2023-11-19T13:31:47+01:00',
332
411
  updated_at: '2023-12-26T15:05:10.256Z',
@@ -346,12 +425,6 @@ describe('jsonapi', () => {
346
425
  orientation: 6,
347
426
  width: 4032
348
427
  },
349
- referenced_by: [
350
- {
351
- id: '536bde9aef87dde16630d3c99d26453f',
352
- type: 'io.cozy.photos.albums'
353
- }
354
- ],
355
428
  cozyMetadata: {
356
429
  doctypeVersion: '1',
357
430
  metadataVersion: 1,