@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,503 @@
|
|
1
|
+
import FDBKeyRange from './FDBKeyRange.js';
|
2
|
+
import FDBObjectStore from './FDBObjectStore.js';
|
3
|
+
import cmp from './lib/cmp.js';
|
4
|
+
import {
|
5
|
+
DataError,
|
6
|
+
InvalidAccessError,
|
7
|
+
InvalidStateError,
|
8
|
+
ReadOnlyError,
|
9
|
+
TransactionInactiveError,
|
10
|
+
} from './lib/errors.js';
|
11
|
+
import extractKey from './lib/extractKey.js';
|
12
|
+
import valueToKey from './lib/valueToKey.js';
|
13
|
+
const getEffectiveObjectStore = cursor => {
|
14
|
+
if (cursor.source instanceof FDBObjectStore) {
|
15
|
+
return cursor.source;
|
16
|
+
}
|
17
|
+
return cursor.source.objectStore;
|
18
|
+
};
|
19
|
+
|
20
|
+
// This takes a key range, a list of lower bounds, and a list of upper bounds and combines them all into a single key
|
21
|
+
// range. It does not handle gt/gte distinctions, because it doesn't really matter much anyway, since for next/prev
|
22
|
+
// cursor iteration it'd also have to look at values to be precise, which would be complicated. This should get us 99%
|
23
|
+
// of the way there.
|
24
|
+
const makeKeyRange = (range, lowers, uppers) => {
|
25
|
+
// Start with bounds from range
|
26
|
+
let lower = range !== undefined ? range.lower : undefined;
|
27
|
+
let upper = range !== undefined ? range.upper : undefined;
|
28
|
+
|
29
|
+
// Augment with values from lowers and uppers
|
30
|
+
for (const lowerTemp of lowers) {
|
31
|
+
if (lowerTemp === undefined) {
|
32
|
+
continue;
|
33
|
+
}
|
34
|
+
if (lower === undefined || cmp(lower, lowerTemp) === 1) {
|
35
|
+
lower = lowerTemp;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
for (const upperTemp of uppers) {
|
39
|
+
if (upperTemp === undefined) {
|
40
|
+
continue;
|
41
|
+
}
|
42
|
+
if (upper === undefined || cmp(upper, upperTemp) === -1) {
|
43
|
+
upper = upperTemp;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
if (lower !== undefined && upper !== undefined) {
|
47
|
+
return FDBKeyRange.bound(lower, upper);
|
48
|
+
}
|
49
|
+
if (lower !== undefined) {
|
50
|
+
return FDBKeyRange.lowerBound(lower);
|
51
|
+
}
|
52
|
+
if (upper !== undefined) {
|
53
|
+
return FDBKeyRange.upperBound(upper);
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
|
58
|
+
class FDBCursor {
|
59
|
+
_gotValue = false;
|
60
|
+
_position = undefined; // Key of previously returned record
|
61
|
+
_objectStorePosition = undefined;
|
62
|
+
_keyOnly = false;
|
63
|
+
_key = undefined;
|
64
|
+
_primaryKey = undefined;
|
65
|
+
constructor(source, range, direction = 'next', request, keyOnly = false) {
|
66
|
+
this._range = range;
|
67
|
+
this._source = source;
|
68
|
+
this._direction = direction;
|
69
|
+
this._request = request;
|
70
|
+
this._keyOnly = keyOnly;
|
71
|
+
}
|
72
|
+
|
73
|
+
// Read only properties
|
74
|
+
get source() {
|
75
|
+
return this._source;
|
76
|
+
}
|
77
|
+
set source(val) {
|
78
|
+
/* For babel */
|
79
|
+
}
|
80
|
+
get request() {
|
81
|
+
return this._request;
|
82
|
+
}
|
83
|
+
set request(val) {
|
84
|
+
/* For babel */
|
85
|
+
}
|
86
|
+
get direction() {
|
87
|
+
return this._direction;
|
88
|
+
}
|
89
|
+
set direction(val) {
|
90
|
+
/* For babel */
|
91
|
+
}
|
92
|
+
get key() {
|
93
|
+
return this._key;
|
94
|
+
}
|
95
|
+
set key(val) {
|
96
|
+
/* For babel */
|
97
|
+
}
|
98
|
+
get primaryKey() {
|
99
|
+
return this._primaryKey;
|
100
|
+
}
|
101
|
+
set primaryKey(val) {
|
102
|
+
/* For babel */
|
103
|
+
}
|
104
|
+
|
105
|
+
// https://w3c.github.io/IndexedDB/#iterate-a-cursor
|
106
|
+
_iterate(key, primaryKey) {
|
107
|
+
const sourceIsObjectStore = this.source instanceof FDBObjectStore;
|
108
|
+
|
109
|
+
// Can't use sourceIsObjectStore because TypeScript
|
110
|
+
const records =
|
111
|
+
this.source instanceof FDBObjectStore
|
112
|
+
? this.source._rawObjectStore.records
|
113
|
+
: this.source._rawIndex.records;
|
114
|
+
let foundRecord;
|
115
|
+
if (this.direction === 'next') {
|
116
|
+
const range = makeKeyRange(this._range, [key, this._position], []);
|
117
|
+
for (const record of records.values(range)) {
|
118
|
+
const cmpResultKey = key !== undefined ? cmp(record.key, key) : undefined;
|
119
|
+
const cmpResultPosition =
|
120
|
+
this._position !== undefined ? cmp(record.key, this._position) : undefined;
|
121
|
+
if (key !== undefined) {
|
122
|
+
if (cmpResultKey === -1) {
|
123
|
+
continue;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
if (primaryKey !== undefined) {
|
127
|
+
if (cmpResultKey === -1) {
|
128
|
+
continue;
|
129
|
+
}
|
130
|
+
const cmpResultPrimaryKey = cmp(record.value, primaryKey);
|
131
|
+
if (cmpResultKey === 0 && cmpResultPrimaryKey === -1) {
|
132
|
+
continue;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
if (this._position !== undefined && sourceIsObjectStore) {
|
136
|
+
if (cmpResultPosition !== 1) {
|
137
|
+
continue;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
if (this._position !== undefined && !sourceIsObjectStore) {
|
141
|
+
if (cmpResultPosition === -1) {
|
142
|
+
continue;
|
143
|
+
}
|
144
|
+
if (cmpResultPosition === 0 && cmp(record.value, this._objectStorePosition) !== 1) {
|
145
|
+
continue;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
if (this._range !== undefined) {
|
149
|
+
if (!this._range.includes(record.key)) {
|
150
|
+
continue;
|
151
|
+
}
|
152
|
+
}
|
153
|
+
foundRecord = record;
|
154
|
+
break;
|
155
|
+
}
|
156
|
+
} else if (this.direction === 'nextunique') {
|
157
|
+
// This could be done without iterating, if the range was defined slightly better (to handle gt/gte cases).
|
158
|
+
// But the performance difference should be small, and that wouldn't work anyway for directions where the
|
159
|
+
// value needs to be used (like next and prev).
|
160
|
+
const range = makeKeyRange(this._range, [key, this._position], []);
|
161
|
+
for (const record of records.values(range)) {
|
162
|
+
if (key !== undefined) {
|
163
|
+
if (cmp(record.key, key) === -1) {
|
164
|
+
continue;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
if (this._position !== undefined) {
|
168
|
+
if (cmp(record.key, this._position) !== 1) {
|
169
|
+
continue;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
if (this._range !== undefined) {
|
173
|
+
if (!this._range.includes(record.key)) {
|
174
|
+
continue;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
foundRecord = record;
|
178
|
+
break;
|
179
|
+
}
|
180
|
+
} else if (this.direction === 'prev') {
|
181
|
+
const range = makeKeyRange(this._range, [], [key, this._position]);
|
182
|
+
for (const record of records.values(range, 'prev')) {
|
183
|
+
const cmpResultKey = key !== undefined ? cmp(record.key, key) : undefined;
|
184
|
+
const cmpResultPosition =
|
185
|
+
this._position !== undefined ? cmp(record.key, this._position) : undefined;
|
186
|
+
if (key !== undefined) {
|
187
|
+
if (cmpResultKey === 1) {
|
188
|
+
continue;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
if (primaryKey !== undefined) {
|
192
|
+
if (cmpResultKey === 1) {
|
193
|
+
continue;
|
194
|
+
}
|
195
|
+
const cmpResultPrimaryKey = cmp(record.value, primaryKey);
|
196
|
+
if (cmpResultKey === 0 && cmpResultPrimaryKey === 1) {
|
197
|
+
continue;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
if (this._position !== undefined && sourceIsObjectStore) {
|
201
|
+
if (cmpResultPosition !== -1) {
|
202
|
+
continue;
|
203
|
+
}
|
204
|
+
}
|
205
|
+
if (this._position !== undefined && !sourceIsObjectStore) {
|
206
|
+
if (cmpResultPosition === 1) {
|
207
|
+
continue;
|
208
|
+
}
|
209
|
+
if (cmpResultPosition === 0 && cmp(record.value, this._objectStorePosition) !== -1) {
|
210
|
+
continue;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
if (this._range !== undefined) {
|
214
|
+
if (!this._range.includes(record.key)) {
|
215
|
+
continue;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
foundRecord = record;
|
219
|
+
break;
|
220
|
+
}
|
221
|
+
} else if (this.direction === 'prevunique') {
|
222
|
+
let tempRecord;
|
223
|
+
const range = makeKeyRange(this._range, [], [key, this._position]);
|
224
|
+
for (const record of records.values(range, 'prev')) {
|
225
|
+
if (key !== undefined) {
|
226
|
+
if (cmp(record.key, key) === 1) {
|
227
|
+
continue;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
if (this._position !== undefined) {
|
231
|
+
if (cmp(record.key, this._position) !== -1) {
|
232
|
+
continue;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
if (this._range !== undefined) {
|
236
|
+
if (!this._range.includes(record.key)) {
|
237
|
+
continue;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
tempRecord = record;
|
241
|
+
break;
|
242
|
+
}
|
243
|
+
if (tempRecord) {
|
244
|
+
foundRecord = records.get(tempRecord.key);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
let result;
|
248
|
+
if (!foundRecord) {
|
249
|
+
this._key = undefined;
|
250
|
+
if (!sourceIsObjectStore) {
|
251
|
+
this._objectStorePosition = undefined;
|
252
|
+
}
|
253
|
+
|
254
|
+
// "this instanceof FDBCursorWithValue" would be better and not require (this as any), but causes runtime
|
255
|
+
// error due to circular dependency.
|
256
|
+
if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
|
257
|
+
this.value = undefined;
|
258
|
+
}
|
259
|
+
result = null;
|
260
|
+
} else {
|
261
|
+
this._position = foundRecord.key;
|
262
|
+
if (!sourceIsObjectStore) {
|
263
|
+
this._objectStorePosition = foundRecord.value;
|
264
|
+
}
|
265
|
+
this._key = foundRecord.key;
|
266
|
+
if (sourceIsObjectStore) {
|
267
|
+
this._primaryKey = structuredClone(foundRecord.key);
|
268
|
+
if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
|
269
|
+
this.value = structuredClone(foundRecord.value);
|
270
|
+
}
|
271
|
+
} else {
|
272
|
+
this._primaryKey = structuredClone(foundRecord.value);
|
273
|
+
if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
|
274
|
+
if (this.source instanceof FDBObjectStore) {
|
275
|
+
// Can't use sourceIsObjectStore because TypeScript
|
276
|
+
throw new Error('This should never happen');
|
277
|
+
}
|
278
|
+
const value = this.source.objectStore._rawObjectStore.getValue(foundRecord.value);
|
279
|
+
this.value = structuredClone(value);
|
280
|
+
}
|
281
|
+
}
|
282
|
+
this._gotValue = true;
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
284
|
+
result = this;
|
285
|
+
}
|
286
|
+
return result;
|
287
|
+
}
|
288
|
+
|
289
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
|
290
|
+
update(value) {
|
291
|
+
if (value === undefined) {
|
292
|
+
throw new TypeError();
|
293
|
+
}
|
294
|
+
const effectiveObjectStore = getEffectiveObjectStore(this);
|
295
|
+
const effectiveKey = Object.hasOwn(this.source, '_rawIndex') ? this.primaryKey : this._position;
|
296
|
+
const transaction = effectiveObjectStore.transaction;
|
297
|
+
if (transaction._state !== 'active') {
|
298
|
+
throw new TransactionInactiveError();
|
299
|
+
}
|
300
|
+
if (transaction.mode === 'readonly') {
|
301
|
+
throw new ReadOnlyError();
|
302
|
+
}
|
303
|
+
if (effectiveObjectStore._rawObjectStore.deleted) {
|
304
|
+
throw new InvalidStateError();
|
305
|
+
}
|
306
|
+
if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
|
307
|
+
throw new InvalidStateError();
|
308
|
+
}
|
309
|
+
if (!this._gotValue || !Object.hasOwn(this, 'value')) {
|
310
|
+
throw new InvalidStateError();
|
311
|
+
}
|
312
|
+
const clone = structuredClone(value);
|
313
|
+
if (effectiveObjectStore.keyPath !== null) {
|
314
|
+
let tempKey;
|
315
|
+
try {
|
316
|
+
tempKey = extractKey(effectiveObjectStore.keyPath, clone);
|
317
|
+
} catch (err) {
|
318
|
+
/* Handled immediately below */
|
319
|
+
}
|
320
|
+
if (cmp(tempKey, effectiveKey) !== 0) {
|
321
|
+
throw new DataError();
|
322
|
+
}
|
323
|
+
}
|
324
|
+
const record = {
|
325
|
+
key: effectiveKey,
|
326
|
+
value: clone,
|
327
|
+
};
|
328
|
+
return transaction._execRequestAsync({
|
329
|
+
operation: effectiveObjectStore._rawObjectStore.storeRecord.bind(
|
330
|
+
effectiveObjectStore._rawObjectStore,
|
331
|
+
record,
|
332
|
+
false,
|
333
|
+
transaction._rollbackLog,
|
334
|
+
),
|
335
|
+
source: this,
|
336
|
+
});
|
337
|
+
}
|
338
|
+
|
339
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
|
340
|
+
advance(count) {
|
341
|
+
if (!Number.isInteger(count) || count <= 0) {
|
342
|
+
throw new TypeError();
|
343
|
+
}
|
344
|
+
const effectiveObjectStore = getEffectiveObjectStore(this);
|
345
|
+
const transaction = effectiveObjectStore.transaction;
|
346
|
+
if (transaction._state !== 'active') {
|
347
|
+
throw new TransactionInactiveError();
|
348
|
+
}
|
349
|
+
if (effectiveObjectStore._rawObjectStore.deleted) {
|
350
|
+
throw new InvalidStateError();
|
351
|
+
}
|
352
|
+
if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
|
353
|
+
throw new InvalidStateError();
|
354
|
+
}
|
355
|
+
if (!this._gotValue) {
|
356
|
+
throw new InvalidStateError();
|
357
|
+
}
|
358
|
+
if (this._request) {
|
359
|
+
this._request.readyState = 'pending';
|
360
|
+
}
|
361
|
+
transaction._execRequestAsync({
|
362
|
+
operation: () => {
|
363
|
+
let result;
|
364
|
+
for (let i = 0; i < count; i++) {
|
365
|
+
result = this._iterate();
|
366
|
+
|
367
|
+
// Not sure why this is needed
|
368
|
+
if (!result) {
|
369
|
+
break;
|
370
|
+
}
|
371
|
+
}
|
372
|
+
return result;
|
373
|
+
},
|
374
|
+
request: this._request,
|
375
|
+
source: this.source,
|
376
|
+
});
|
377
|
+
this._gotValue = false;
|
378
|
+
}
|
379
|
+
|
380
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
|
381
|
+
continue(key) {
|
382
|
+
const effectiveObjectStore = getEffectiveObjectStore(this);
|
383
|
+
const transaction = effectiveObjectStore.transaction;
|
384
|
+
if (transaction._state !== 'active') {
|
385
|
+
throw new TransactionInactiveError();
|
386
|
+
}
|
387
|
+
if (effectiveObjectStore._rawObjectStore.deleted) {
|
388
|
+
throw new InvalidStateError();
|
389
|
+
}
|
390
|
+
if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
|
391
|
+
throw new InvalidStateError();
|
392
|
+
}
|
393
|
+
if (!this._gotValue) {
|
394
|
+
throw new InvalidStateError();
|
395
|
+
}
|
396
|
+
if (key !== undefined) {
|
397
|
+
key = valueToKey(key);
|
398
|
+
const cmpResult = cmp(key, this._position);
|
399
|
+
if (
|
400
|
+
(cmpResult <= 0 && (this.direction === 'next' || this.direction === 'nextunique')) ||
|
401
|
+
(cmpResult >= 0 && (this.direction === 'prev' || this.direction === 'prevunique'))
|
402
|
+
) {
|
403
|
+
throw new DataError();
|
404
|
+
}
|
405
|
+
}
|
406
|
+
if (this._request) {
|
407
|
+
this._request.readyState = 'pending';
|
408
|
+
}
|
409
|
+
transaction._execRequestAsync({
|
410
|
+
operation: this._iterate.bind(this, key),
|
411
|
+
request: this._request,
|
412
|
+
source: this.source,
|
413
|
+
});
|
414
|
+
this._gotValue = false;
|
415
|
+
}
|
416
|
+
|
417
|
+
// hthttps://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
|
418
|
+
continuePrimaryKey(key, primaryKey) {
|
419
|
+
const effectiveObjectStore = getEffectiveObjectStore(this);
|
420
|
+
const transaction = effectiveObjectStore.transaction;
|
421
|
+
if (transaction._state !== 'active') {
|
422
|
+
throw new TransactionInactiveError();
|
423
|
+
}
|
424
|
+
if (effectiveObjectStore._rawObjectStore.deleted) {
|
425
|
+
throw new InvalidStateError();
|
426
|
+
}
|
427
|
+
if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
|
428
|
+
throw new InvalidStateError();
|
429
|
+
}
|
430
|
+
if (
|
431
|
+
this.source instanceof FDBObjectStore ||
|
432
|
+
(this.direction !== 'next' && this.direction !== 'prev')
|
433
|
+
) {
|
434
|
+
throw new InvalidAccessError();
|
435
|
+
}
|
436
|
+
if (!this._gotValue) {
|
437
|
+
throw new InvalidStateError();
|
438
|
+
}
|
439
|
+
|
440
|
+
// Not sure about this
|
441
|
+
if (key === undefined || primaryKey === undefined) {
|
442
|
+
throw new DataError();
|
443
|
+
}
|
444
|
+
key = valueToKey(key);
|
445
|
+
const cmpResult = cmp(key, this._position);
|
446
|
+
if (
|
447
|
+
(cmpResult === -1 && this.direction === 'next') ||
|
448
|
+
(cmpResult === 1 && this.direction === 'prev')
|
449
|
+
) {
|
450
|
+
throw new DataError();
|
451
|
+
}
|
452
|
+
const cmpResult2 = cmp(primaryKey, this._objectStorePosition);
|
453
|
+
if (cmpResult === 0) {
|
454
|
+
if (
|
455
|
+
(cmpResult2 <= 0 && this.direction === 'next') ||
|
456
|
+
(cmpResult2 >= 0 && this.direction === 'prev')
|
457
|
+
) {
|
458
|
+
throw new DataError();
|
459
|
+
}
|
460
|
+
}
|
461
|
+
if (this._request) {
|
462
|
+
this._request.readyState = 'pending';
|
463
|
+
}
|
464
|
+
transaction._execRequestAsync({
|
465
|
+
operation: this._iterate.bind(this, key, primaryKey),
|
466
|
+
request: this._request,
|
467
|
+
source: this.source,
|
468
|
+
});
|
469
|
+
this._gotValue = false;
|
470
|
+
}
|
471
|
+
delete() {
|
472
|
+
const effectiveObjectStore = getEffectiveObjectStore(this);
|
473
|
+
const effectiveKey = Object.hasOwn(this.source, '_rawIndex') ? this.primaryKey : this._position;
|
474
|
+
const transaction = effectiveObjectStore.transaction;
|
475
|
+
if (transaction._state !== 'active') {
|
476
|
+
throw new TransactionInactiveError();
|
477
|
+
}
|
478
|
+
if (transaction.mode === 'readonly') {
|
479
|
+
throw new ReadOnlyError();
|
480
|
+
}
|
481
|
+
if (effectiveObjectStore._rawObjectStore.deleted) {
|
482
|
+
throw new InvalidStateError();
|
483
|
+
}
|
484
|
+
if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
|
485
|
+
throw new InvalidStateError();
|
486
|
+
}
|
487
|
+
if (!this._gotValue || !Object.hasOwn(this, 'value')) {
|
488
|
+
throw new InvalidStateError();
|
489
|
+
}
|
490
|
+
return transaction._execRequestAsync({
|
491
|
+
operation: effectiveObjectStore._rawObjectStore.deleteRecord.bind(
|
492
|
+
effectiveObjectStore._rawObjectStore,
|
493
|
+
effectiveKey,
|
494
|
+
transaction._rollbackLog,
|
495
|
+
),
|
496
|
+
source: this,
|
497
|
+
});
|
498
|
+
}
|
499
|
+
toString() {
|
500
|
+
return '[object IDBCursor]';
|
501
|
+
}
|
502
|
+
}
|
503
|
+
export default FDBCursor;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import FDBCursor from './FDBCursor.js';
|
2
|
+
class FDBCursorWithValue extends FDBCursor {
|
3
|
+
value = undefined;
|
4
|
+
constructor(source, range, direction, request) {
|
5
|
+
super(source, range, direction, request);
|
6
|
+
}
|
7
|
+
toString() {
|
8
|
+
return '[object IDBCursorWithValue]';
|
9
|
+
}
|
10
|
+
}
|
11
|
+
export default FDBCursorWithValue;
|
@@ -0,0 +1,172 @@
|
|
1
|
+
import FDBTransaction from './FDBTransaction.js';
|
2
|
+
import {
|
3
|
+
ConstraintError,
|
4
|
+
InvalidAccessError,
|
5
|
+
InvalidStateError,
|
6
|
+
NotFoundError,
|
7
|
+
TransactionInactiveError,
|
8
|
+
} from './lib/errors.js';
|
9
|
+
import FakeDOMStringList from './lib/FakeDOMStringList.js';
|
10
|
+
import FakeEventTarget from './lib/FakeEventTarget.js';
|
11
|
+
import ObjectStore from './lib/ObjectStore.js';
|
12
|
+
import { queueTask } from './lib/scheduling.js';
|
13
|
+
import validateKeyPath from './lib/validateKeyPath.js';
|
14
|
+
const confirmActiveVersionchangeTransaction = database => {
|
15
|
+
if (!database._runningVersionchangeTransaction) {
|
16
|
+
throw new InvalidStateError();
|
17
|
+
}
|
18
|
+
|
19
|
+
// Find the latest versionchange transaction
|
20
|
+
const transactions = database._rawDatabase.transactions.filter(tx => {
|
21
|
+
return tx.mode === 'versionchange';
|
22
|
+
});
|
23
|
+
const transaction = transactions[transactions.length - 1];
|
24
|
+
if (!transaction || transaction._state === 'finished') {
|
25
|
+
throw new InvalidStateError();
|
26
|
+
}
|
27
|
+
if (transaction._state !== 'active') {
|
28
|
+
throw new TransactionInactiveError();
|
29
|
+
}
|
30
|
+
return transaction;
|
31
|
+
};
|
32
|
+
|
33
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
|
34
|
+
const closeConnection = connection => {
|
35
|
+
connection._closePending = true;
|
36
|
+
const transactionsComplete = connection._rawDatabase.transactions.every(transaction => {
|
37
|
+
return transaction._state === 'finished';
|
38
|
+
});
|
39
|
+
if (transactionsComplete) {
|
40
|
+
connection._closed = true;
|
41
|
+
connection._rawDatabase.connections = connection._rawDatabase.connections.filter(
|
42
|
+
otherConnection => {
|
43
|
+
return connection !== otherConnection;
|
44
|
+
},
|
45
|
+
);
|
46
|
+
} else {
|
47
|
+
queueTask(() => {
|
48
|
+
closeConnection(connection);
|
49
|
+
});
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
|
54
|
+
class FDBDatabase extends FakeEventTarget {
|
55
|
+
_closePending = false;
|
56
|
+
_closed = false;
|
57
|
+
_runningVersionchangeTransaction = false;
|
58
|
+
constructor(rawDatabase) {
|
59
|
+
super();
|
60
|
+
this._rawDatabase = rawDatabase;
|
61
|
+
this._rawDatabase.connections.push(this);
|
62
|
+
this.name = rawDatabase.name;
|
63
|
+
this.version = rawDatabase.version;
|
64
|
+
this.objectStoreNames = new FakeDOMStringList(
|
65
|
+
...Array.from(rawDatabase.rawObjectStores.keys()).sort(),
|
66
|
+
);
|
67
|
+
}
|
68
|
+
|
69
|
+
// http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
|
70
|
+
createObjectStore(name, options = {}) {
|
71
|
+
if (name === undefined) {
|
72
|
+
throw new TypeError();
|
73
|
+
}
|
74
|
+
const transaction = confirmActiveVersionchangeTransaction(this);
|
75
|
+
const keyPath = options !== null && options.keyPath !== undefined ? options.keyPath : null;
|
76
|
+
const autoIncrement =
|
77
|
+
options !== null && options.autoIncrement !== undefined ? options.autoIncrement : false;
|
78
|
+
if (keyPath !== null) {
|
79
|
+
validateKeyPath(keyPath);
|
80
|
+
}
|
81
|
+
if (this._rawDatabase.rawObjectStores.has(name)) {
|
82
|
+
throw new ConstraintError();
|
83
|
+
}
|
84
|
+
if (autoIncrement && (keyPath === '' || Array.isArray(keyPath))) {
|
85
|
+
throw new InvalidAccessError();
|
86
|
+
}
|
87
|
+
const objectStoreNames = [...this.objectStoreNames];
|
88
|
+
transaction._rollbackLog.push(() => {
|
89
|
+
const objectStore = this._rawDatabase.rawObjectStores.get(name);
|
90
|
+
if (objectStore) {
|
91
|
+
objectStore.deleted = true;
|
92
|
+
}
|
93
|
+
this.objectStoreNames = new FakeDOMStringList(...objectStoreNames);
|
94
|
+
transaction._scope.delete(name);
|
95
|
+
this._rawDatabase.rawObjectStores.delete(name);
|
96
|
+
});
|
97
|
+
const rawObjectStore = new ObjectStore(this._rawDatabase, name, keyPath, autoIncrement);
|
98
|
+
this.objectStoreNames._push(name);
|
99
|
+
this.objectStoreNames._sort();
|
100
|
+
transaction._scope.add(name);
|
101
|
+
this._rawDatabase.rawObjectStores.set(name, rawObjectStore);
|
102
|
+
transaction.objectStoreNames = new FakeDOMStringList(...this.objectStoreNames);
|
103
|
+
return transaction.objectStore(name);
|
104
|
+
}
|
105
|
+
deleteObjectStore(name) {
|
106
|
+
if (name === undefined) {
|
107
|
+
throw new TypeError();
|
108
|
+
}
|
109
|
+
const transaction = confirmActiveVersionchangeTransaction(this);
|
110
|
+
const store = this._rawDatabase.rawObjectStores.get(name);
|
111
|
+
if (store === undefined) {
|
112
|
+
throw new NotFoundError();
|
113
|
+
}
|
114
|
+
this.objectStoreNames = new FakeDOMStringList(
|
115
|
+
...Array.from(this.objectStoreNames).filter(objectStoreName => {
|
116
|
+
return objectStoreName !== name;
|
117
|
+
}),
|
118
|
+
);
|
119
|
+
transaction.objectStoreNames = new FakeDOMStringList(...this.objectStoreNames);
|
120
|
+
transaction._rollbackLog.push(() => {
|
121
|
+
store.deleted = false;
|
122
|
+
this._rawDatabase.rawObjectStores.set(name, store);
|
123
|
+
this.objectStoreNames._push(name);
|
124
|
+
this.objectStoreNames._sort();
|
125
|
+
});
|
126
|
+
store.deleted = true;
|
127
|
+
this._rawDatabase.rawObjectStores.delete(name);
|
128
|
+
transaction._objectStoresCache.delete(name);
|
129
|
+
}
|
130
|
+
transaction(storeNames, mode) {
|
131
|
+
mode = mode !== undefined ? mode : 'readonly';
|
132
|
+
if (mode !== 'readonly' && mode !== 'readwrite' && mode !== 'versionchange') {
|
133
|
+
throw new TypeError('Invalid mode: ' + mode);
|
134
|
+
}
|
135
|
+
const hasActiveVersionchange = this._rawDatabase.transactions.some(transaction => {
|
136
|
+
return (
|
137
|
+
transaction._state === 'active' &&
|
138
|
+
transaction.mode === 'versionchange' &&
|
139
|
+
transaction.db === this
|
140
|
+
);
|
141
|
+
});
|
142
|
+
if (hasActiveVersionchange) {
|
143
|
+
throw new InvalidStateError();
|
144
|
+
}
|
145
|
+
if (this._closePending) {
|
146
|
+
throw new InvalidStateError();
|
147
|
+
}
|
148
|
+
if (!Array.isArray(storeNames)) {
|
149
|
+
storeNames = [storeNames];
|
150
|
+
}
|
151
|
+
if (storeNames.length === 0 && mode !== 'versionchange') {
|
152
|
+
throw new InvalidAccessError();
|
153
|
+
}
|
154
|
+
for (const storeName of storeNames) {
|
155
|
+
if (!this.objectStoreNames.contains(storeName)) {
|
156
|
+
throw new NotFoundError('No objectStore named ' + storeName + ' in this database');
|
157
|
+
}
|
158
|
+
}
|
159
|
+
const tx = new FDBTransaction(storeNames, mode, this);
|
160
|
+
this._rawDatabase.transactions.push(tx);
|
161
|
+
this._rawDatabase.processTransactions(); // See if can start right away (async)
|
162
|
+
|
163
|
+
return tx;
|
164
|
+
}
|
165
|
+
close() {
|
166
|
+
closeConnection(this);
|
167
|
+
}
|
168
|
+
toString() {
|
169
|
+
return '[object IDBDatabase]';
|
170
|
+
}
|
171
|
+
}
|
172
|
+
export default FDBDatabase;
|