cozy-pouch-link 57.4.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.
- package/dist/CozyPouchLink.js +221 -469
- package/dist/CozyPouchLink.spec.js +6 -147
- package/dist/PouchManager.js +43 -8
- package/dist/PouchManager.spec.js +21 -12
- package/dist/__mocks__/@op-engineering/op-sqlite.js +11 -0
- package/dist/db/dbInterface.js +190 -0
- package/dist/db/helpers.js +106 -0
- package/dist/db/pouchdb/getDocs.js +157 -0
- package/dist/db/pouchdb/getDocs.spec.js +63 -0
- package/dist/db/pouchdb/pouchdb.js +264 -0
- package/dist/db/pouchdb/pouchdb.spec.js +151 -0
- package/dist/db/sqlite/sql.js +418 -0
- package/dist/db/sqlite/sql.spec.js +363 -0
- package/dist/db/sqlite/sqliteDb.js +319 -0
- package/dist/errors.js +17 -2
- package/dist/helpers.js +21 -147
- package/dist/helpers.spec.js +1 -98
- package/dist/index.js +9 -1
- package/dist/jsonapi.js +49 -10
- package/dist/jsonapi.spec.js +105 -32
- package/dist/mango.js +146 -3
- package/dist/migrations/pouchdb.js +32 -0
- package/dist/replicateOnce.js +25 -23
- package/dist/types.js +5 -0
- package/dist/utils.js +33 -3
- package/package.json +4 -3
- package/types/CozyPouchLink.d.ts +4 -60
- package/types/PouchManager.d.ts +6 -1
- package/types/__mocks__/@op-engineering/op-sqlite.d.ts +1 -0
- package/types/db/dbInterface.d.ts +117 -0
- package/types/db/helpers.d.ts +3 -0
- package/types/db/pouchdb/getDocs.d.ts +18 -0
- package/types/db/pouchdb/pouchdb.d.ts +8 -0
- package/types/db/sqlite/sql.d.ts +45 -0
- package/types/db/sqlite/sqliteDb.d.ts +7 -0
- package/types/errors.d.ts +2 -0
- package/types/helpers.d.ts +1 -4
- package/types/index.d.ts +1 -0
- package/types/jsonapi.d.ts +2 -0
- package/types/mango.d.ts +19 -1
- package/types/migrations/pouchdb.d.ts +1 -0
- package/types/types.d.ts +2 -0
- package/types/utils.d.ts +3 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.getDocs = exports.getDocsAndNormalize = void 0;
|
|
9
|
+
|
|
10
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
|
+
|
|
12
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
13
|
+
|
|
14
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
15
|
+
|
|
16
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
17
|
+
|
|
18
|
+
var _helpers = _interopRequireDefault(require("../../helpers"));
|
|
19
|
+
|
|
20
|
+
var _jsonapi = require("../../jsonapi");
|
|
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
|
+
|
|
26
|
+
var isAdapterBugged = _helpers.default.isAdapterBugged,
|
|
27
|
+
LIMIT_BUG = _helpers.default.LIMIT_BUG;
|
|
28
|
+
|
|
29
|
+
var getDocsAndNormalize = /*#__PURE__*/function () {
|
|
30
|
+
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref) {
|
|
31
|
+
var client, doctype, db, queryFunc, _ref$queryParams, queryParams, _ref$withRows, withRows, results, jsonResult;
|
|
32
|
+
|
|
33
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
34
|
+
while (1) {
|
|
35
|
+
switch (_context.prev = _context.next) {
|
|
36
|
+
case 0:
|
|
37
|
+
client = _ref.client, doctype = _ref.doctype, db = _ref.db, queryFunc = _ref.queryFunc, _ref$queryParams = _ref.queryParams, queryParams = _ref$queryParams === void 0 ? {} : _ref$queryParams, _ref$withRows = _ref.withRows, withRows = _ref$withRows === void 0 ? true : _ref$withRows;
|
|
38
|
+
_context.next = 3;
|
|
39
|
+
return getDocs(db, queryFunc, queryParams);
|
|
40
|
+
|
|
41
|
+
case 3:
|
|
42
|
+
results = _context.sent;
|
|
43
|
+
jsonResult = (0, _jsonapi.fromPouchResult)({
|
|
44
|
+
res: results,
|
|
45
|
+
withRows: withRows,
|
|
46
|
+
doctype: doctype,
|
|
47
|
+
client: client
|
|
48
|
+
});
|
|
49
|
+
return _context.abrupt("return", jsonResult);
|
|
50
|
+
|
|
51
|
+
case 6:
|
|
52
|
+
case "end":
|
|
53
|
+
return _context.stop();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, _callee);
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
return function getDocsAndNormalize(_x) {
|
|
60
|
+
return _ref2.apply(this, arguments);
|
|
61
|
+
};
|
|
62
|
+
}();
|
|
63
|
+
|
|
64
|
+
exports.getDocsAndNormalize = getDocsAndNormalize;
|
|
65
|
+
|
|
66
|
+
var getDocs = /*#__PURE__*/function () {
|
|
67
|
+
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(db, fct) {
|
|
68
|
+
var queryParams,
|
|
69
|
+
limit,
|
|
70
|
+
field,
|
|
71
|
+
data,
|
|
72
|
+
next,
|
|
73
|
+
_args2 = arguments;
|
|
74
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
75
|
+
while (1) {
|
|
76
|
+
switch (_context2.prev = _context2.next) {
|
|
77
|
+
case 0:
|
|
78
|
+
queryParams = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : {};
|
|
79
|
+
// allDocs return an error when limit is null
|
|
80
|
+
if (queryParams.limit === null) delete queryParams.limit;
|
|
81
|
+
limit = queryParams.limit;
|
|
82
|
+
field = fct === 'allDocs' ? 'rows' : 'docs';
|
|
83
|
+
|
|
84
|
+
if (isAdapterBugged(db.adapter)) {
|
|
85
|
+
// FIXME: to remove? This was used to deal with an old adapter that is probably no longer used
|
|
86
|
+
// But it might be worth checking the issue does not exist anymore
|
|
87
|
+
if (limit === undefined || limit > LIMIT_BUG) {
|
|
88
|
+
queryParams.limit = LIMIT_BUG;
|
|
89
|
+
queryParams.skip = queryParams.skip || 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!(fct === 'get')) {
|
|
94
|
+
_context2.next = 9;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (queryParams.id) {
|
|
99
|
+
_context2.next = 8;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return _context2.abrupt("return", null);
|
|
104
|
+
|
|
105
|
+
case 8:
|
|
106
|
+
return _context2.abrupt("return", db.get(queryParams.id));
|
|
107
|
+
|
|
108
|
+
case 9:
|
|
109
|
+
_context2.next = 11;
|
|
110
|
+
return db[fct](queryParams);
|
|
111
|
+
|
|
112
|
+
case 11:
|
|
113
|
+
data = _context2.sent;
|
|
114
|
+
|
|
115
|
+
if (!(data[field].length === queryParams.limit)) {
|
|
116
|
+
_context2.next = 20;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
queryParams.skip = (queryParams.skip ? queryParams.skip : 0) + queryParams.limit;
|
|
121
|
+
queryParams.limit = limit ? limit - queryParams.limit : undefined;
|
|
122
|
+
|
|
123
|
+
if (!(queryParams.limit > 0 || queryParams.limit === undefined)) {
|
|
124
|
+
_context2.next = 20;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
_context2.next = 18;
|
|
129
|
+
return getDocs(db, fct, queryParams);
|
|
130
|
+
|
|
131
|
+
case 18:
|
|
132
|
+
next = _context2.sent;
|
|
133
|
+
return _context2.abrupt("return", _objectSpread(_objectSpread({}, data), {}, (0, _defineProperty2.default)({}, field, [].concat((0, _toConsumableArray2.default)(data[field]), (0, _toConsumableArray2.default)(next[field])))));
|
|
134
|
+
|
|
135
|
+
case 20:
|
|
136
|
+
if (queryParams.keys) {
|
|
137
|
+
// Special case for getByIds queries: Pouch returns the total number of rows in the database,
|
|
138
|
+
// which will make cozy-client believes there are more results to fetch
|
|
139
|
+
data.total_rows = data.rows.length;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return _context2.abrupt("return", data);
|
|
143
|
+
|
|
144
|
+
case 22:
|
|
145
|
+
case "end":
|
|
146
|
+
return _context2.stop();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}, _callee2);
|
|
150
|
+
}));
|
|
151
|
+
|
|
152
|
+
return function getDocs(_x2, _x3) {
|
|
153
|
+
return _ref3.apply(this, arguments);
|
|
154
|
+
};
|
|
155
|
+
}();
|
|
156
|
+
|
|
157
|
+
exports.getDocs = getDocs;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getDocs } from './getDocs'
|
|
2
|
+
|
|
3
|
+
import PouchDB from 'pouchdb-browser'
|
|
4
|
+
import PouchDBFind from 'pouchdb-find'
|
|
5
|
+
import adapter from 'pouchdb-adapter-memory'
|
|
6
|
+
PouchDB.plugin(PouchDBFind)
|
|
7
|
+
PouchDB.plugin(adapter)
|
|
8
|
+
|
|
9
|
+
const insertData = async (db, number) => {
|
|
10
|
+
const docs = []
|
|
11
|
+
for (let i = 0; i < number; i++) {
|
|
12
|
+
docs.push({ _id: `doc${i}`, status: true })
|
|
13
|
+
}
|
|
14
|
+
await db.bulkDocs(docs)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('getDocs', () => {
|
|
18
|
+
let db, options
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
db = new PouchDB('test', { adapter: 'memory' })
|
|
22
|
+
options = { selector: { status: { $eq: true } } }
|
|
23
|
+
await db.createIndex({ index: { fields: ['status'] } })
|
|
24
|
+
await insertData(db, 105)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
await db.destroy()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should get all docs', async () => {
|
|
32
|
+
const resp = await getDocs(db, 'allDocs', options)
|
|
33
|
+
expect(resp.rows).toHaveLength(106) // include design doc
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should get 20 docs with allDocs', async () => {
|
|
37
|
+
const resp = await getDocs(db, 'allDocs', { limit: 20 })
|
|
38
|
+
expect(resp.rows).toHaveLength(20)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should find docs with default limit', async () => {
|
|
42
|
+
const resp = await getDocs(db, 'find', options)
|
|
43
|
+
expect(resp.docs).toHaveLength(105) // does not include design doc
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should get 20 docs with find', async () => {
|
|
47
|
+
const resp = await getDocs(db, 'find', { ...options, limit: 20 })
|
|
48
|
+
expect(resp.docs).toHaveLength(20)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('should get a single doc by id', async () => {
|
|
52
|
+
const resp = await getDocs(db, 'get', { ...options, id: 'doc0' })
|
|
53
|
+
expect(resp._id).toEqual('doc0')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should get a multiple docs by ids', async () => {
|
|
57
|
+
const resp = await getDocs(db, 'allDocs', {
|
|
58
|
+
...options,
|
|
59
|
+
keys: ['doc0', 'doc1', 'doc2']
|
|
60
|
+
})
|
|
61
|
+
expect(resp.rows).toHaveLength(3)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
|
|
10
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
11
|
+
|
|
12
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
13
|
+
|
|
14
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
15
|
+
|
|
16
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
17
|
+
|
|
18
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
19
|
+
|
|
20
|
+
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
21
|
+
|
|
22
|
+
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
23
|
+
|
|
24
|
+
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
25
|
+
|
|
26
|
+
var _mango = require("../../mango");
|
|
27
|
+
|
|
28
|
+
var _dbInterface = _interopRequireDefault(require("../dbInterface"));
|
|
29
|
+
|
|
30
|
+
var _errors = require("../../errors");
|
|
31
|
+
|
|
32
|
+
var _getDocs = require("./getDocs");
|
|
33
|
+
|
|
34
|
+
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; }
|
|
35
|
+
|
|
36
|
+
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; }
|
|
37
|
+
|
|
38
|
+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
|
|
39
|
+
|
|
40
|
+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
41
|
+
|
|
42
|
+
var PouchDBQueryEngine = /*#__PURE__*/function (_DatabaseQueryEngine) {
|
|
43
|
+
(0, _inherits2.default)(PouchDBQueryEngine, _DatabaseQueryEngine);
|
|
44
|
+
|
|
45
|
+
var _super = _createSuper(PouchDBQueryEngine);
|
|
46
|
+
|
|
47
|
+
function PouchDBQueryEngine(pouchManager, doctype) {
|
|
48
|
+
var _this;
|
|
49
|
+
|
|
50
|
+
(0, _classCallCheck2.default)(this, PouchDBQueryEngine);
|
|
51
|
+
_this = _super.call(this);
|
|
52
|
+
_this.pouchManager = pouchManager;
|
|
53
|
+
_this.client = pouchManager === null || pouchManager === void 0 ? void 0 : pouchManager.client;
|
|
54
|
+
_this.doctype = doctype;
|
|
55
|
+
_this.db = null;
|
|
56
|
+
return _this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
(0, _createClass2.default)(PouchDBQueryEngine, [{
|
|
60
|
+
key: "openDB",
|
|
61
|
+
value: function openDB(dbName) {
|
|
62
|
+
this.db = this.pouchManager.getPouch(dbName);
|
|
63
|
+
return this.db;
|
|
64
|
+
}
|
|
65
|
+
}, {
|
|
66
|
+
key: "allDocs",
|
|
67
|
+
value: function () {
|
|
68
|
+
var _allDocs = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(options) {
|
|
69
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
70
|
+
while (1) {
|
|
71
|
+
switch (_context.prev = _context.next) {
|
|
72
|
+
case 0:
|
|
73
|
+
return _context.abrupt("return", (0, _getDocs.getDocsAndNormalize)({
|
|
74
|
+
client: this.client,
|
|
75
|
+
db: this.db,
|
|
76
|
+
doctype: this.doctype,
|
|
77
|
+
queryFunc: 'allDocs',
|
|
78
|
+
queryParams: _objectSpread({
|
|
79
|
+
include_docs: true
|
|
80
|
+
}, options)
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
case 1:
|
|
84
|
+
case "end":
|
|
85
|
+
return _context.stop();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}, _callee, this);
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
function allDocs(_x) {
|
|
92
|
+
return _allDocs.apply(this, arguments);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return allDocs;
|
|
96
|
+
}()
|
|
97
|
+
}, {
|
|
98
|
+
key: "getById",
|
|
99
|
+
value: function () {
|
|
100
|
+
var _getById = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(id) {
|
|
101
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
102
|
+
while (1) {
|
|
103
|
+
switch (_context2.prev = _context2.next) {
|
|
104
|
+
case 0:
|
|
105
|
+
return _context2.abrupt("return", (0, _getDocs.getDocsAndNormalize)({
|
|
106
|
+
client: this.client,
|
|
107
|
+
db: this.db,
|
|
108
|
+
doctype: this.doctype,
|
|
109
|
+
queryFunc: 'get',
|
|
110
|
+
queryParams: {
|
|
111
|
+
id: id
|
|
112
|
+
},
|
|
113
|
+
withRows: false
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
case 1:
|
|
117
|
+
case "end":
|
|
118
|
+
return _context2.stop();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}, _callee2, this);
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
function getById(_x2) {
|
|
125
|
+
return _getById.apply(this, arguments);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return getById;
|
|
129
|
+
}()
|
|
130
|
+
}, {
|
|
131
|
+
key: "getByIds",
|
|
132
|
+
value: function () {
|
|
133
|
+
var _getByIds = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(ids) {
|
|
134
|
+
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
135
|
+
while (1) {
|
|
136
|
+
switch (_context3.prev = _context3.next) {
|
|
137
|
+
case 0:
|
|
138
|
+
return _context3.abrupt("return", (0, _getDocs.getDocsAndNormalize)({
|
|
139
|
+
client: this.client,
|
|
140
|
+
db: this.db,
|
|
141
|
+
doctype: this.doctype,
|
|
142
|
+
queryFunc: 'allDocs',
|
|
143
|
+
queryParams: {
|
|
144
|
+
include_docs: true,
|
|
145
|
+
keys: ids
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
|
|
149
|
+
case 1:
|
|
150
|
+
case "end":
|
|
151
|
+
return _context3.stop();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}, _callee3, this);
|
|
155
|
+
}));
|
|
156
|
+
|
|
157
|
+
function getByIds(_x3) {
|
|
158
|
+
return _getByIds.apply(this, arguments);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return getByIds;
|
|
162
|
+
}()
|
|
163
|
+
}, {
|
|
164
|
+
key: "find",
|
|
165
|
+
value: function () {
|
|
166
|
+
var _find = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(options) {
|
|
167
|
+
var selector, sort, partialFilter, doctype, indexedFields, indexName, findOpts, res;
|
|
168
|
+
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
169
|
+
while (1) {
|
|
170
|
+
switch (_context4.prev = _context4.next) {
|
|
171
|
+
case 0:
|
|
172
|
+
selector = options.selector, sort = options.sort, partialFilter = options.partialFilter, doctype = options.doctype;
|
|
173
|
+
indexedFields = options.indexedFields;
|
|
174
|
+
indexedFields = (0, _mango.getIndexFields)({
|
|
175
|
+
indexedFields: indexedFields,
|
|
176
|
+
selector: selector,
|
|
177
|
+
sort: sort,
|
|
178
|
+
partialFilter: partialFilter
|
|
179
|
+
});
|
|
180
|
+
indexName = (0, _mango.getIndexName)({
|
|
181
|
+
selector: selector,
|
|
182
|
+
sort: sort,
|
|
183
|
+
partialFilter: partialFilter,
|
|
184
|
+
indexedFields: indexedFields
|
|
185
|
+
});
|
|
186
|
+
findOpts = _objectSpread({
|
|
187
|
+
selector: selector,
|
|
188
|
+
sort: sort,
|
|
189
|
+
partialFilter: partialFilter,
|
|
190
|
+
doctype: doctype,
|
|
191
|
+
use_index: indexName
|
|
192
|
+
}, options);
|
|
193
|
+
findOpts.indexedFields = indexedFields;
|
|
194
|
+
_context4.prev = 6;
|
|
195
|
+
_context4.next = 9;
|
|
196
|
+
return (0, _getDocs.getDocsAndNormalize)({
|
|
197
|
+
client: this.client,
|
|
198
|
+
db: this.db,
|
|
199
|
+
doctype: this.doctype,
|
|
200
|
+
queryFunc: 'find',
|
|
201
|
+
queryParams: findOpts
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
case 9:
|
|
205
|
+
res = _context4.sent;
|
|
206
|
+
_context4.next = 23;
|
|
207
|
+
break;
|
|
208
|
+
|
|
209
|
+
case 12:
|
|
210
|
+
_context4.prev = 12;
|
|
211
|
+
_context4.t0 = _context4["catch"](6);
|
|
212
|
+
|
|
213
|
+
if (!(0, _errors.isMissingPouchDBIndexError)(_context4.t0)) {
|
|
214
|
+
_context4.next = 22;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
_context4.next = 17;
|
|
219
|
+
return (0, _mango.createIndex)(this.db, indexedFields, {
|
|
220
|
+
indexName: indexName,
|
|
221
|
+
doctype: doctype,
|
|
222
|
+
partialFilter: partialFilter
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
case 17:
|
|
226
|
+
_context4.next = 19;
|
|
227
|
+
return (0, _getDocs.getDocsAndNormalize)({
|
|
228
|
+
client: this.client,
|
|
229
|
+
db: this.db,
|
|
230
|
+
doctype: this.doctype,
|
|
231
|
+
queryFunc: 'find',
|
|
232
|
+
queryParams: findOpts
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
case 19:
|
|
236
|
+
res = _context4.sent;
|
|
237
|
+
_context4.next = 23;
|
|
238
|
+
break;
|
|
239
|
+
|
|
240
|
+
case 22:
|
|
241
|
+
throw _context4.t0;
|
|
242
|
+
|
|
243
|
+
case 23:
|
|
244
|
+
return _context4.abrupt("return", res);
|
|
245
|
+
|
|
246
|
+
case 24:
|
|
247
|
+
case "end":
|
|
248
|
+
return _context4.stop();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}, _callee4, this, [[6, 12]]);
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
function find(_x4) {
|
|
255
|
+
return _find.apply(this, arguments);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return find;
|
|
259
|
+
}()
|
|
260
|
+
}]);
|
|
261
|
+
return PouchDBQueryEngine;
|
|
262
|
+
}(_dbInterface.default);
|
|
263
|
+
|
|
264
|
+
exports.default = PouchDBQueryEngine;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import PouchDBQuery from './pouchdb'
|
|
2
|
+
import { createIndex } from '../../mango'
|
|
3
|
+
import { getDocsAndNormalize } from './getDocs'
|
|
4
|
+
import { Q } from 'cozy-client'
|
|
5
|
+
|
|
6
|
+
jest.mock('../../mango', () => ({
|
|
7
|
+
...jest.requireActual('../../mango'),
|
|
8
|
+
createIndex: jest.fn()
|
|
9
|
+
}))
|
|
10
|
+
|
|
11
|
+
jest.mock('./getDocs', () => ({
|
|
12
|
+
getDocsAndNormalize: jest.fn()
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
describe('PouchDBQuery find()', () => {
|
|
16
|
+
let pouchQE
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
pouchQE = new PouchDBQuery()
|
|
20
|
+
pouchQE.client = {}
|
|
21
|
+
pouchQE.db = {}
|
|
22
|
+
pouchQE.doctype = 'io.cozy.test'
|
|
23
|
+
|
|
24
|
+
jest.clearAllMocks()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should use provided indexedFields', async () => {
|
|
28
|
+
const options = {
|
|
29
|
+
selector: { name: 'John' },
|
|
30
|
+
sort: [{ name: 'asc' }],
|
|
31
|
+
indexedFields: ['name'],
|
|
32
|
+
doctype: 'io.cozy.test'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getDocsAndNormalize.mockResolvedValue([{ _id: '1', name: 'John' }])
|
|
36
|
+
|
|
37
|
+
const result = await pouchQE.find(options)
|
|
38
|
+
|
|
39
|
+
expect(getDocsAndNormalize).toHaveBeenCalledWith({
|
|
40
|
+
client: pouchQE.client,
|
|
41
|
+
db: pouchQE.db,
|
|
42
|
+
doctype: pouchQE.doctype,
|
|
43
|
+
queryFunc: 'find',
|
|
44
|
+
queryParams: expect.objectContaining({
|
|
45
|
+
selector: options.selector,
|
|
46
|
+
sort: options.sort,
|
|
47
|
+
partialFilter: options.partialFilter,
|
|
48
|
+
indexedFields: ['name'],
|
|
49
|
+
use_index: 'by_name'
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
expect(result).toEqual([{ _id: '1', name: 'John' }])
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should use the index attribute from the sort', async () => {
|
|
56
|
+
const query = Q('io.cozy.todos')
|
|
57
|
+
.where({})
|
|
58
|
+
.sortBy([{ name: 'asc' }])
|
|
59
|
+
await pouchQE.find(query)
|
|
60
|
+
expect(getDocsAndNormalize).toHaveBeenCalledWith({
|
|
61
|
+
client: pouchQE.client,
|
|
62
|
+
db: pouchQE.db,
|
|
63
|
+
doctype: pouchQE.doctype,
|
|
64
|
+
queryFunc: 'find',
|
|
65
|
+
queryParams: expect.objectContaining({
|
|
66
|
+
sort: query.sort,
|
|
67
|
+
indexedFields: ['name'],
|
|
68
|
+
use_index: 'by_name'
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should handle partialIndex', async () => {
|
|
74
|
+
const query = Q('io.cozy.todos')
|
|
75
|
+
.indexFields(['name'])
|
|
76
|
+
.partialIndex({ name: { $exists: true } })
|
|
77
|
+
await pouchQE.find(query)
|
|
78
|
+
expect(getDocsAndNormalize).toHaveBeenCalledWith({
|
|
79
|
+
client: pouchQE.client,
|
|
80
|
+
db: pouchQE.db,
|
|
81
|
+
doctype: pouchQE.doctype,
|
|
82
|
+
queryFunc: 'find',
|
|
83
|
+
queryParams: expect.objectContaining({
|
|
84
|
+
partialFilter: { name: { $exists: true } },
|
|
85
|
+
indexedFields: ['name'],
|
|
86
|
+
use_index: 'by_name_filter_(name_$exists_true)'
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should handle complex index name for partial filters ', async () => {
|
|
92
|
+
const query = Q('io.cozy.todos')
|
|
93
|
+
.indexFields(['name'])
|
|
94
|
+
.partialIndex({
|
|
95
|
+
$and: [{ name: { $exists: true } }, { date: { $gt: null } }],
|
|
96
|
+
$or: [{ count: { $eq: '1' } }, { count: { $eq: '2' } }]
|
|
97
|
+
})
|
|
98
|
+
await pouchQE.find(query)
|
|
99
|
+
expect(getDocsAndNormalize).toHaveBeenCalledWith({
|
|
100
|
+
client: pouchQE.client,
|
|
101
|
+
db: pouchQE.db,
|
|
102
|
+
doctype: pouchQE.doctype,
|
|
103
|
+
queryFunc: 'find',
|
|
104
|
+
queryParams: expect.objectContaining({
|
|
105
|
+
partialFilter: {
|
|
106
|
+
$and: [{ name: { $exists: true } }, { date: { $gt: null } }],
|
|
107
|
+
$or: [{ count: { $eq: '1' } }, { count: { $eq: '2' } }]
|
|
108
|
+
},
|
|
109
|
+
indexedFields: ['name'],
|
|
110
|
+
use_index:
|
|
111
|
+
'by_name_filter_((name_$exists_true)_$and_(date_$gt_null))_and_((count_$eq_1)_$or_(count_$eq_2))'
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('should create index and retry query if missing index error occurs', async () => {
|
|
117
|
+
const options = {
|
|
118
|
+
selector: { age: { $gt: 18 } },
|
|
119
|
+
sort: [{ age: 'desc' }],
|
|
120
|
+
indexedFields: ['age'],
|
|
121
|
+
doctype: 'io.cozy.test'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const mockError = new Error('no index')
|
|
125
|
+
|
|
126
|
+
getDocsAndNormalize
|
|
127
|
+
.mockRejectedValueOnce(mockError)
|
|
128
|
+
.mockResolvedValueOnce([{ _id: '2', age: 20 }])
|
|
129
|
+
|
|
130
|
+
const result = await pouchQE.find(options)
|
|
131
|
+
|
|
132
|
+
expect(createIndex).toHaveBeenCalledWith(pouchQE.db, ['age'], {
|
|
133
|
+
indexName: 'by_age',
|
|
134
|
+
doctype: 'io.cozy.test'
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
expect(getDocsAndNormalize).toHaveBeenCalledTimes(2)
|
|
138
|
+
expect(result).toEqual([{ _id: '2', age: 20 }])
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should throw error if non-index related error occurs', async () => {
|
|
142
|
+
const options = { selector: { status: 'active' } }
|
|
143
|
+
const mockError = new Error('generic error')
|
|
144
|
+
|
|
145
|
+
getDocsAndNormalize.mockRejectedValue(mockError)
|
|
146
|
+
|
|
147
|
+
await expect(pouchQE.find(options)).rejects.toThrow('generic error')
|
|
148
|
+
|
|
149
|
+
expect(createIndex).not.toHaveBeenCalled()
|
|
150
|
+
})
|
|
151
|
+
})
|