@aws-amplify/datastore 5.0.1-api-v6-models.c1977f8.0 → 5.0.1-api-v6-models.891fe0d.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/lib/authModeStrategies/defaultAuthStrategy.js +1 -1
- package/lib/authModeStrategies/multiAuthStrategy.js +29 -105
- package/lib/datastore/datastore.js +887 -1370
- package/lib/index.js +1 -1
- package/lib/predicates/index.js +53 -102
- package/lib/predicates/next.js +310 -557
- package/lib/predicates/sort.js +24 -27
- package/lib/ssr/index.js +1 -1
- package/lib/storage/adapter/AsyncStorageAdapter.js +115 -449
- package/lib/storage/adapter/AsyncStorageDatabase.js +215 -480
- package/lib/storage/adapter/InMemoryStore.js +27 -101
- package/lib/storage/adapter/InMemoryStore.native.js +1 -1
- package/lib/storage/adapter/IndexedDBAdapter.js +441 -1002
- package/lib/storage/adapter/StorageAdapterBase.js +177 -396
- package/lib/storage/adapter/getDefaultAdapter/index.js +5 -6
- package/lib/storage/adapter/getDefaultAdapter/index.native.js +2 -2
- package/lib/storage/relationship.js +174 -260
- package/lib/storage/storage.js +244 -507
- package/lib/sync/datastoreConnectivity.js +29 -84
- package/lib/sync/datastoreReachability/index.js +1 -1
- package/lib/sync/datastoreReachability/index.native.js +2 -2
- package/lib/sync/index.js +512 -885
- package/lib/sync/merger.js +30 -133
- package/lib/sync/outbox.js +147 -302
- package/lib/sync/processors/errorMaps.js +30 -80
- package/lib/sync/processors/mutation.js +331 -579
- package/lib/sync/processors/subscription.js +268 -428
- package/lib/sync/processors/sync.js +276 -464
- package/lib/sync/utils.js +248 -393
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.js +16 -58
- package/lib/util.js +335 -575
- package/lib-esm/authModeStrategies/defaultAuthStrategy.js +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js +27 -103
- package/lib-esm/datastore/datastore.js +874 -1359
- package/lib-esm/index.js +6 -6
- package/lib-esm/predicates/index.js +54 -104
- package/lib-esm/predicates/next.js +306 -555
- package/lib-esm/predicates/sort.js +24 -27
- package/lib-esm/ssr/index.js +1 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +111 -446
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +212 -477
- package/lib-esm/storage/adapter/InMemoryStore.js +27 -102
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +436 -997
- package/lib-esm/storage/adapter/StorageAdapterBase.js +172 -392
- package/lib-esm/storage/adapter/getDefaultAdapter/index.js +2 -3
- package/lib-esm/storage/adapter/getDefaultAdapter/index.native.js +1 -1
- package/lib-esm/storage/relationship.js +173 -260
- package/lib-esm/storage/storage.js +236 -499
- package/lib-esm/sync/datastoreConnectivity.js +26 -82
- package/lib-esm/sync/datastoreReachability/index.js +1 -1
- package/lib-esm/sync/datastoreReachability/index.native.js +1 -1
- package/lib-esm/sync/index.js +498 -872
- package/lib-esm/sync/merger.js +28 -131
- package/lib-esm/sync/outbox.js +143 -298
- package/lib-esm/sync/processors/errorMaps.js +32 -82
- package/lib-esm/sync/processors/mutation.js +324 -572
- package/lib-esm/sync/processors/subscription.js +258 -418
- package/lib-esm/sync/processors/sync.js +269 -457
- package/lib-esm/sync/utils.js +245 -390
- package/lib-esm/tsconfig.tsbuildinfo +1 -1
- package/lib-esm/types.js +16 -59
- package/lib-esm/util.js +335 -577
- package/package.json +12 -12
- package/src/datastore/datastore.ts +4 -3
- package/src/storage/adapter/getDefaultAdapter/index.ts +1 -3
- package/src/sync/processors/mutation.ts +1 -1
- package/src/sync/processors/sync.ts +1 -1
- package/src/sync/utils.ts +1 -1
- package/src/util.ts +44 -6
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
3
|
if (k2 === undefined) k2 = k;
|
|
19
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -37,94 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
37
22
|
__setModuleDefault(result, mod);
|
|
38
23
|
return result;
|
|
39
24
|
};
|
|
40
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
41
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
42
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
43
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
44
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
45
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
46
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
47
|
-
});
|
|
48
|
-
};
|
|
49
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
50
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
51
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
52
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
53
|
-
function step(op) {
|
|
54
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
55
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
56
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
57
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
58
|
-
switch (op[0]) {
|
|
59
|
-
case 0: case 1: t = op; break;
|
|
60
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
61
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
62
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
63
|
-
default:
|
|
64
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
65
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
66
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
67
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
68
|
-
if (t[2]) _.ops.pop();
|
|
69
|
-
_.trys.pop(); continue;
|
|
70
|
-
}
|
|
71
|
-
op = body.call(thisArg, _);
|
|
72
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
73
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
77
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
78
|
-
var m = o[Symbol.asyncIterator], i;
|
|
79
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
80
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
81
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
82
|
-
};
|
|
83
|
-
var __values = (this && this.__values) || function(o) {
|
|
84
|
-
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
85
|
-
if (m) return m.call(o);
|
|
86
|
-
if (o && typeof o.length === "number") return {
|
|
87
|
-
next: function () {
|
|
88
|
-
if (o && i >= o.length) o = void 0;
|
|
89
|
-
return { value: o && o[i++], done: !o };
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
93
|
-
};
|
|
94
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
95
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
96
|
-
if (!m) return o;
|
|
97
|
-
var i = m.call(o), r, ar = [], e;
|
|
98
|
-
try {
|
|
99
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
100
|
-
}
|
|
101
|
-
catch (error) { e = { error: error }; }
|
|
102
|
-
finally {
|
|
103
|
-
try {
|
|
104
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
105
|
-
}
|
|
106
|
-
finally { if (e) throw e.error; }
|
|
107
|
-
}
|
|
108
|
-
return ar;
|
|
109
|
-
};
|
|
110
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
111
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
112
|
-
if (ar || !(i in from)) {
|
|
113
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
114
|
-
ar[i] = from[i];
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
118
|
-
};
|
|
119
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
120
26
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
121
27
|
// SPDX-License-Identifier: Apache-2.0
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
28
|
+
const idb = __importStar(require("idb"));
|
|
29
|
+
const types_1 = require("../../types");
|
|
30
|
+
const util_1 = require("../../util");
|
|
31
|
+
const StorageAdapterBase_1 = require("./StorageAdapterBase");
|
|
32
|
+
const core_1 = require("@aws-amplify/core");
|
|
33
|
+
const logger = new core_1.ConsoleLogger('DataStore');
|
|
128
34
|
/**
|
|
129
35
|
* The point after which queries composed of multiple simple OR conditions
|
|
130
36
|
* should scan-and-filter instead of individual queries for each condition.
|
|
@@ -146,14 +52,13 @@ var logger = new core_1.ConsoleLogger('DataStore');
|
|
|
146
52
|
* etc...
|
|
147
53
|
*
|
|
148
54
|
*/
|
|
149
|
-
|
|
55
|
+
const MULTI_OR_CONDITION_SCAN_BREAKPOINT = 7;
|
|
150
56
|
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
_this.safariCompatabilityMode = false;
|
|
57
|
+
const DB_VERSION = 3;
|
|
58
|
+
class IndexedDBAdapter extends StorageAdapterBase_1.StorageAdapterBase {
|
|
59
|
+
constructor() {
|
|
60
|
+
super(...arguments);
|
|
61
|
+
this.safariCompatabilityMode = false;
|
|
157
62
|
/**
|
|
158
63
|
* Checks the given path against the browser's IndexedDB implementation for
|
|
159
64
|
* necessary compatibility transformations, applying those transforms if needed.
|
|
@@ -162,43 +67,22 @@ var IndexedDBAdapter = /** @class */ (function (_super) {
|
|
|
162
67
|
* @returns An array or string, depending on and given key,
|
|
163
68
|
* that is ensured to be compatible with the IndexedDB implementation's nuances.
|
|
164
69
|
*/
|
|
165
|
-
|
|
166
|
-
if (
|
|
70
|
+
this.canonicalKeyPath = (keyArr) => {
|
|
71
|
+
if (this.safariCompatabilityMode) {
|
|
167
72
|
return keyArr.length > 1 ? keyArr : keyArr[0];
|
|
168
73
|
}
|
|
169
74
|
return keyArr;
|
|
170
75
|
};
|
|
171
|
-
return _this;
|
|
172
76
|
//#endregion
|
|
173
77
|
}
|
|
174
78
|
// checks are called by StorageAdapterBase class
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return [4 /*yield*/, this.setSafariCompatabilityMode()];
|
|
183
|
-
case 2:
|
|
184
|
-
_a.sent();
|
|
185
|
-
return [2 /*return*/];
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
};
|
|
190
|
-
IndexedDBAdapter.prototype.preOpCheck = function () {
|
|
191
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
192
|
-
return __generator(this, function (_a) {
|
|
193
|
-
switch (_a.label) {
|
|
194
|
-
case 0: return [4 /*yield*/, this.checkPrivate()];
|
|
195
|
-
case 1:
|
|
196
|
-
_a.sent();
|
|
197
|
-
return [2 /*return*/];
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
};
|
|
79
|
+
async preSetUpChecks() {
|
|
80
|
+
await this.checkPrivate();
|
|
81
|
+
await this.setSafariCompatabilityMode();
|
|
82
|
+
}
|
|
83
|
+
async preOpCheck() {
|
|
84
|
+
await this.checkPrivate();
|
|
85
|
+
}
|
|
202
86
|
/**
|
|
203
87
|
* Initialize IndexedDB database
|
|
204
88
|
* Create new DB if one doesn't exist
|
|
@@ -208,559 +92,245 @@ var IndexedDBAdapter = /** @class */ (function (_super) {
|
|
|
208
92
|
*
|
|
209
93
|
* @returns IDB Database instance
|
|
210
94
|
*/
|
|
211
|
-
|
|
212
|
-
return
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// create new database
|
|
225
|
-
if (oldVersion === 0) {
|
|
226
|
-
Object.keys(this.schema.namespaces).forEach(function (namespaceName) {
|
|
227
|
-
var namespace = _this.schema.namespaces[namespaceName];
|
|
228
|
-
Object.keys(namespace.models).forEach(function (modelName) {
|
|
229
|
-
var storeName = (0, util_1.getStorename)(namespaceName, modelName);
|
|
230
|
-
_this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
return [2 /*return*/];
|
|
234
|
-
}
|
|
235
|
-
if (!((oldVersion === 1 || oldVersion === 2) && newVersion === 3)) return [3 /*break*/, 16];
|
|
236
|
-
_e.label = 1;
|
|
237
|
-
case 1:
|
|
238
|
-
_e.trys.push([1, 14, , 15]);
|
|
239
|
-
_e.label = 2;
|
|
240
|
-
case 2:
|
|
241
|
-
_e.trys.push([2, 11, 12, 13]);
|
|
242
|
-
_a = __values(txn.objectStoreNames), _b = _a.next();
|
|
243
|
-
_e.label = 3;
|
|
244
|
-
case 3:
|
|
245
|
-
if (!!_b.done) return [3 /*break*/, 10];
|
|
246
|
-
storeName = _b.value;
|
|
247
|
-
origStore = txn.objectStore(storeName);
|
|
248
|
-
tmpName = "tmp_".concat(storeName);
|
|
249
|
-
origStore.name = tmpName;
|
|
250
|
-
_c = this.getNamespaceAndModelFromStorename(storeName), namespaceName = _c.namespaceName, modelName = _c.modelName;
|
|
251
|
-
modelInCurrentSchema = modelName in this.schema.namespaces[namespaceName].models;
|
|
252
|
-
if (!modelInCurrentSchema) {
|
|
253
|
-
// delete original
|
|
254
|
-
db.deleteObjectStore(tmpName);
|
|
255
|
-
return [3 /*break*/, 9];
|
|
256
|
-
}
|
|
257
|
-
newStore = this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
258
|
-
return [4 /*yield*/, origStore.openCursor()];
|
|
259
|
-
case 4:
|
|
260
|
-
cursor = _e.sent();
|
|
261
|
-
count = 0;
|
|
262
|
-
_e.label = 5;
|
|
263
|
-
case 5:
|
|
264
|
-
if (!(cursor && cursor.value)) return [3 /*break*/, 8];
|
|
265
|
-
// we don't pass key, since they are all new entries in the new store
|
|
266
|
-
return [4 /*yield*/, newStore.put(cursor.value)];
|
|
267
|
-
case 6:
|
|
268
|
-
// we don't pass key, since they are all new entries in the new store
|
|
269
|
-
_e.sent();
|
|
270
|
-
return [4 /*yield*/, cursor.continue()];
|
|
271
|
-
case 7:
|
|
272
|
-
cursor = _e.sent();
|
|
273
|
-
count++;
|
|
274
|
-
return [3 /*break*/, 5];
|
|
275
|
-
case 8:
|
|
276
|
-
// delete original
|
|
277
|
-
db.deleteObjectStore(tmpName);
|
|
278
|
-
logger.debug("".concat(count, " ").concat(storeName, " records migrated"));
|
|
279
|
-
_e.label = 9;
|
|
280
|
-
case 9:
|
|
281
|
-
_b = _a.next();
|
|
282
|
-
return [3 /*break*/, 3];
|
|
283
|
-
case 10: return [3 /*break*/, 13];
|
|
284
|
-
case 11:
|
|
285
|
-
e_1_1 = _e.sent();
|
|
286
|
-
e_1 = { error: e_1_1 };
|
|
287
|
-
return [3 /*break*/, 13];
|
|
288
|
-
case 12:
|
|
289
|
-
try {
|
|
290
|
-
if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
|
|
291
|
-
}
|
|
292
|
-
finally { if (e_1) throw e_1.error; }
|
|
293
|
-
return [7 /*endfinally*/];
|
|
294
|
-
case 13:
|
|
295
|
-
// add new models created after IndexedDB, but before migration
|
|
296
|
-
// this case may happen when a user has not opened an app for
|
|
297
|
-
// some time and a new model is added during that time
|
|
298
|
-
Object.keys(this.schema.namespaces).forEach(function (namespaceName) {
|
|
299
|
-
var namespace = _this.schema.namespaces[namespaceName];
|
|
300
|
-
var objectStoreNames = new Set(txn.objectStoreNames);
|
|
301
|
-
Object.keys(namespace.models)
|
|
302
|
-
.map(function (modelName) {
|
|
303
|
-
return [modelName, (0, util_1.getStorename)(namespaceName, modelName)];
|
|
304
|
-
})
|
|
305
|
-
.filter(function (_a) {
|
|
306
|
-
var _b = __read(_a, 2), storeName = _b[1];
|
|
307
|
-
return !objectStoreNames.has(storeName);
|
|
308
|
-
})
|
|
309
|
-
.forEach(function (_a) {
|
|
310
|
-
var _b = __read(_a, 2), modelName = _b[0], storeName = _b[1];
|
|
311
|
-
_this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
return [3 /*break*/, 15];
|
|
315
|
-
case 14:
|
|
316
|
-
error_1 = _e.sent();
|
|
317
|
-
logger.error('Error migrating IndexedDB data', error_1);
|
|
318
|
-
txn.abort();
|
|
319
|
-
throw error_1;
|
|
320
|
-
case 15: return [2 /*return*/];
|
|
321
|
-
case 16: return [2 /*return*/];
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
}); },
|
|
325
|
-
})];
|
|
326
|
-
case 1: return [2 /*return*/, _a.sent()];
|
|
95
|
+
async initDb() {
|
|
96
|
+
return await idb.openDB(this.dbName, DB_VERSION, {
|
|
97
|
+
upgrade: async (db, oldVersion, newVersion, txn) => {
|
|
98
|
+
// create new database
|
|
99
|
+
if (oldVersion === 0) {
|
|
100
|
+
Object.keys(this.schema.namespaces).forEach(namespaceName => {
|
|
101
|
+
const namespace = this.schema.namespaces[namespaceName];
|
|
102
|
+
Object.keys(namespace.models).forEach(modelName => {
|
|
103
|
+
const storeName = (0, util_1.getStorename)(namespaceName, modelName);
|
|
104
|
+
this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
327
108
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
109
|
+
// migrate existing database to latest schema
|
|
110
|
+
if ((oldVersion === 1 || oldVersion === 2) && newVersion === 3) {
|
|
111
|
+
try {
|
|
112
|
+
for (const storeName of txn.objectStoreNames) {
|
|
113
|
+
const origStore = txn.objectStore(storeName);
|
|
114
|
+
// rename original store
|
|
115
|
+
const tmpName = `tmp_${storeName}`;
|
|
116
|
+
origStore.name = tmpName;
|
|
117
|
+
const { namespaceName, modelName } = this.getNamespaceAndModelFromStorename(storeName);
|
|
118
|
+
const modelInCurrentSchema = modelName in this.schema.namespaces[namespaceName].models;
|
|
119
|
+
if (!modelInCurrentSchema) {
|
|
120
|
+
// delete original
|
|
121
|
+
db.deleteObjectStore(tmpName);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const newStore = this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
125
|
+
let cursor = await origStore.openCursor();
|
|
126
|
+
let count = 0;
|
|
127
|
+
// Copy data from original to new
|
|
128
|
+
while (cursor && cursor.value) {
|
|
129
|
+
// we don't pass key, since they are all new entries in the new store
|
|
130
|
+
await newStore.put(cursor.value);
|
|
131
|
+
cursor = await cursor.continue();
|
|
132
|
+
count++;
|
|
133
|
+
}
|
|
134
|
+
// delete original
|
|
135
|
+
db.deleteObjectStore(tmpName);
|
|
136
|
+
logger.debug(`${count} ${storeName} records migrated`);
|
|
344
137
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
case 0: return [4 /*yield*/, this.checkPrivate()];
|
|
359
|
-
case 1:
|
|
360
|
-
_b.sent();
|
|
361
|
-
(_a = this.db) === null || _a === void 0 ? void 0 : _a.close();
|
|
362
|
-
return [4 /*yield*/, idb.deleteDB(this.dbName)];
|
|
363
|
-
case 2:
|
|
364
|
-
_b.sent();
|
|
365
|
-
this.db = undefined;
|
|
366
|
-
this.initPromise = undefined;
|
|
367
|
-
return [2 /*return*/];
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
|
-
};
|
|
372
|
-
IndexedDBAdapter.prototype.save = function (model, condition) {
|
|
373
|
-
var _a, e_2, _b, _c;
|
|
374
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
375
|
-
var _d, storeName, set, connectionStoreNames, modelKeyValues, tx, store, fromDB, result, _loop_1, this_1, _e, connectionStoreNames_1, connectionStoreNames_1_1, e_2_1;
|
|
376
|
-
return __generator(this, function (_f) {
|
|
377
|
-
switch (_f.label) {
|
|
378
|
-
case 0: return [4 /*yield*/, this.checkPrivate()];
|
|
379
|
-
case 1:
|
|
380
|
-
_f.sent();
|
|
381
|
-
_d = this.saveMetadata(model), storeName = _d.storeName, set = _d.set, connectionStoreNames = _d.connectionStoreNames, modelKeyValues = _d.modelKeyValues;
|
|
382
|
-
tx = this.db.transaction(__spreadArray([storeName], __read(Array.from(set.values())), false), 'readwrite');
|
|
383
|
-
store = tx.objectStore(storeName);
|
|
384
|
-
return [4 /*yield*/, this._get(store, modelKeyValues)];
|
|
385
|
-
case 2:
|
|
386
|
-
fromDB = _f.sent();
|
|
387
|
-
this.validateSaveCondition(condition, fromDB);
|
|
388
|
-
result = [];
|
|
389
|
-
_f.label = 3;
|
|
390
|
-
case 3:
|
|
391
|
-
_f.trys.push([3, 9, 10, 15]);
|
|
392
|
-
_loop_1 = function () {
|
|
393
|
-
var resItem, storeName_1, item, instance, keys, store_1, itemKeyValues, fromDB_1, opType, key;
|
|
394
|
-
return __generator(this, function (_g) {
|
|
395
|
-
switch (_g.label) {
|
|
396
|
-
case 0:
|
|
397
|
-
_c = connectionStoreNames_1_1.value;
|
|
398
|
-
_e = false;
|
|
399
|
-
_g.label = 1;
|
|
400
|
-
case 1:
|
|
401
|
-
_g.trys.push([1, , 6, 7]);
|
|
402
|
-
resItem = _c;
|
|
403
|
-
storeName_1 = resItem.storeName, item = resItem.item, instance = resItem.instance, keys = resItem.keys;
|
|
404
|
-
store_1 = tx.objectStore(storeName_1);
|
|
405
|
-
itemKeyValues = keys.map(function (key) { return item[key]; });
|
|
406
|
-
return [4 /*yield*/, this_1._get(store_1, itemKeyValues)];
|
|
407
|
-
case 2:
|
|
408
|
-
fromDB_1 = _g.sent();
|
|
409
|
-
opType = fromDB_1 ? types_1.OpType.UPDATE : types_1.OpType.INSERT;
|
|
410
|
-
if (!((0, util_1.keysEqual)(itemKeyValues, modelKeyValues) ||
|
|
411
|
-
opType === types_1.OpType.INSERT)) return [3 /*break*/, 5];
|
|
412
|
-
return [4 /*yield*/, store_1
|
|
413
|
-
.index('byPk')
|
|
414
|
-
.getKey(this_1.canonicalKeyPath(itemKeyValues))];
|
|
415
|
-
case 3:
|
|
416
|
-
key = _g.sent();
|
|
417
|
-
return [4 /*yield*/, store_1.put(item, key)];
|
|
418
|
-
case 4:
|
|
419
|
-
_g.sent();
|
|
420
|
-
result.push([instance, opType]);
|
|
421
|
-
_g.label = 5;
|
|
422
|
-
case 5: return [3 /*break*/, 7];
|
|
423
|
-
case 6:
|
|
424
|
-
_e = true;
|
|
425
|
-
return [7 /*endfinally*/];
|
|
426
|
-
case 7: return [2 /*return*/];
|
|
427
|
-
}
|
|
138
|
+
// add new models created after IndexedDB, but before migration
|
|
139
|
+
// this case may happen when a user has not opened an app for
|
|
140
|
+
// some time and a new model is added during that time
|
|
141
|
+
Object.keys(this.schema.namespaces).forEach(namespaceName => {
|
|
142
|
+
const namespace = this.schema.namespaces[namespaceName];
|
|
143
|
+
const objectStoreNames = new Set(txn.objectStoreNames);
|
|
144
|
+
Object.keys(namespace.models)
|
|
145
|
+
.map(modelName => {
|
|
146
|
+
return [modelName, (0, util_1.getStorename)(namespaceName, modelName)];
|
|
147
|
+
})
|
|
148
|
+
.filter(([, storeName]) => !objectStoreNames.has(storeName))
|
|
149
|
+
.forEach(([modelName, storeName]) => {
|
|
150
|
+
this.createObjectStoreForModel(db, namespaceName, storeName, modelName);
|
|
428
151
|
});
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
case 6:
|
|
438
|
-
_f.sent();
|
|
439
|
-
_f.label = 7;
|
|
440
|
-
case 7: return [3 /*break*/, 4];
|
|
441
|
-
case 8: return [3 /*break*/, 15];
|
|
442
|
-
case 9:
|
|
443
|
-
e_2_1 = _f.sent();
|
|
444
|
-
e_2 = { error: e_2_1 };
|
|
445
|
-
return [3 /*break*/, 15];
|
|
446
|
-
case 10:
|
|
447
|
-
_f.trys.push([10, , 13, 14]);
|
|
448
|
-
if (!(!_e && !_a && (_b = connectionStoreNames_1.return))) return [3 /*break*/, 12];
|
|
449
|
-
return [4 /*yield*/, _b.call(connectionStoreNames_1)];
|
|
450
|
-
case 11:
|
|
451
|
-
_f.sent();
|
|
452
|
-
_f.label = 12;
|
|
453
|
-
case 12: return [3 /*break*/, 14];
|
|
454
|
-
case 13:
|
|
455
|
-
if (e_2) throw e_2.error;
|
|
456
|
-
return [7 /*endfinally*/];
|
|
457
|
-
case 14: return [7 /*endfinally*/];
|
|
458
|
-
case 15: return [4 /*yield*/, tx.done];
|
|
459
|
-
case 16:
|
|
460
|
-
_f.sent();
|
|
461
|
-
return [2 /*return*/, result];
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
};
|
|
466
|
-
IndexedDBAdapter.prototype.query = function (modelConstructor, predicate, pagination) {
|
|
467
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
468
|
-
var _a, storeName, namespaceName, queryByKey, predicates, hasSort, hasPagination, records;
|
|
469
|
-
var _this = this;
|
|
470
|
-
return __generator(this, function (_b) {
|
|
471
|
-
switch (_b.label) {
|
|
472
|
-
case 0: return [4 /*yield*/, this.checkPrivate()];
|
|
473
|
-
case 1:
|
|
474
|
-
_b.sent();
|
|
475
|
-
_a = this.queryMetadata(modelConstructor, predicate, pagination), storeName = _a.storeName, namespaceName = _a.namespaceName, queryByKey = _a.queryByKey, predicates = _a.predicates, hasSort = _a.hasSort, hasPagination = _a.hasPagination;
|
|
476
|
-
return [4 /*yield*/, (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
477
|
-
var record, filtered, all;
|
|
478
|
-
return __generator(this, function (_a) {
|
|
479
|
-
switch (_a.label) {
|
|
480
|
-
case 0:
|
|
481
|
-
if (!queryByKey) return [3 /*break*/, 2];
|
|
482
|
-
return [4 /*yield*/, this.getByKey(storeName, queryByKey)];
|
|
483
|
-
case 1:
|
|
484
|
-
record = _a.sent();
|
|
485
|
-
return [2 /*return*/, record ? [record] : []];
|
|
486
|
-
case 2:
|
|
487
|
-
if (!predicates) return [3 /*break*/, 4];
|
|
488
|
-
return [4 /*yield*/, this.filterOnPredicate(storeName, predicates)];
|
|
489
|
-
case 3:
|
|
490
|
-
filtered = _a.sent();
|
|
491
|
-
return [2 /*return*/, this.inMemoryPagination(filtered, pagination)];
|
|
492
|
-
case 4:
|
|
493
|
-
if (!hasSort) return [3 /*break*/, 6];
|
|
494
|
-
return [4 /*yield*/, this.getAll(storeName)];
|
|
495
|
-
case 5:
|
|
496
|
-
all = _a.sent();
|
|
497
|
-
return [2 /*return*/, this.inMemoryPagination(all, pagination)];
|
|
498
|
-
case 6:
|
|
499
|
-
if (hasPagination) {
|
|
500
|
-
return [2 /*return*/, this.enginePagination(storeName, pagination)];
|
|
501
|
-
}
|
|
502
|
-
return [2 /*return*/, this.getAll(storeName)];
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
}); })()];
|
|
506
|
-
case 2:
|
|
507
|
-
records = (_b.sent());
|
|
508
|
-
return [4 /*yield*/, this.load(namespaceName, modelConstructor.name, records)];
|
|
509
|
-
case 3: return [2 /*return*/, _b.sent()];
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
};
|
|
514
|
-
IndexedDBAdapter.prototype.queryOne = function (modelConstructor, firstOrLast) {
|
|
515
|
-
if (firstOrLast === void 0) { firstOrLast = types_1.QueryOne.FIRST; }
|
|
516
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
517
|
-
var storeName, cursor, result;
|
|
518
|
-
return __generator(this, function (_a) {
|
|
519
|
-
switch (_a.label) {
|
|
520
|
-
case 0: return [4 /*yield*/, this.checkPrivate()];
|
|
521
|
-
case 1:
|
|
522
|
-
_a.sent();
|
|
523
|
-
storeName = this.getStorenameForModel(modelConstructor);
|
|
524
|
-
return [4 /*yield*/, this.db
|
|
525
|
-
.transaction([storeName], 'readonly')
|
|
526
|
-
.objectStore(storeName)
|
|
527
|
-
.openCursor(undefined, firstOrLast === types_1.QueryOne.FIRST ? 'next' : 'prev')];
|
|
528
|
-
case 2:
|
|
529
|
-
cursor = _a.sent();
|
|
530
|
-
result = cursor ? cursor.value : undefined;
|
|
531
|
-
return [2 /*return*/, result && this.modelInstanceCreator(modelConstructor, result)];
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.error('Error migrating IndexedDB data', error);
|
|
156
|
+
txn.abort();
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
532
160
|
}
|
|
533
|
-
}
|
|
161
|
+
},
|
|
534
162
|
});
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
163
|
+
}
|
|
164
|
+
async _get(storeOrStoreName, keyArr) {
|
|
165
|
+
let index;
|
|
166
|
+
if (typeof storeOrStoreName === 'string') {
|
|
167
|
+
const storeName = storeOrStoreName;
|
|
168
|
+
index = this.db.transaction(storeName, 'readonly').store.index('byPk');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const store = storeOrStoreName;
|
|
172
|
+
index = store.index('byPk');
|
|
173
|
+
}
|
|
174
|
+
const result = await index.get(this.canonicalKeyPath(keyArr));
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
async clear() {
|
|
178
|
+
await this.checkPrivate();
|
|
179
|
+
this.db?.close();
|
|
180
|
+
await idb.deleteDB(this.dbName);
|
|
181
|
+
this.db = undefined;
|
|
182
|
+
this.initPromise = undefined;
|
|
183
|
+
}
|
|
184
|
+
async save(model, condition) {
|
|
185
|
+
await this.checkPrivate();
|
|
186
|
+
const { storeName, set, connectionStoreNames, modelKeyValues } = this.saveMetadata(model);
|
|
187
|
+
const tx = this.db.transaction([storeName, ...Array.from(set.values())], 'readwrite');
|
|
188
|
+
const store = tx.objectStore(storeName);
|
|
189
|
+
const fromDB = await this._get(store, modelKeyValues);
|
|
190
|
+
this.validateSaveCondition(condition, fromDB);
|
|
191
|
+
const result = [];
|
|
192
|
+
for await (const resItem of connectionStoreNames) {
|
|
193
|
+
const { storeName, item, instance, keys } = resItem;
|
|
194
|
+
const store = tx.objectStore(storeName);
|
|
195
|
+
const itemKeyValues = keys.map(key => item[key]);
|
|
196
|
+
const fromDB = await this._get(store, itemKeyValues);
|
|
197
|
+
const opType = fromDB ? types_1.OpType.UPDATE : types_1.OpType.INSERT;
|
|
198
|
+
if ((0, util_1.keysEqual)(itemKeyValues, modelKeyValues) ||
|
|
199
|
+
opType === types_1.OpType.INSERT) {
|
|
200
|
+
const key = await store
|
|
201
|
+
.index('byPk')
|
|
202
|
+
.getKey(this.canonicalKeyPath(itemKeyValues));
|
|
203
|
+
await store.put(item, key);
|
|
204
|
+
result.push([instance, opType]);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
await tx.done;
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
async query(modelConstructor, predicate, pagination) {
|
|
211
|
+
await this.checkPrivate();
|
|
212
|
+
const { storeName, namespaceName, queryByKey, predicates, hasSort, hasPagination, } = this.queryMetadata(modelConstructor, predicate, pagination);
|
|
213
|
+
const records = (await (async () => {
|
|
214
|
+
//
|
|
215
|
+
// NOTE: @svidgen explored removing this and letting query() take care of automatic
|
|
216
|
+
// index leveraging. This would eliminate some amount of very similar code.
|
|
217
|
+
// But, getAll is slightly slower than get()
|
|
218
|
+
//
|
|
219
|
+
// On Chrome:
|
|
220
|
+
// ~700ms vs ~1175ms per 10k reads.
|
|
221
|
+
//
|
|
222
|
+
// You can (and should) check my work here:
|
|
223
|
+
// https://gist.github.com/svidgen/74e55d573b19c3e5432b1b5bdf0f4d96
|
|
224
|
+
//
|
|
225
|
+
if (queryByKey) {
|
|
226
|
+
const record = await this.getByKey(storeName, queryByKey);
|
|
227
|
+
return record ? [record] : [];
|
|
228
|
+
}
|
|
229
|
+
if (predicates) {
|
|
230
|
+
const filtered = await this.filterOnPredicate(storeName, predicates);
|
|
231
|
+
return this.inMemoryPagination(filtered, pagination);
|
|
232
|
+
}
|
|
233
|
+
if (hasSort) {
|
|
234
|
+
const all = await this.getAll(storeName);
|
|
235
|
+
return this.inMemoryPagination(all, pagination);
|
|
236
|
+
}
|
|
237
|
+
if (hasPagination) {
|
|
238
|
+
return this.enginePagination(storeName, pagination);
|
|
239
|
+
}
|
|
240
|
+
return this.getAll(storeName);
|
|
241
|
+
})());
|
|
242
|
+
return await this.load(namespaceName, modelConstructor.name, records);
|
|
243
|
+
}
|
|
244
|
+
async queryOne(modelConstructor, firstOrLast = types_1.QueryOne.FIRST) {
|
|
245
|
+
await this.checkPrivate();
|
|
246
|
+
const storeName = this.getStorenameForModel(modelConstructor);
|
|
247
|
+
const cursor = await this.db
|
|
248
|
+
.transaction([storeName], 'readonly')
|
|
249
|
+
.objectStore(storeName)
|
|
250
|
+
.openCursor(undefined, firstOrLast === types_1.QueryOne.FIRST ? 'next' : 'prev');
|
|
251
|
+
const result = cursor ? cursor.value : undefined;
|
|
252
|
+
return result && this.modelInstanceCreator(modelConstructor, result);
|
|
253
|
+
}
|
|
254
|
+
async batchSave(modelConstructor, items) {
|
|
255
|
+
await this.checkPrivate();
|
|
256
|
+
if (items.length === 0) {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
const modelName = modelConstructor.name;
|
|
260
|
+
const namespaceName = this.namespaceResolver(modelConstructor);
|
|
261
|
+
const storeName = this.getStorenameForModel(modelConstructor);
|
|
262
|
+
const result = [];
|
|
263
|
+
const txn = this.db.transaction(storeName, 'readwrite');
|
|
264
|
+
const store = txn.store;
|
|
265
|
+
for (const item of items) {
|
|
266
|
+
const model = this.modelInstanceCreator(modelConstructor, item);
|
|
267
|
+
const connectedModels = (0, util_1.traverseModel)(modelName, model, this.schema.namespaces[namespaceName], this.modelInstanceCreator, this.getModelConstructorByModelName);
|
|
268
|
+
const keyValues = this.getIndexKeyValuesFromModel(model);
|
|
269
|
+
const { _deleted } = item;
|
|
270
|
+
const index = store.index('byPk');
|
|
271
|
+
const key = await index.getKey(this.canonicalKeyPath(keyValues));
|
|
272
|
+
if (!_deleted) {
|
|
273
|
+
const { instance } = connectedModels.find(({ instance }) => {
|
|
274
|
+
const instanceKeyValues = this.getIndexKeyValuesFromModel(instance);
|
|
275
|
+
return (0, util_1.keysEqual)(instanceKeyValues, keyValues);
|
|
276
|
+
});
|
|
277
|
+
result.push([
|
|
278
|
+
instance,
|
|
279
|
+
key ? types_1.OpType.UPDATE : types_1.OpType.INSERT,
|
|
280
|
+
]);
|
|
281
|
+
await store.put(instance, key);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
result.push([item, types_1.OpType.DELETE]);
|
|
285
|
+
if (key) {
|
|
286
|
+
await store.delete(key);
|
|
624
287
|
}
|
|
625
|
-
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
await txn.done;
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
async deleteItem(deleteQueue) {
|
|
294
|
+
const connectionStoreNames = deleteQueue.map(({ storeName }) => {
|
|
295
|
+
return storeName;
|
|
626
296
|
});
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (!(_j = _l.sent(), _a = _j.done, !_a)) return [3 /*break*/, 27];
|
|
648
|
-
_c = _j.value;
|
|
649
|
-
_g = false;
|
|
650
|
-
_l.label = 4;
|
|
651
|
-
case 4:
|
|
652
|
-
_l.trys.push([4, , 25, 26]);
|
|
653
|
-
deleteItem = _c;
|
|
654
|
-
storeName = deleteItem.storeName, items = deleteItem.items;
|
|
655
|
-
store = tx.objectStore(storeName);
|
|
656
|
-
_l.label = 5;
|
|
657
|
-
case 5:
|
|
658
|
-
_l.trys.push([5, 18, 19, 24]);
|
|
659
|
-
_k = true, items_2 = (e_5 = void 0, __asyncValues(items));
|
|
660
|
-
_l.label = 6;
|
|
661
|
-
case 6: return [4 /*yield*/, items_2.next()];
|
|
662
|
-
case 7:
|
|
663
|
-
if (!(items_2_1 = _l.sent(), _d = items_2_1.done, !_d)) return [3 /*break*/, 17];
|
|
664
|
-
_f = items_2_1.value;
|
|
665
|
-
_k = false;
|
|
666
|
-
_l.label = 8;
|
|
667
|
-
case 8:
|
|
668
|
-
_l.trys.push([8, , 15, 16]);
|
|
669
|
-
item = _f;
|
|
670
|
-
if (!item) return [3 /*break*/, 14];
|
|
671
|
-
key = void 0;
|
|
672
|
-
if (!(typeof item === 'object')) return [3 /*break*/, 10];
|
|
673
|
-
keyValues = this.getIndexKeyValuesFromModel(item);
|
|
674
|
-
return [4 /*yield*/, store
|
|
675
|
-
.index('byPk')
|
|
676
|
-
.getKey(this.canonicalKeyPath(keyValues))];
|
|
677
|
-
case 9:
|
|
678
|
-
key = _l.sent();
|
|
679
|
-
return [3 /*break*/, 12];
|
|
680
|
-
case 10:
|
|
681
|
-
itemKey = item.toString();
|
|
682
|
-
return [4 /*yield*/, store.index('byPk').getKey(itemKey)];
|
|
683
|
-
case 11:
|
|
684
|
-
key = _l.sent();
|
|
685
|
-
_l.label = 12;
|
|
686
|
-
case 12:
|
|
687
|
-
if (!(key !== undefined)) return [3 /*break*/, 14];
|
|
688
|
-
return [4 /*yield*/, store.delete(key)];
|
|
689
|
-
case 13:
|
|
690
|
-
_l.sent();
|
|
691
|
-
_l.label = 14;
|
|
692
|
-
case 14: return [3 /*break*/, 16];
|
|
693
|
-
case 15:
|
|
694
|
-
_k = true;
|
|
695
|
-
return [7 /*endfinally*/];
|
|
696
|
-
case 16: return [3 /*break*/, 6];
|
|
697
|
-
case 17: return [3 /*break*/, 24];
|
|
698
|
-
case 18:
|
|
699
|
-
e_5_1 = _l.sent();
|
|
700
|
-
e_5 = { error: e_5_1 };
|
|
701
|
-
return [3 /*break*/, 24];
|
|
702
|
-
case 19:
|
|
703
|
-
_l.trys.push([19, , 22, 23]);
|
|
704
|
-
if (!(!_k && !_d && (_e = items_2.return))) return [3 /*break*/, 21];
|
|
705
|
-
return [4 /*yield*/, _e.call(items_2)];
|
|
706
|
-
case 20:
|
|
707
|
-
_l.sent();
|
|
708
|
-
_l.label = 21;
|
|
709
|
-
case 21: return [3 /*break*/, 23];
|
|
710
|
-
case 22:
|
|
711
|
-
if (e_5) throw e_5.error;
|
|
712
|
-
return [7 /*endfinally*/];
|
|
713
|
-
case 23: return [7 /*endfinally*/];
|
|
714
|
-
case 24: return [3 /*break*/, 26];
|
|
715
|
-
case 25:
|
|
716
|
-
_g = true;
|
|
717
|
-
return [7 /*endfinally*/];
|
|
718
|
-
case 26: return [3 /*break*/, 2];
|
|
719
|
-
case 27: return [3 /*break*/, 34];
|
|
720
|
-
case 28:
|
|
721
|
-
e_4_1 = _l.sent();
|
|
722
|
-
e_4 = { error: e_4_1 };
|
|
723
|
-
return [3 /*break*/, 34];
|
|
724
|
-
case 29:
|
|
725
|
-
_l.trys.push([29, , 32, 33]);
|
|
726
|
-
if (!(!_g && !_a && (_b = _h.return))) return [3 /*break*/, 31];
|
|
727
|
-
return [4 /*yield*/, _b.call(_h)];
|
|
728
|
-
case 30:
|
|
729
|
-
_l.sent();
|
|
730
|
-
_l.label = 31;
|
|
731
|
-
case 31: return [3 /*break*/, 33];
|
|
732
|
-
case 32:
|
|
733
|
-
if (e_4) throw e_4.error;
|
|
734
|
-
return [7 /*endfinally*/];
|
|
735
|
-
case 33: return [7 /*endfinally*/];
|
|
736
|
-
case 34: return [2 /*return*/];
|
|
297
|
+
const tx = this.db.transaction([...connectionStoreNames], 'readwrite');
|
|
298
|
+
for await (const deleteItem of deleteQueue) {
|
|
299
|
+
const { storeName, items } = deleteItem;
|
|
300
|
+
const store = tx.objectStore(storeName);
|
|
301
|
+
for await (const item of items) {
|
|
302
|
+
if (item) {
|
|
303
|
+
let key;
|
|
304
|
+
if (typeof item === 'object') {
|
|
305
|
+
const keyValues = this.getIndexKeyValuesFromModel(item);
|
|
306
|
+
key = await store
|
|
307
|
+
.index('byPk')
|
|
308
|
+
.getKey(this.canonicalKeyPath(keyValues));
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
const itemKey = item.toString();
|
|
312
|
+
key = await store.index('byPk').getKey(itemKey);
|
|
313
|
+
}
|
|
314
|
+
if (key !== undefined) {
|
|
315
|
+
await store.delete(key);
|
|
316
|
+
}
|
|
737
317
|
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
741
321
|
//#region platform-specific helper methods
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
return __generator(this, function (_a) {
|
|
746
|
-
switch (_a.label) {
|
|
747
|
-
case 0: return [4 /*yield*/, (0, util_1.isPrivateMode)().then(function (isPrivate) {
|
|
748
|
-
return isPrivate;
|
|
749
|
-
})];
|
|
750
|
-
case 1:
|
|
751
|
-
isPrivate = _a.sent();
|
|
752
|
-
if (isPrivate) {
|
|
753
|
-
logger.error("IndexedDB not supported in this browser's private mode");
|
|
754
|
-
return [2 /*return*/, Promise.reject("IndexedDB not supported in this browser's private mode")];
|
|
755
|
-
}
|
|
756
|
-
else {
|
|
757
|
-
return [2 /*return*/, Promise.resolve()];
|
|
758
|
-
}
|
|
759
|
-
return [2 /*return*/];
|
|
760
|
-
}
|
|
761
|
-
});
|
|
322
|
+
async checkPrivate() {
|
|
323
|
+
const isPrivate = await (0, util_1.isPrivateMode)().then(isPrivate => {
|
|
324
|
+
return isPrivate;
|
|
762
325
|
});
|
|
763
|
-
|
|
326
|
+
if (isPrivate) {
|
|
327
|
+
logger.error("IndexedDB not supported in this browser's private mode");
|
|
328
|
+
return Promise.reject("IndexedDB not supported in this browser's private mode");
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
return Promise.resolve();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
764
334
|
/**
|
|
765
335
|
* Whether the browser's implementation of IndexedDB is coercing single-field
|
|
766
336
|
* indexes to a scalar key.
|
|
@@ -771,62 +341,35 @@ var IndexedDBAdapter = /** @class */ (function (_super) {
|
|
|
771
341
|
* See PR description for reference:
|
|
772
342
|
* https://github.com/aws-amplify/amplify-js/pull/10527
|
|
773
343
|
*/
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
case 1:
|
|
783
|
-
_a.safariCompatabilityMode = _b.sent();
|
|
784
|
-
if (this.safariCompatabilityMode === true) {
|
|
785
|
-
logger.debug('IndexedDB Adapter is running in Safari Compatability Mode');
|
|
786
|
-
}
|
|
787
|
-
return [2 /*return*/];
|
|
788
|
-
}
|
|
789
|
-
});
|
|
790
|
-
});
|
|
791
|
-
};
|
|
792
|
-
IndexedDBAdapter.prototype.getNamespaceAndModelFromStorename = function (storeName) {
|
|
793
|
-
var _a = __read(storeName.split('_')), namespaceName = _a[0], modelNameArr = _a.slice(1);
|
|
344
|
+
async setSafariCompatabilityMode() {
|
|
345
|
+
this.safariCompatabilityMode = await (0, util_1.isSafariCompatabilityMode)();
|
|
346
|
+
if (this.safariCompatabilityMode === true) {
|
|
347
|
+
logger.debug('IndexedDB Adapter is running in Safari Compatability Mode');
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
getNamespaceAndModelFromStorename(storeName) {
|
|
351
|
+
const [namespaceName, ...modelNameArr] = storeName.split('_');
|
|
794
352
|
return {
|
|
795
|
-
namespaceName
|
|
353
|
+
namespaceName,
|
|
796
354
|
modelName: modelNameArr.join('_'),
|
|
797
355
|
};
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
|
|
356
|
+
}
|
|
357
|
+
createObjectStoreForModel(db, namespaceName, storeName, modelName) {
|
|
358
|
+
const store = db.createObjectStore(storeName, {
|
|
801
359
|
autoIncrement: true,
|
|
802
360
|
});
|
|
803
|
-
|
|
804
|
-
indexes.forEach(
|
|
805
|
-
var _b = __read(_a, 3), idxName = _b[0], keyPath = _b[1], options = _b[2];
|
|
361
|
+
const { indexes } = this.schema.namespaces[namespaceName].relationships[modelName];
|
|
362
|
+
indexes.forEach(([idxName, keyPath, options]) => {
|
|
806
363
|
store.createIndex(idxName, keyPath, options);
|
|
807
364
|
});
|
|
808
365
|
return store;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
return
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
}
|
|
817
|
-
});
|
|
818
|
-
});
|
|
819
|
-
};
|
|
820
|
-
IndexedDBAdapter.prototype.getAll = function (storeName) {
|
|
821
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
822
|
-
return __generator(this, function (_a) {
|
|
823
|
-
switch (_a.label) {
|
|
824
|
-
case 0: return [4 /*yield*/, this.db.getAll(storeName)];
|
|
825
|
-
case 1: return [2 /*return*/, _a.sent()];
|
|
826
|
-
}
|
|
827
|
-
});
|
|
828
|
-
});
|
|
829
|
-
};
|
|
366
|
+
}
|
|
367
|
+
async getByKey(storeName, keyValue) {
|
|
368
|
+
return await this._get(storeName, keyValue);
|
|
369
|
+
}
|
|
370
|
+
async getAll(storeName) {
|
|
371
|
+
return await this.db.getAll(storeName);
|
|
372
|
+
}
|
|
830
373
|
/**
|
|
831
374
|
* Tries to generate an index fetcher for the given predicates. Assumes
|
|
832
375
|
* that the given predicate conditions are contained by an AND group and
|
|
@@ -836,295 +379,191 @@ var IndexedDBAdapter = /** @class */ (function (_super) {
|
|
|
836
379
|
* @param predicates The predicates to try to AND together.
|
|
837
380
|
* @param transaction
|
|
838
381
|
*/
|
|
839
|
-
|
|
840
|
-
var e_6, _a, e_7, _b;
|
|
841
|
-
var _this = this;
|
|
382
|
+
matchingIndexQueries(storeName, predicates, transaction) {
|
|
842
383
|
// could be expanded later to include `exec()` and a `cardinality` estimate?
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
var predicate = predicates_1_1.value;
|
|
848
|
-
predicateIndex.set(String(predicate.field), predicate);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
852
|
-
finally {
|
|
853
|
-
try {
|
|
854
|
-
if (predicates_1_1 && !predicates_1_1.done && (_a = predicates_1.return)) _a.call(predicates_1);
|
|
855
|
-
}
|
|
856
|
-
finally { if (e_6) throw e_6.error; }
|
|
384
|
+
const queries = [];
|
|
385
|
+
const predicateIndex = new Map();
|
|
386
|
+
for (const predicate of predicates) {
|
|
387
|
+
predicateIndex.set(String(predicate.field), predicate);
|
|
857
388
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
var p = predicateIndex.get(field);
|
|
868
|
-
if (p && p.operand !== null && p.operand !== undefined) {
|
|
869
|
-
matchingPredicateValues.push(p.operand);
|
|
870
|
-
}
|
|
871
|
-
else {
|
|
872
|
-
break;
|
|
873
|
-
}
|
|
389
|
+
const store = transaction.objectStore(storeName);
|
|
390
|
+
for (const name of store.indexNames) {
|
|
391
|
+
const idx = store.index(name);
|
|
392
|
+
const keypath = Array.isArray(idx.keyPath) ? idx.keyPath : [idx.keyPath];
|
|
393
|
+
const matchingPredicateValues = [];
|
|
394
|
+
for (const field of keypath) {
|
|
395
|
+
const p = predicateIndex.get(field);
|
|
396
|
+
if (p && p.operand !== null && p.operand !== undefined) {
|
|
397
|
+
matchingPredicateValues.push(p.operand);
|
|
874
398
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
finally {
|
|
878
|
-
try {
|
|
879
|
-
if (keypath_1_1 && !keypath_1_1.done && (_e = keypath_1.return)) _e.call(keypath_1);
|
|
399
|
+
else {
|
|
400
|
+
break;
|
|
880
401
|
}
|
|
881
|
-
finally { if (e_8) throw e_8.error; }
|
|
882
402
|
}
|
|
883
403
|
// if we have a matching predicate field for each component of this index,
|
|
884
404
|
// we can build a query for it. otherwise, we can't.
|
|
885
405
|
if (matchingPredicateValues.length === keypath.length) {
|
|
886
406
|
// re-create a transaction, because the transaction used to fetch the
|
|
887
407
|
// indexes may no longer be active.
|
|
888
|
-
queries.push(
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
.getAll(_this.canonicalKeyPath(matchingPredicateValues));
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
};
|
|
897
|
-
try {
|
|
898
|
-
for (var _c = __values(store.indexNames), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
899
|
-
var name_1 = _d.value;
|
|
900
|
-
_loop_3(name_1);
|
|
408
|
+
queries.push(() => this.db
|
|
409
|
+
.transaction(storeName)
|
|
410
|
+
.objectStore(storeName)
|
|
411
|
+
.index(name)
|
|
412
|
+
.getAll(this.canonicalKeyPath(matchingPredicateValues)));
|
|
901
413
|
}
|
|
902
414
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
415
|
+
return queries;
|
|
416
|
+
}
|
|
417
|
+
async baseQueryIndex(storeName, predicates, transaction) {
|
|
418
|
+
let { predicates: predicateObjs, type } = predicates;
|
|
419
|
+
// the predicate objects we care about tend to be nested at least
|
|
420
|
+
// one level down: `{and: {or: {and: { <the predicates we want> }}}}`
|
|
421
|
+
// so, we unpack and/or groups until we find a group with more than 1
|
|
422
|
+
// child OR a child that is not a group (and is therefore a predicate "object").
|
|
423
|
+
while (predicateObjs.length === 1 &&
|
|
424
|
+
(0, types_1.isPredicateGroup)(predicateObjs[0]) &&
|
|
425
|
+
predicateObjs[0].type !== 'not') {
|
|
426
|
+
type = predicateObjs[0].type;
|
|
427
|
+
predicateObjs = predicateObjs[0].predicates;
|
|
428
|
+
}
|
|
429
|
+
const fieldPredicates = predicateObjs.filter(p => (0, types_1.isPredicateObj)(p) && p.operator === 'eq');
|
|
430
|
+
// several sub-queries could occur here. explicitly start a txn here to avoid
|
|
431
|
+
// opening/closing multiple txns.
|
|
432
|
+
const txn = transaction || this.db.transaction(storeName);
|
|
433
|
+
let result = {};
|
|
434
|
+
// `or` conditions, if usable, need to generate multiple queries. this is unlike
|
|
435
|
+
// `and` conditions, which should just be combined.
|
|
436
|
+
if (type === 'or') {
|
|
437
|
+
/**
|
|
438
|
+
* Base queries for each child group.
|
|
439
|
+
*
|
|
440
|
+
* For each child group, if it's an AND condition that results in a single
|
|
441
|
+
* subordinate "base query", we can use it. if it's any more complicated
|
|
442
|
+
* than that, it's not a simple join condition we want to use.
|
|
443
|
+
*/
|
|
444
|
+
const groupQueries = await Promise.all(predicateObjs
|
|
445
|
+
.filter(o => (0, types_1.isPredicateGroup)(o) && o.type === 'and')
|
|
446
|
+
.map(o => this.baseQueryIndex(storeName, o, txn))).then(queries => queries
|
|
447
|
+
.filter(q => q.indexedQueries.length === 1)
|
|
448
|
+
.map(i => i.indexedQueries));
|
|
449
|
+
/**
|
|
450
|
+
* Base queries for each simple child "object" (field condition).
|
|
451
|
+
*/
|
|
452
|
+
const objectQueries = predicateObjs
|
|
453
|
+
.filter(o => (0, types_1.isPredicateObj)(o))
|
|
454
|
+
.map(o => this.matchingIndexQueries(storeName, [o], txn));
|
|
455
|
+
const indexedQueries = [...groupQueries, ...objectQueries]
|
|
456
|
+
.map(q => q[0])
|
|
457
|
+
.filter(i => i);
|
|
458
|
+
// if, after hunting for base queries, we don't have exactly 1 base query
|
|
459
|
+
// for each child group + object, stop trying to optimize. we're not dealing
|
|
460
|
+
// with a simple query that fits the intended optimization path.
|
|
461
|
+
if (predicateObjs.length > indexedQueries.length) {
|
|
462
|
+
result = {
|
|
463
|
+
groupType: null,
|
|
464
|
+
indexedQueries: [],
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
result = {
|
|
469
|
+
groupType: 'or',
|
|
470
|
+
indexedQueries,
|
|
471
|
+
};
|
|
907
472
|
}
|
|
908
|
-
finally { if (e_7) throw e_7.error; }
|
|
909
473
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
result = {
|
|
957
|
-
groupType: null,
|
|
958
|
-
indexedQueries: [],
|
|
959
|
-
};
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
962
|
-
result = {
|
|
963
|
-
groupType: 'or',
|
|
964
|
-
indexedQueries: indexedQueries,
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
return [3 /*break*/, 3];
|
|
968
|
-
case 2:
|
|
969
|
-
if (type === 'and') {
|
|
970
|
-
// our potential indexes or lacks thereof.
|
|
971
|
-
// note that we're only optimizing for `eq` right now.
|
|
972
|
-
result = {
|
|
973
|
-
groupType: type,
|
|
974
|
-
indexedQueries: this.matchingIndexQueries(storeName, fieldPredicates, txn),
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
|
-
else {
|
|
978
|
-
result = {
|
|
979
|
-
groupType: null,
|
|
980
|
-
indexedQueries: [],
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
_a.label = 3;
|
|
984
|
-
case 3:
|
|
985
|
-
if (!!transaction) return [3 /*break*/, 5];
|
|
986
|
-
return [4 /*yield*/, txn.done];
|
|
987
|
-
case 4:
|
|
988
|
-
_a.sent();
|
|
989
|
-
_a.label = 5;
|
|
990
|
-
case 5: return [2 /*return*/, result];
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
|
-
});
|
|
994
|
-
};
|
|
995
|
-
IndexedDBAdapter.prototype.filterOnPredicate = function (storeName, predicates) {
|
|
996
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
997
|
-
var predicateObjs, type, _a, groupType, indexedQueries, candidateResults, distinctResults, indexedQueries_1, indexedQueries_1_1, query, resultGroup, resultGroup_1, resultGroup_1_1, item, distinctificationString, e_9_1, filtered;
|
|
998
|
-
var e_9, _b, e_10, _c;
|
|
999
|
-
return __generator(this, function (_d) {
|
|
1000
|
-
switch (_d.label) {
|
|
1001
|
-
case 0:
|
|
1002
|
-
predicateObjs = predicates.predicates, type = predicates.type;
|
|
1003
|
-
return [4 /*yield*/, this.baseQueryIndex(storeName, predicates)];
|
|
1004
|
-
case 1:
|
|
1005
|
-
_a = _d.sent(), groupType = _a.groupType, indexedQueries = _a.indexedQueries;
|
|
1006
|
-
if (!(groupType === 'and' && indexedQueries.length > 0)) return [3 /*break*/, 3];
|
|
1007
|
-
return [4 /*yield*/, indexedQueries[0]()];
|
|
1008
|
-
case 2:
|
|
1009
|
-
// each condition must be satsified, we can form a base set with any
|
|
1010
|
-
// ONE of those conditions and then filter.
|
|
1011
|
-
candidateResults = _d.sent();
|
|
1012
|
-
return [3 /*break*/, 14];
|
|
1013
|
-
case 3:
|
|
1014
|
-
if (!(groupType === 'or' &&
|
|
1015
|
-
indexedQueries.length > 0 &&
|
|
1016
|
-
indexedQueries.length <= MULTI_OR_CONDITION_SCAN_BREAKPOINT)) return [3 /*break*/, 12];
|
|
1017
|
-
distinctResults = new Map();
|
|
1018
|
-
_d.label = 4;
|
|
1019
|
-
case 4:
|
|
1020
|
-
_d.trys.push([4, 9, 10, 11]);
|
|
1021
|
-
indexedQueries_1 = __values(indexedQueries), indexedQueries_1_1 = indexedQueries_1.next();
|
|
1022
|
-
_d.label = 5;
|
|
1023
|
-
case 5:
|
|
1024
|
-
if (!!indexedQueries_1_1.done) return [3 /*break*/, 8];
|
|
1025
|
-
query = indexedQueries_1_1.value;
|
|
1026
|
-
return [4 /*yield*/, query()];
|
|
1027
|
-
case 6:
|
|
1028
|
-
resultGroup = _d.sent();
|
|
1029
|
-
try {
|
|
1030
|
-
for (resultGroup_1 = (e_10 = void 0, __values(resultGroup)), resultGroup_1_1 = resultGroup_1.next(); !resultGroup_1_1.done; resultGroup_1_1 = resultGroup_1.next()) {
|
|
1031
|
-
item = resultGroup_1_1.value;
|
|
1032
|
-
distinctificationString = JSON.stringify(item);
|
|
1033
|
-
distinctResults.set(distinctificationString, item);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
1037
|
-
finally {
|
|
1038
|
-
try {
|
|
1039
|
-
if (resultGroup_1_1 && !resultGroup_1_1.done && (_c = resultGroup_1.return)) _c.call(resultGroup_1);
|
|
1040
|
-
}
|
|
1041
|
-
finally { if (e_10) throw e_10.error; }
|
|
1042
|
-
}
|
|
1043
|
-
_d.label = 7;
|
|
1044
|
-
case 7:
|
|
1045
|
-
indexedQueries_1_1 = indexedQueries_1.next();
|
|
1046
|
-
return [3 /*break*/, 5];
|
|
1047
|
-
case 8: return [3 /*break*/, 11];
|
|
1048
|
-
case 9:
|
|
1049
|
-
e_9_1 = _d.sent();
|
|
1050
|
-
e_9 = { error: e_9_1 };
|
|
1051
|
-
return [3 /*break*/, 11];
|
|
1052
|
-
case 10:
|
|
1053
|
-
try {
|
|
1054
|
-
if (indexedQueries_1_1 && !indexedQueries_1_1.done && (_b = indexedQueries_1.return)) _b.call(indexedQueries_1);
|
|
1055
|
-
}
|
|
1056
|
-
finally { if (e_9) throw e_9.error; }
|
|
1057
|
-
return [7 /*endfinally*/];
|
|
1058
|
-
case 11:
|
|
1059
|
-
// we could conceivably check for special conditions and return early here.
|
|
1060
|
-
// but, this is simpler and has not yet had a measurable performance impact.
|
|
1061
|
-
candidateResults = Array.from(distinctResults.values());
|
|
1062
|
-
return [3 /*break*/, 14];
|
|
1063
|
-
case 12: return [4 /*yield*/, this.getAll(storeName)];
|
|
1064
|
-
case 13:
|
|
1065
|
-
// nothing intelligent we can do with `not` groups unless or until we start
|
|
1066
|
-
// smashing comparison operators against indexes -- at which point we could
|
|
1067
|
-
// perform some reversal here.
|
|
1068
|
-
candidateResults = (_d.sent());
|
|
1069
|
-
_d.label = 14;
|
|
1070
|
-
case 14:
|
|
1071
|
-
filtered = predicateObjs
|
|
1072
|
-
? candidateResults.filter(function (m) { return (0, util_1.validatePredicate)(m, type, predicateObjs); })
|
|
1073
|
-
: candidateResults;
|
|
1074
|
-
return [2 /*return*/, filtered];
|
|
474
|
+
else if (type === 'and') {
|
|
475
|
+
// our potential indexes or lacks thereof.
|
|
476
|
+
// note that we're only optimizing for `eq` right now.
|
|
477
|
+
result = {
|
|
478
|
+
groupType: type,
|
|
479
|
+
indexedQueries: this.matchingIndexQueries(storeName, fieldPredicates, txn),
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
result = {
|
|
484
|
+
groupType: null,
|
|
485
|
+
indexedQueries: [],
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
// Explicitly wait for txns from index queries to complete before proceding.
|
|
489
|
+
// This helps ensure IndexedDB is in a stable, ready state. Else, subseqeuent
|
|
490
|
+
// qeuries can sometimes appear to deadlock (at least in FakeIndexedDB).
|
|
491
|
+
// (Unless we were *given* the transaction -- we'll assume the parent handles it.)
|
|
492
|
+
if (!transaction)
|
|
493
|
+
await txn.done;
|
|
494
|
+
return result;
|
|
495
|
+
}
|
|
496
|
+
async filterOnPredicate(storeName, predicates) {
|
|
497
|
+
const { predicates: predicateObjs, type } = predicates;
|
|
498
|
+
const { groupType, indexedQueries } = await this.baseQueryIndex(storeName, predicates);
|
|
499
|
+
// where we'll accumulate candidate results, which will be filtered at the end.
|
|
500
|
+
let candidateResults;
|
|
501
|
+
// semi-naive implementation:
|
|
502
|
+
if (groupType === 'and' && indexedQueries.length > 0) {
|
|
503
|
+
// each condition must be satsified, we can form a base set with any
|
|
504
|
+
// ONE of those conditions and then filter.
|
|
505
|
+
candidateResults = await indexedQueries[0]();
|
|
506
|
+
}
|
|
507
|
+
else if (groupType === 'or' &&
|
|
508
|
+
indexedQueries.length > 0 &&
|
|
509
|
+
indexedQueries.length <= MULTI_OR_CONDITION_SCAN_BREAKPOINT) {
|
|
510
|
+
// NOTE: each condition implies a potentially distinct set. we only benefit
|
|
511
|
+
// from using indexes here if EVERY condition uses an index. if any one
|
|
512
|
+
// index requires a table scan, we gain nothing from the indexes.
|
|
513
|
+
// NOTE: results must be DISTINCT-ified if we leverage indexes.
|
|
514
|
+
const distinctResults = new Map();
|
|
515
|
+
for (const query of indexedQueries) {
|
|
516
|
+
const resultGroup = await query();
|
|
517
|
+
for (const item of resultGroup) {
|
|
518
|
+
const distinctificationString = JSON.stringify(item);
|
|
519
|
+
distinctResults.set(distinctificationString, item);
|
|
1075
520
|
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
521
|
+
}
|
|
522
|
+
// we could conceivably check for special conditions and return early here.
|
|
523
|
+
// but, this is simpler and has not yet had a measurable performance impact.
|
|
524
|
+
candidateResults = Array.from(distinctResults.values());
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// nothing intelligent we can do with `not` groups unless or until we start
|
|
528
|
+
// smashing comparison operators against indexes -- at which point we could
|
|
529
|
+
// perform some reversal here.
|
|
530
|
+
candidateResults = await this.getAll(storeName);
|
|
531
|
+
}
|
|
532
|
+
const filtered = predicateObjs
|
|
533
|
+
? candidateResults.filter(m => (0, util_1.validatePredicate)(m, type, predicateObjs))
|
|
534
|
+
: candidateResults;
|
|
535
|
+
return filtered;
|
|
536
|
+
}
|
|
537
|
+
inMemoryPagination(records, pagination) {
|
|
1080
538
|
return (0, util_1.inMemoryPagination)(records, pagination);
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
_c.sent();
|
|
1101
|
-
_c.label = 3;
|
|
1102
|
-
case 3:
|
|
1103
|
-
pageResults = [];
|
|
1104
|
-
hasLimit = typeof limit === 'number' && limit > 0;
|
|
1105
|
-
_c.label = 4;
|
|
1106
|
-
case 4:
|
|
1107
|
-
if (!(cursor && cursor.value)) return [3 /*break*/, 6];
|
|
1108
|
-
pageResults.push(cursor.value);
|
|
1109
|
-
if (hasLimit && pageResults.length === limit) {
|
|
1110
|
-
return [3 /*break*/, 6];
|
|
1111
|
-
}
|
|
1112
|
-
return [4 /*yield*/, cursor.continue()];
|
|
1113
|
-
case 5:
|
|
1114
|
-
cursor = _c.sent();
|
|
1115
|
-
return [3 /*break*/, 4];
|
|
1116
|
-
case 6:
|
|
1117
|
-
result = pageResults;
|
|
1118
|
-
return [3 /*break*/, 9];
|
|
1119
|
-
case 7: return [4 /*yield*/, this.db.getAll(storeName)];
|
|
1120
|
-
case 8:
|
|
1121
|
-
result = (_c.sent());
|
|
1122
|
-
_c.label = 9;
|
|
1123
|
-
case 9: return [2 /*return*/, result];
|
|
539
|
+
}
|
|
540
|
+
async enginePagination(storeName, pagination) {
|
|
541
|
+
let result;
|
|
542
|
+
if (pagination) {
|
|
543
|
+
const { page = 0, limit = 0 } = pagination;
|
|
544
|
+
const initialRecord = Math.max(0, page * limit) || 0;
|
|
545
|
+
let cursor = await this.db
|
|
546
|
+
.transaction(storeName)
|
|
547
|
+
.objectStore(storeName)
|
|
548
|
+
.openCursor();
|
|
549
|
+
if (cursor && initialRecord > 0) {
|
|
550
|
+
await cursor.advance(initialRecord);
|
|
551
|
+
}
|
|
552
|
+
const pageResults = [];
|
|
553
|
+
const hasLimit = typeof limit === 'number' && limit > 0;
|
|
554
|
+
while (cursor && cursor.value) {
|
|
555
|
+
pageResults.push(cursor.value);
|
|
556
|
+
if (hasLimit && pageResults.length === limit) {
|
|
557
|
+
break;
|
|
1124
558
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
559
|
+
cursor = await cursor.continue();
|
|
560
|
+
}
|
|
561
|
+
result = pageResults;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
result = await this.db.getAll(storeName);
|
|
565
|
+
}
|
|
566
|
+
return result;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
1130
569
|
exports.default = new IndexedDBAdapter();
|