@react-native-firebase/app 20.0.0 → 20.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +1 -1
- package/ios/RNFBApp/RNFBVersion.m +1 -1
- package/lib/common/index.js +2 -0
- package/lib/index.d.ts +1 -0
- package/lib/internal/RNFBNativeEventEmitter.js +31 -6
- package/lib/internal/nativeModule.android.js +2 -0
- package/lib/internal/nativeModule.ios.js +2 -0
- package/lib/internal/nativeModule.js +4 -0
- package/lib/internal/nativeModuleAndroidIos.js +45 -0
- package/lib/internal/nativeModuleWeb.js +48 -0
- package/lib/internal/registry/app.js +2 -1
- package/lib/internal/registry/nativeModule.js +11 -15
- package/lib/internal/web/RNFBAppModule.js +266 -0
- package/lib/internal/web/firebaseApp.js +3 -0
- package/lib/internal/web/firebaseAppCheck.js +6 -0
- package/lib/internal/web/firebaseAuth.js +4 -0
- package/lib/internal/web/firebaseDatabase.js +4 -0
- package/lib/internal/web/firebaseFirestore.js +4 -0
- package/lib/internal/web/firebaseFunctions.js +4 -0
- package/lib/internal/web/firebaseInstallations.js +6 -0
- package/lib/internal/web/firebaseRemoteConfig.js +6 -0
- package/lib/internal/web/firebaseStorage.js +4 -0
- package/lib/internal/web/memidb/FDBCursor.js +503 -0
- package/lib/internal/web/memidb/FDBCursorWithValue.js +11 -0
- package/lib/internal/web/memidb/FDBDatabase.js +172 -0
- package/lib/internal/web/memidb/FDBFactory.js +256 -0
- package/lib/internal/web/memidb/FDBIndex.js +187 -0
- package/lib/internal/web/memidb/FDBKeyRange.js +71 -0
- package/lib/internal/web/memidb/FDBObjectStore.js +411 -0
- package/lib/internal/web/memidb/FDBOpenDBRequest.js +9 -0
- package/lib/internal/web/memidb/FDBRequest.js +33 -0
- package/lib/internal/web/memidb/FDBTransaction.js +216 -0
- package/lib/internal/web/memidb/FDBVersionChangeEvent.js +12 -0
- package/lib/internal/web/memidb/LICENSE +208 -0
- package/lib/internal/web/memidb/index.js +39 -0
- package/lib/internal/web/memidb/lib/Database.js +32 -0
- package/lib/internal/web/memidb/lib/FakeDOMStringList.js +72 -0
- package/lib/internal/web/memidb/lib/FakeEvent.js +38 -0
- package/lib/internal/web/memidb/lib/FakeEventTarget.js +110 -0
- package/lib/internal/web/memidb/lib/Index.js +157 -0
- package/lib/internal/web/memidb/lib/KeyGenerator.js +22 -0
- package/lib/internal/web/memidb/lib/ObjectStore.js +172 -0
- package/lib/internal/web/memidb/lib/RecordStore.js +141 -0
- package/lib/internal/web/memidb/lib/binarySearch.js +78 -0
- package/lib/internal/web/memidb/lib/canInjectKey.js +25 -0
- package/lib/internal/web/memidb/lib/cmp.js +77 -0
- package/lib/internal/web/memidb/lib/enforceRange.js +13 -0
- package/lib/internal/web/memidb/lib/errors.js +69 -0
- package/lib/internal/web/memidb/lib/extractKey.js +39 -0
- package/lib/internal/web/memidb/lib/scheduling.js +30 -0
- package/lib/internal/web/memidb/lib/types.js +1 -0
- package/lib/internal/web/memidb/lib/validateKeyPath.js +54 -0
- package/lib/internal/web/memidb/lib/valueToKey.js +62 -0
- package/lib/internal/web/memidb/lib/valueToKeyRange.js +19 -0
- package/lib/internal/web/structuredClone/index.js +222 -0
- package/lib/internal/web/utils.js +35 -0
- package/lib/utils/UtilsStatics.js +3 -2
- package/lib/version.js +1 -1
- package/package.json +9 -8
@@ -0,0 +1,411 @@
|
|
1
|
+
import FDBCursor from './FDBCursor.js';
|
2
|
+
import FDBCursorWithValue from './FDBCursorWithValue.js';
|
3
|
+
import FDBIndex from './FDBIndex.js';
|
4
|
+
import FDBKeyRange from './FDBKeyRange.js';
|
5
|
+
import FDBRequest from './FDBRequest.js';
|
6
|
+
import canInjectKey from './lib/canInjectKey.js';
|
7
|
+
import enforceRange from './lib/enforceRange.js';
|
8
|
+
import {
|
9
|
+
ConstraintError,
|
10
|
+
DataError,
|
11
|
+
InvalidAccessError,
|
12
|
+
InvalidStateError,
|
13
|
+
NotFoundError,
|
14
|
+
ReadOnlyError,
|
15
|
+
TransactionInactiveError,
|
16
|
+
} from './lib/errors.js';
|
17
|
+
import extractKey from './lib/extractKey.js';
|
18
|
+
import FakeDOMStringList from './lib/FakeDOMStringList.js';
|
19
|
+
import Index from './lib/Index.js';
|
20
|
+
import validateKeyPath from './lib/validateKeyPath.js';
|
21
|
+
import valueToKey from './lib/valueToKey.js';
|
22
|
+
import valueToKeyRange from './lib/valueToKeyRange.js';
|
23
|
+
const confirmActiveTransaction = objectStore => {
|
24
|
+
if (objectStore._rawObjectStore.deleted) {
|
25
|
+
throw new InvalidStateError();
|
26
|
+
}
|
27
|
+
if (objectStore.transaction._state !== 'active') {
|
28
|
+
throw new TransactionInactiveError();
|
29
|
+
}
|
30
|
+
};
|
31
|
+
const buildRecordAddPut = (objectStore, value, key) => {
|
32
|
+
confirmActiveTransaction(objectStore);
|
33
|
+
if (objectStore.transaction.mode === 'readonly') {
|
34
|
+
throw new ReadOnlyError();
|
35
|
+
}
|
36
|
+
if (objectStore.keyPath !== null) {
|
37
|
+
if (key !== undefined) {
|
38
|
+
throw new DataError();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
const clone = structuredClone(value);
|
42
|
+
if (objectStore.keyPath !== null) {
|
43
|
+
const tempKey = extractKey(objectStore.keyPath, clone);
|
44
|
+
if (tempKey !== undefined) {
|
45
|
+
valueToKey(tempKey);
|
46
|
+
} else {
|
47
|
+
if (!objectStore._rawObjectStore.keyGenerator) {
|
48
|
+
throw new DataError();
|
49
|
+
} else if (!canInjectKey(objectStore.keyPath, clone)) {
|
50
|
+
throw new DataError();
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
if (
|
55
|
+
objectStore.keyPath === null &&
|
56
|
+
objectStore._rawObjectStore.keyGenerator === null &&
|
57
|
+
key === undefined
|
58
|
+
) {
|
59
|
+
throw new DataError();
|
60
|
+
}
|
61
|
+
if (key !== undefined) {
|
62
|
+
key = valueToKey(key);
|
63
|
+
}
|
64
|
+
return {
|
65
|
+
key,
|
66
|
+
value: clone,
|
67
|
+
};
|
68
|
+
};
|
69
|
+
|
70
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
|
71
|
+
class FDBObjectStore {
|
72
|
+
_indexesCache = new Map();
|
73
|
+
constructor(transaction, rawObjectStore) {
|
74
|
+
this._rawObjectStore = rawObjectStore;
|
75
|
+
this._name = rawObjectStore.name;
|
76
|
+
this.keyPath = rawObjectStore.keyPath;
|
77
|
+
this.autoIncrement = rawObjectStore.autoIncrement;
|
78
|
+
this.transaction = transaction;
|
79
|
+
this.indexNames = new FakeDOMStringList(...Array.from(rawObjectStore.rawIndexes.keys()).sort());
|
80
|
+
}
|
81
|
+
get name() {
|
82
|
+
return this._name;
|
83
|
+
}
|
84
|
+
|
85
|
+
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
|
86
|
+
set name(name) {
|
87
|
+
const transaction = this.transaction;
|
88
|
+
if (!transaction.db._runningVersionchangeTransaction) {
|
89
|
+
throw new InvalidStateError();
|
90
|
+
}
|
91
|
+
confirmActiveTransaction(this);
|
92
|
+
name = String(name);
|
93
|
+
if (name === this._name) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
if (this._rawObjectStore.rawDatabase.rawObjectStores.has(name)) {
|
97
|
+
throw new ConstraintError();
|
98
|
+
}
|
99
|
+
const oldName = this._name;
|
100
|
+
const oldObjectStoreNames = [...transaction.db.objectStoreNames];
|
101
|
+
this._name = name;
|
102
|
+
this._rawObjectStore.name = name;
|
103
|
+
this.transaction._objectStoresCache.delete(oldName);
|
104
|
+
this.transaction._objectStoresCache.set(name, this);
|
105
|
+
this._rawObjectStore.rawDatabase.rawObjectStores.delete(oldName);
|
106
|
+
this._rawObjectStore.rawDatabase.rawObjectStores.set(name, this._rawObjectStore);
|
107
|
+
transaction.db.objectStoreNames = new FakeDOMStringList(
|
108
|
+
...Array.from(this._rawObjectStore.rawDatabase.rawObjectStores.keys())
|
109
|
+
.filter(objectStoreName => {
|
110
|
+
const objectStore = this._rawObjectStore.rawDatabase.rawObjectStores.get(objectStoreName);
|
111
|
+
return objectStore && !objectStore.deleted;
|
112
|
+
})
|
113
|
+
.sort(),
|
114
|
+
);
|
115
|
+
const oldScope = new Set(transaction._scope);
|
116
|
+
const oldTransactionObjectStoreNames = [...transaction.objectStoreNames];
|
117
|
+
this.transaction._scope.delete(oldName);
|
118
|
+
transaction._scope.add(name);
|
119
|
+
transaction.objectStoreNames = new FakeDOMStringList(...Array.from(transaction._scope).sort());
|
120
|
+
transaction._rollbackLog.push(() => {
|
121
|
+
this._name = oldName;
|
122
|
+
this._rawObjectStore.name = oldName;
|
123
|
+
this.transaction._objectStoresCache.delete(name);
|
124
|
+
this.transaction._objectStoresCache.set(oldName, this);
|
125
|
+
this._rawObjectStore.rawDatabase.rawObjectStores.delete(name);
|
126
|
+
this._rawObjectStore.rawDatabase.rawObjectStores.set(oldName, this._rawObjectStore);
|
127
|
+
transaction.db.objectStoreNames = new FakeDOMStringList(...oldObjectStoreNames);
|
128
|
+
transaction._scope = oldScope;
|
129
|
+
transaction.objectStoreNames = new FakeDOMStringList(...oldTransactionObjectStoreNames);
|
130
|
+
});
|
131
|
+
}
|
132
|
+
put(value, key) {
|
133
|
+
if (arguments.length === 0) {
|
134
|
+
throw new TypeError();
|
135
|
+
}
|
136
|
+
const record = buildRecordAddPut(this, value, key);
|
137
|
+
return this.transaction._execRequestAsync({
|
138
|
+
operation: this._rawObjectStore.storeRecord.bind(
|
139
|
+
this._rawObjectStore,
|
140
|
+
record,
|
141
|
+
false,
|
142
|
+
this.transaction._rollbackLog,
|
143
|
+
),
|
144
|
+
source: this,
|
145
|
+
});
|
146
|
+
}
|
147
|
+
add(value, key) {
|
148
|
+
if (arguments.length === 0) {
|
149
|
+
throw new TypeError();
|
150
|
+
}
|
151
|
+
const record = buildRecordAddPut(this, value, key);
|
152
|
+
return this.transaction._execRequestAsync({
|
153
|
+
operation: this._rawObjectStore.storeRecord.bind(
|
154
|
+
this._rawObjectStore,
|
155
|
+
record,
|
156
|
+
true,
|
157
|
+
this.transaction._rollbackLog,
|
158
|
+
),
|
159
|
+
source: this,
|
160
|
+
});
|
161
|
+
}
|
162
|
+
delete(key) {
|
163
|
+
if (arguments.length === 0) {
|
164
|
+
throw new TypeError();
|
165
|
+
}
|
166
|
+
confirmActiveTransaction(this);
|
167
|
+
if (this.transaction.mode === 'readonly') {
|
168
|
+
throw new ReadOnlyError();
|
169
|
+
}
|
170
|
+
if (!(key instanceof FDBKeyRange)) {
|
171
|
+
key = valueToKey(key);
|
172
|
+
}
|
173
|
+
return this.transaction._execRequestAsync({
|
174
|
+
operation: this._rawObjectStore.deleteRecord.bind(
|
175
|
+
this._rawObjectStore,
|
176
|
+
key,
|
177
|
+
this.transaction._rollbackLog,
|
178
|
+
),
|
179
|
+
source: this,
|
180
|
+
});
|
181
|
+
}
|
182
|
+
get(key) {
|
183
|
+
if (arguments.length === 0) {
|
184
|
+
throw new TypeError();
|
185
|
+
}
|
186
|
+
confirmActiveTransaction(this);
|
187
|
+
if (!(key instanceof FDBKeyRange)) {
|
188
|
+
key = valueToKey(key);
|
189
|
+
}
|
190
|
+
return this.transaction._execRequestAsync({
|
191
|
+
operation: this._rawObjectStore.getValue.bind(this._rawObjectStore, key),
|
192
|
+
source: this,
|
193
|
+
});
|
194
|
+
}
|
195
|
+
|
196
|
+
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
|
197
|
+
getAll(query, count) {
|
198
|
+
if (arguments.length > 1 && count !== undefined) {
|
199
|
+
count = enforceRange(count, 'unsigned long');
|
200
|
+
}
|
201
|
+
confirmActiveTransaction(this);
|
202
|
+
const range = valueToKeyRange(query);
|
203
|
+
return this.transaction._execRequestAsync({
|
204
|
+
operation: this._rawObjectStore.getAllValues.bind(this._rawObjectStore, range, count),
|
205
|
+
source: this,
|
206
|
+
});
|
207
|
+
}
|
208
|
+
|
209
|
+
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
|
210
|
+
getKey(key) {
|
211
|
+
if (arguments.length === 0) {
|
212
|
+
throw new TypeError();
|
213
|
+
}
|
214
|
+
confirmActiveTransaction(this);
|
215
|
+
if (!(key instanceof FDBKeyRange)) {
|
216
|
+
key = valueToKey(key);
|
217
|
+
}
|
218
|
+
return this.transaction._execRequestAsync({
|
219
|
+
operation: this._rawObjectStore.getKey.bind(this._rawObjectStore, key),
|
220
|
+
source: this,
|
221
|
+
});
|
222
|
+
}
|
223
|
+
|
224
|
+
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
|
225
|
+
getAllKeys(query, count) {
|
226
|
+
if (arguments.length > 1 && count !== undefined) {
|
227
|
+
count = enforceRange(count, 'unsigned long');
|
228
|
+
}
|
229
|
+
confirmActiveTransaction(this);
|
230
|
+
const range = valueToKeyRange(query);
|
231
|
+
return this.transaction._execRequestAsync({
|
232
|
+
operation: this._rawObjectStore.getAllKeys.bind(this._rawObjectStore, range, count),
|
233
|
+
source: this,
|
234
|
+
});
|
235
|
+
}
|
236
|
+
clear() {
|
237
|
+
confirmActiveTransaction(this);
|
238
|
+
if (this.transaction.mode === 'readonly') {
|
239
|
+
throw new ReadOnlyError();
|
240
|
+
}
|
241
|
+
return this.transaction._execRequestAsync({
|
242
|
+
operation: this._rawObjectStore.clear.bind(
|
243
|
+
this._rawObjectStore,
|
244
|
+
this.transaction._rollbackLog,
|
245
|
+
),
|
246
|
+
source: this,
|
247
|
+
});
|
248
|
+
}
|
249
|
+
openCursor(range, direction) {
|
250
|
+
confirmActiveTransaction(this);
|
251
|
+
if (range === null) {
|
252
|
+
range = undefined;
|
253
|
+
}
|
254
|
+
if (range !== undefined && !(range instanceof FDBKeyRange)) {
|
255
|
+
range = FDBKeyRange.only(valueToKey(range));
|
256
|
+
}
|
257
|
+
const request = new FDBRequest();
|
258
|
+
request.source = this;
|
259
|
+
request.transaction = this.transaction;
|
260
|
+
const cursor = new FDBCursorWithValue(this, range, direction, request);
|
261
|
+
return this.transaction._execRequestAsync({
|
262
|
+
operation: cursor._iterate.bind(cursor),
|
263
|
+
request,
|
264
|
+
source: this,
|
265
|
+
});
|
266
|
+
}
|
267
|
+
openKeyCursor(range, direction) {
|
268
|
+
confirmActiveTransaction(this);
|
269
|
+
if (range === null) {
|
270
|
+
range = undefined;
|
271
|
+
}
|
272
|
+
if (range !== undefined && !(range instanceof FDBKeyRange)) {
|
273
|
+
range = FDBKeyRange.only(valueToKey(range));
|
274
|
+
}
|
275
|
+
const request = new FDBRequest();
|
276
|
+
request.source = this;
|
277
|
+
request.transaction = this.transaction;
|
278
|
+
const cursor = new FDBCursor(this, range, direction, request, true);
|
279
|
+
return this.transaction._execRequestAsync({
|
280
|
+
operation: cursor._iterate.bind(cursor),
|
281
|
+
request,
|
282
|
+
source: this,
|
283
|
+
});
|
284
|
+
}
|
285
|
+
|
286
|
+
// tslint:-next-line max-line-length
|
287
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-createIndex-IDBIndex-DOMString-name-DOMString-sequence-DOMString--keyPath-IDBIndexParameters-optionalParameters
|
288
|
+
createIndex(name, keyPath, optionalParameters = {}) {
|
289
|
+
if (arguments.length < 2) {
|
290
|
+
throw new TypeError();
|
291
|
+
}
|
292
|
+
const multiEntry =
|
293
|
+
optionalParameters.multiEntry !== undefined ? optionalParameters.multiEntry : false;
|
294
|
+
const unique = optionalParameters.unique !== undefined ? optionalParameters.unique : false;
|
295
|
+
if (this.transaction.mode !== 'versionchange') {
|
296
|
+
throw new InvalidStateError();
|
297
|
+
}
|
298
|
+
confirmActiveTransaction(this);
|
299
|
+
if (this.indexNames.contains(name)) {
|
300
|
+
throw new ConstraintError();
|
301
|
+
}
|
302
|
+
validateKeyPath(keyPath);
|
303
|
+
if (Array.isArray(keyPath) && multiEntry) {
|
304
|
+
throw new InvalidAccessError();
|
305
|
+
}
|
306
|
+
|
307
|
+
// The index that is requested to be created can contain constraints on the data allowed in the index's
|
308
|
+
// referenced object store, such as requiring uniqueness of the values referenced by the index's keyPath. If the
|
309
|
+
// referenced object store already contains data which violates these constraints, this MUST NOT cause the
|
310
|
+
// implementation of createIndex to throw an exception or affect what it returns. The implementation MUST still
|
311
|
+
// create and return an IDBIndex object. Instead the implementation must queue up an operation to abort the
|
312
|
+
// "versionchange" transaction which was used for the createIndex call.
|
313
|
+
|
314
|
+
const indexNames = [...this.indexNames];
|
315
|
+
this.transaction._rollbackLog.push(() => {
|
316
|
+
const index2 = this._rawObjectStore.rawIndexes.get(name);
|
317
|
+
if (index2) {
|
318
|
+
index2.deleted = true;
|
319
|
+
}
|
320
|
+
this.indexNames = new FakeDOMStringList(...indexNames);
|
321
|
+
this._rawObjectStore.rawIndexes.delete(name);
|
322
|
+
});
|
323
|
+
const index = new Index(this._rawObjectStore, name, keyPath, multiEntry, unique);
|
324
|
+
this.indexNames._push(name);
|
325
|
+
this.indexNames._sort();
|
326
|
+
this._rawObjectStore.rawIndexes.set(name, index);
|
327
|
+
index.initialize(this.transaction); // This is async by design
|
328
|
+
|
329
|
+
return new FDBIndex(this, index);
|
330
|
+
}
|
331
|
+
|
332
|
+
// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
|
333
|
+
index(name) {
|
334
|
+
if (arguments.length === 0) {
|
335
|
+
throw new TypeError();
|
336
|
+
}
|
337
|
+
if (this._rawObjectStore.deleted || this.transaction._state === 'finished') {
|
338
|
+
throw new InvalidStateError();
|
339
|
+
}
|
340
|
+
const index = this._indexesCache.get(name);
|
341
|
+
if (index !== undefined) {
|
342
|
+
return index;
|
343
|
+
}
|
344
|
+
const rawIndex = this._rawObjectStore.rawIndexes.get(name);
|
345
|
+
if (!this.indexNames.contains(name) || rawIndex === undefined) {
|
346
|
+
throw new NotFoundError();
|
347
|
+
}
|
348
|
+
const index2 = new FDBIndex(this, rawIndex);
|
349
|
+
this._indexesCache.set(name, index2);
|
350
|
+
return index2;
|
351
|
+
}
|
352
|
+
deleteIndex(name) {
|
353
|
+
if (arguments.length === 0) {
|
354
|
+
throw new TypeError();
|
355
|
+
}
|
356
|
+
if (this.transaction.mode !== 'versionchange') {
|
357
|
+
throw new InvalidStateError();
|
358
|
+
}
|
359
|
+
confirmActiveTransaction(this);
|
360
|
+
const rawIndex = this._rawObjectStore.rawIndexes.get(name);
|
361
|
+
if (rawIndex === undefined) {
|
362
|
+
throw new NotFoundError();
|
363
|
+
}
|
364
|
+
this.transaction._rollbackLog.push(() => {
|
365
|
+
rawIndex.deleted = false;
|
366
|
+
this._rawObjectStore.rawIndexes.set(name, rawIndex);
|
367
|
+
this.indexNames._push(name);
|
368
|
+
this.indexNames._sort();
|
369
|
+
});
|
370
|
+
this.indexNames = new FakeDOMStringList(
|
371
|
+
...Array.from(this.indexNames).filter(indexName => {
|
372
|
+
return indexName !== name;
|
373
|
+
}),
|
374
|
+
);
|
375
|
+
rawIndex.deleted = true; // Not sure if this is supposed to happen synchronously
|
376
|
+
|
377
|
+
this.transaction._execRequestAsync({
|
378
|
+
operation: () => {
|
379
|
+
const rawIndex2 = this._rawObjectStore.rawIndexes.get(name);
|
380
|
+
|
381
|
+
// Hack in case another index is given this name before this async request is processed. It'd be better
|
382
|
+
// to have a real unique ID for each index.
|
383
|
+
if (rawIndex === rawIndex2) {
|
384
|
+
this._rawObjectStore.rawIndexes.delete(name);
|
385
|
+
}
|
386
|
+
},
|
387
|
+
source: this,
|
388
|
+
});
|
389
|
+
}
|
390
|
+
|
391
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-count-IDBRequest-any-key
|
392
|
+
count(key) {
|
393
|
+
confirmActiveTransaction(this);
|
394
|
+
if (key === null) {
|
395
|
+
key = undefined;
|
396
|
+
}
|
397
|
+
if (key !== undefined && !(key instanceof FDBKeyRange)) {
|
398
|
+
key = FDBKeyRange.only(valueToKey(key));
|
399
|
+
}
|
400
|
+
return this.transaction._execRequestAsync({
|
401
|
+
operation: () => {
|
402
|
+
return this._rawObjectStore.count(key);
|
403
|
+
},
|
404
|
+
source: this,
|
405
|
+
});
|
406
|
+
}
|
407
|
+
toString() {
|
408
|
+
return '[object IDBObjectStore]';
|
409
|
+
}
|
410
|
+
}
|
411
|
+
export default FDBObjectStore;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import { InvalidStateError } from './lib/errors.js';
|
2
|
+
import FakeEventTarget from './lib/FakeEventTarget.js';
|
3
|
+
class FDBRequest extends FakeEventTarget {
|
4
|
+
_result = null;
|
5
|
+
_error = null;
|
6
|
+
source = null;
|
7
|
+
transaction = null;
|
8
|
+
readyState = 'pending';
|
9
|
+
onsuccess = null;
|
10
|
+
onerror = null;
|
11
|
+
get error() {
|
12
|
+
if (this.readyState === 'pending') {
|
13
|
+
throw new InvalidStateError();
|
14
|
+
}
|
15
|
+
return this._error;
|
16
|
+
}
|
17
|
+
set error(value) {
|
18
|
+
this._error = value;
|
19
|
+
}
|
20
|
+
get result() {
|
21
|
+
if (this.readyState === 'pending') {
|
22
|
+
throw new InvalidStateError();
|
23
|
+
}
|
24
|
+
return this._result;
|
25
|
+
}
|
26
|
+
set result(value) {
|
27
|
+
this._result = value;
|
28
|
+
}
|
29
|
+
toString() {
|
30
|
+
return '[object IDBRequest]';
|
31
|
+
}
|
32
|
+
}
|
33
|
+
export default FDBRequest;
|
@@ -0,0 +1,216 @@
|
|
1
|
+
import FDBObjectStore from './FDBObjectStore.js';
|
2
|
+
import FDBRequest from './FDBRequest.js';
|
3
|
+
import {
|
4
|
+
AbortError,
|
5
|
+
InvalidStateError,
|
6
|
+
NotFoundError,
|
7
|
+
TransactionInactiveError,
|
8
|
+
} from './lib/errors.js';
|
9
|
+
import FakeDOMStringList from './lib/FakeDOMStringList.js';
|
10
|
+
import FakeEvent from './lib/FakeEvent.js';
|
11
|
+
import FakeEventTarget from './lib/FakeEventTarget.js';
|
12
|
+
import { queueTask } from './lib/scheduling.js';
|
13
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
|
14
|
+
class FDBTransaction extends FakeEventTarget {
|
15
|
+
_state = 'active';
|
16
|
+
_started = false;
|
17
|
+
_rollbackLog = [];
|
18
|
+
_objectStoresCache = new Map();
|
19
|
+
error = null;
|
20
|
+
onabort = null;
|
21
|
+
oncomplete = null;
|
22
|
+
onerror = null;
|
23
|
+
_requests = [];
|
24
|
+
constructor(storeNames, mode, db) {
|
25
|
+
super();
|
26
|
+
this._scope = new Set(storeNames);
|
27
|
+
this.mode = mode;
|
28
|
+
this.db = db;
|
29
|
+
this.objectStoreNames = new FakeDOMStringList(...Array.from(this._scope).sort());
|
30
|
+
}
|
31
|
+
|
32
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
|
33
|
+
_abort(errName) {
|
34
|
+
for (const f of this._rollbackLog.reverse()) {
|
35
|
+
f();
|
36
|
+
}
|
37
|
+
if (errName !== null) {
|
38
|
+
const e = new DOMException(undefined, errName);
|
39
|
+
this.error = e;
|
40
|
+
}
|
41
|
+
|
42
|
+
// Should this directly remove from _requests?
|
43
|
+
for (const { request } of this._requests) {
|
44
|
+
if (request.readyState !== 'done') {
|
45
|
+
request.readyState = 'done'; // This will cancel execution of this request's operation
|
46
|
+
if (request.source) {
|
47
|
+
request.result = undefined;
|
48
|
+
request.error = new AbortError();
|
49
|
+
const event = new FakeEvent('error', {
|
50
|
+
bubbles: true,
|
51
|
+
cancelable: true,
|
52
|
+
});
|
53
|
+
event.eventPath = [this.db, this];
|
54
|
+
request.dispatchEvent(event);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
queueTask(() => {
|
59
|
+
const event = new FakeEvent('abort', {
|
60
|
+
bubbles: true,
|
61
|
+
cancelable: false,
|
62
|
+
});
|
63
|
+
event.eventPath = [this.db];
|
64
|
+
this.dispatchEvent(event);
|
65
|
+
});
|
66
|
+
this._state = 'finished';
|
67
|
+
}
|
68
|
+
abort() {
|
69
|
+
if (this._state === 'committing' || this._state === 'finished') {
|
70
|
+
throw new InvalidStateError();
|
71
|
+
}
|
72
|
+
this._state = 'active';
|
73
|
+
this._abort(null);
|
74
|
+
}
|
75
|
+
|
76
|
+
// http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
|
77
|
+
objectStore(name) {
|
78
|
+
if (this._state !== 'active') {
|
79
|
+
throw new InvalidStateError();
|
80
|
+
}
|
81
|
+
const objectStore = this._objectStoresCache.get(name);
|
82
|
+
if (objectStore !== undefined) {
|
83
|
+
return objectStore;
|
84
|
+
}
|
85
|
+
const rawObjectStore = this.db._rawDatabase.rawObjectStores.get(name);
|
86
|
+
if (!this._scope.has(name) || rawObjectStore === undefined) {
|
87
|
+
throw new NotFoundError();
|
88
|
+
}
|
89
|
+
const objectStore2 = new FDBObjectStore(this, rawObjectStore);
|
90
|
+
this._objectStoresCache.set(name, objectStore2);
|
91
|
+
return objectStore2;
|
92
|
+
}
|
93
|
+
|
94
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-asynchronously-executing-a-request
|
95
|
+
_execRequestAsync(obj) {
|
96
|
+
const source = obj.source;
|
97
|
+
const operation = obj.operation;
|
98
|
+
let request = Object.hasOwn(obj, 'request') ? obj.request : null;
|
99
|
+
if (this._state !== 'active') {
|
100
|
+
throw new TransactionInactiveError();
|
101
|
+
}
|
102
|
+
|
103
|
+
// Request should only be passed for cursors
|
104
|
+
if (!request) {
|
105
|
+
if (!source) {
|
106
|
+
// Special requests like indexes that just need to run some code
|
107
|
+
request = new FDBRequest();
|
108
|
+
} else {
|
109
|
+
request = new FDBRequest();
|
110
|
+
request.source = source;
|
111
|
+
request.transaction = source.transaction;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
this._requests.push({
|
115
|
+
operation,
|
116
|
+
request,
|
117
|
+
});
|
118
|
+
return request;
|
119
|
+
}
|
120
|
+
_start() {
|
121
|
+
this._started = true;
|
122
|
+
|
123
|
+
// Remove from request queue - cursor ones will be added back if necessary by cursor.continue and such
|
124
|
+
let operation;
|
125
|
+
let request;
|
126
|
+
while (this._requests.length > 0) {
|
127
|
+
const r = this._requests.shift();
|
128
|
+
|
129
|
+
// This should only be false if transaction was aborted
|
130
|
+
if (r && r.request.readyState !== 'done') {
|
131
|
+
request = r.request;
|
132
|
+
operation = r.operation;
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
if (request && operation) {
|
137
|
+
if (!request.source) {
|
138
|
+
// Special requests like indexes that just need to run some code, with error handling already built into
|
139
|
+
// operation
|
140
|
+
operation();
|
141
|
+
} else {
|
142
|
+
let defaultAction;
|
143
|
+
let event;
|
144
|
+
try {
|
145
|
+
const result = operation();
|
146
|
+
request.readyState = 'done';
|
147
|
+
request.result = result;
|
148
|
+
request.error = undefined;
|
149
|
+
|
150
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-a-success-event
|
151
|
+
if (this._state === 'inactive') {
|
152
|
+
this._state = 'active';
|
153
|
+
}
|
154
|
+
event = new FakeEvent('success', {
|
155
|
+
bubbles: false,
|
156
|
+
cancelable: false,
|
157
|
+
});
|
158
|
+
} catch (err) {
|
159
|
+
request.readyState = 'done';
|
160
|
+
request.result = undefined;
|
161
|
+
request.error = err;
|
162
|
+
|
163
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
|
164
|
+
if (this._state === 'inactive') {
|
165
|
+
this._state = 'active';
|
166
|
+
}
|
167
|
+
event = new FakeEvent('error', {
|
168
|
+
bubbles: true,
|
169
|
+
cancelable: true,
|
170
|
+
});
|
171
|
+
defaultAction = this._abort.bind(this, err.name);
|
172
|
+
}
|
173
|
+
try {
|
174
|
+
event.eventPath = [this.db, this];
|
175
|
+
request.dispatchEvent(event);
|
176
|
+
} catch (err) {
|
177
|
+
if (this._state !== 'committing') {
|
178
|
+
this._abort('AbortError');
|
179
|
+
}
|
180
|
+
throw err;
|
181
|
+
}
|
182
|
+
|
183
|
+
// Default action of event
|
184
|
+
if (!event.canceled) {
|
185
|
+
if (defaultAction) {
|
186
|
+
defaultAction();
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
// Give it another chance for new handlers to be set before finishing
|
192
|
+
queueTask(this._start.bind(this));
|
193
|
+
return;
|
194
|
+
}
|
195
|
+
|
196
|
+
// Check if transaction complete event needs to be fired
|
197
|
+
if (this._state !== 'finished') {
|
198
|
+
// Either aborted or committed already
|
199
|
+
this._state = 'finished';
|
200
|
+
if (!this.error) {
|
201
|
+
const event = new FakeEvent('complete');
|
202
|
+
this.dispatchEvent(event);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
commit() {
|
207
|
+
if (this._state !== 'active') {
|
208
|
+
throw new InvalidStateError();
|
209
|
+
}
|
210
|
+
this._state = 'committing';
|
211
|
+
}
|
212
|
+
toString() {
|
213
|
+
return '[object IDBRequest]';
|
214
|
+
}
|
215
|
+
}
|
216
|
+
export default FDBTransaction;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import FakeEvent from './lib/FakeEvent.js';
|
2
|
+
class FDBVersionChangeEvent extends FakeEvent {
|
3
|
+
constructor(type, parameters = {}) {
|
4
|
+
super(type);
|
5
|
+
this.newVersion = parameters.newVersion !== undefined ? parameters.newVersion : null;
|
6
|
+
this.oldVersion = parameters.oldVersion !== undefined ? parameters.oldVersion : 0;
|
7
|
+
}
|
8
|
+
toString() {
|
9
|
+
return '[object IDBVersionChangeEvent]';
|
10
|
+
}
|
11
|
+
}
|
12
|
+
export default FDBVersionChangeEvent;
|