summaryrefslogtreecommitdiff
path: root/packages/idb-bridge/src/bridge-idb.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/idb-bridge/src/bridge-idb.ts')
-rw-r--r--packages/idb-bridge/src/bridge-idb.ts516
1 files changed, 298 insertions, 218 deletions
diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts
index 128a6900d..8cecba534 100644
--- a/packages/idb-bridge/src/bridge-idb.ts
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -17,12 +17,16 @@
import {
Backend,
+ ConnectResult,
DatabaseConnection,
DatabaseTransaction,
- RecordGetRequest,
+ IndexGetQuery,
+ IndexMeta,
+ ObjectStoreGetQuery,
+ ObjectStoreMeta,
+ RecordGetResponse,
RecordStoreRequest,
ResultLevel,
- Schema,
StoreLevel,
} from "./backend-interface.js";
import {
@@ -57,10 +61,7 @@ import {
TransactionInactiveError,
VersionError,
} from "./util/errors.js";
-import {
- FakeDOMStringList,
- fakeDOMStringList,
-} from "./util/fakeDOMStringList.js";
+import { fakeDOMStringList } from "./util/fakeDOMStringList.js";
import FakeEvent from "./util/FakeEvent.js";
import FakeEventTarget from "./util/FakeEventTarget.js";
import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
@@ -71,17 +72,14 @@ import { checkStructuredCloneOrThrow } from "./util/structuredClone.js";
import { validateKeyPath } from "./util/validateKeyPath.js";
import { valueToKey } from "./util/valueToKey.js";
-/** @public */
export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore;
-/** @public */
export interface RequestObj {
operation: () => Promise<any>;
request?: BridgeIDBRequest | undefined;
source?: any;
}
-/** @public */
export interface BridgeIDBDatabaseInfo {
name: string;
version: number;
@@ -101,8 +99,6 @@ function simplifyRange(
/**
* http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
- *
- * @public
*/
export class BridgeIDBCursor implements IDBCursor {
_request: BridgeIDBRequest | undefined;
@@ -207,29 +203,56 @@ export class BridgeIDBCursor implements IDBCursor {
);
BridgeIDBFactory.enableTracing &&
console.log("cursor type ", this.toString());
- const isIndex = this._indexName !== undefined;
- const recordGetRequest: RecordGetRequest = {
- direction: this.direction,
- indexName: this._indexName,
- lastIndexPosition: this._indexPosition,
- lastObjectStorePosition: this._objectStorePosition,
- limit: 1,
- range: simplifyRange(this._range),
- objectStoreName: this._objectStoreName,
- advanceIndexKey: isIndex ? key : undefined,
- advancePrimaryKey: isIndex ? primaryKey : key,
- resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
- };
+ const indexName = this._indexName;
const { btx } = this.source._confirmStartedBackendTransaction();
- let response = await this._backend.getRecords(btx, recordGetRequest);
+ let response: RecordGetResponse;
+
+ if (indexName != null) {
+ const indexRecordGetRequest: IndexGetQuery = {
+ direction: this.direction,
+ indexName: indexName,
+ lastIndexPosition: this._indexPosition,
+ lastObjectStorePosition: this._objectStorePosition,
+ limit: 1,
+ range: simplifyRange(this._range),
+ objectStoreName: this._objectStoreName,
+ advanceIndexKey: key,
+ advancePrimaryKey: primaryKey,
+ resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
+ };
+ response = await this._backend.getIndexRecords(
+ btx,
+ indexRecordGetRequest,
+ );
+ } else {
+ if (primaryKey != null) {
+ // Only allowed for index cursors
+ throw new InvalidAccessError();
+ }
+ const objStoreGetRequest: ObjectStoreGetQuery = {
+ direction: this.direction,
+ lastObjectStorePosition: this._objectStorePosition,
+ limit: 1,
+ range: simplifyRange(this._range),
+ objectStoreName: this._objectStoreName,
+ advancePrimaryKey: key,
+ resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
+ };
+ response = await this._backend.getObjectStoreRecords(
+ btx,
+ objStoreGetRequest,
+ );
+ }
if (response.count === 0) {
if (BridgeIDBFactory.enableTracing) {
console.log("cursor is returning empty result");
}
this._gotValue = false;
+ this._key = undefined;
+ this._value = undefined;
return null;
}
@@ -237,11 +260,6 @@ export class BridgeIDBCursor implements IDBCursor {
throw Error("invariant failed");
}
- if (BridgeIDBFactory.enableTracing) {
- console.log("request is:", JSON.stringify(recordGetRequest));
- console.log("get response is:", JSON.stringify(response));
- }
-
if (this._indexName !== undefined) {
this._key = response.indexKeys![0];
} else {
@@ -550,7 +568,6 @@ const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => {
};
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
-/** @public */
export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
_closePending = false;
_closed = false;
@@ -561,7 +578,16 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
_backendConnection: DatabaseConnection;
_backend: Backend;
- _schema: Schema;
+ _name: string;
+
+ _initialVersion: number;
+
+ _version: number;
+
+ // "object store set" from the spec
+ _objectStoreSet: string[];
+
+ // _schema: Schema;
/**
* Name that can be set to identify the object store in logs.
@@ -569,17 +595,15 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
_debugName: string | undefined = undefined;
get name(): string {
- return this._schema.databaseName;
+ return this._name;
}
get version(): number {
- return this._schema.databaseVersion;
+ return this._version;
}
get objectStoreNames(): DOMStringList {
- return fakeDOMStringList(
- Object.keys(this._schema.objectStores),
- ).sort() as DOMStringList;
+ return fakeDOMStringList([...this._objectStoreSet]).sort() as DOMStringList;
}
/**
@@ -606,13 +630,13 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
}
}
- constructor(backend: Backend, backendConnection: DatabaseConnection) {
+ constructor(name: string, backend: Backend, connResult: ConnectResult) {
super();
-
- this._schema = backend.getSchema(backendConnection);
-
+ this._name = name;
+ this._version = this._initialVersion = connResult.version;
this._backend = backend;
- this._backendConnection = backendConnection;
+ this._backendConnection = connResult.conn;
+ this._objectStoreSet = connResult.objectStores;
}
// http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
@@ -645,7 +669,8 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
validateKeyPath(keyPath);
}
- if (Object.keys(this._schema.objectStores).includes(name)) {
+ if (this._objectStoreSet.includes(name)) {
+ // Already exists
throw new ConstraintError();
}
@@ -660,7 +685,9 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
autoIncrement,
);
- this._schema = this._backend.getCurrentTransactionSchema(backendTx);
+ transaction._scope.add(name);
+ this._objectStoreSet.push(name);
+ this._objectStoreSet.sort();
const newObjectStore = transaction.objectStore(name);
newObjectStore._justCreated = true;
@@ -682,6 +709,10 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
os._deleted = true;
transaction._objectStoresCache.delete(name);
}
+ transaction._cachedObjectStoreNames = undefined;
+ transaction._scope.delete(name);
+ const nameIdx = this._objectStoreSet.indexOf(name);
+ this._objectStoreSet.splice(nameIdx, 1);
}
public _internalTransaction(
@@ -766,10 +797,8 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
}
}
-/** @public */
export type DatabaseList = Array<{ name: string; version: number }>;
-/** @public */
export class BridgeIDBFactory {
public cmp = compareKeys;
private backend: Backend;
@@ -810,8 +839,10 @@ export class BridgeIDBFactory {
});
request.dispatchEvent(event2);
} catch (err: any) {
- request.error = new Error();
- request.error.name = err.name;
+ const myErr = new Error();
+ myErr.name = err.name;
+ myErr.message = err.message;
+ request.error = myErr;
request.readyState = "done";
const event = new FakeEvent("error", {
@@ -841,27 +872,26 @@ export class BridgeIDBFactory {
const request = new BridgeIDBOpenDBRequest();
queueTask(async () => {
- let dbconn: DatabaseConnection;
+ let dbConnRes: ConnectResult;
try {
if (BridgeIDBFactory.enableTracing) {
console.log("TRACE: connecting to database");
}
- dbconn = await this.backend.connectDatabase(name);
+ dbConnRes = await this.backend.connectDatabase(name);
if (BridgeIDBFactory.enableTracing) {
console.log("TRACE: connected!");
}
} catch (err: any) {
if (BridgeIDBFactory.enableTracing) {
console.log(
- "TRACE: caught exception while trying to connect with backend",
+ "TRACE: caught exception while trying to connect with backend:",
+ err,
);
}
request._finishWithError(err);
return;
}
-
- const schema = this.backend.getSchema(dbconn);
- const existingVersion = schema.databaseVersion;
+ const existingVersion = dbConnRes.version;
if (version === undefined) {
version = existingVersion !== 0 ? existingVersion : 1;
@@ -879,7 +909,7 @@ export class BridgeIDBFactory {
return;
}
- const db = new BridgeIDBDatabase(this.backend, dbconn);
+ const db = new BridgeIDBDatabase(name, this.backend, dbConnRes);
if (existingVersion == requestedVersion) {
request.result = db;
@@ -929,16 +959,14 @@ export class BridgeIDBFactory {
}
const backendTransaction = await this.backend.enterVersionChange(
- dbconn,
+ dbConnRes.conn,
requestedVersion,
);
// We need to expose the new version number to the upgrade transaction.
- db._schema =
- this.backend.getCurrentTransactionSchema(backendTransaction);
-
+ db._version = version;
const transaction = db._internalTransaction(
- [],
+ dbConnRes.objectStores,
"versionchange",
backendTransaction,
request,
@@ -1030,37 +1058,48 @@ export class BridgeIDBFactory {
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
-/** @public */
export class BridgeIDBIndex implements IDBIndex {
_objectStore: BridgeIDBObjectStore;
+ _indexMeta: IndexMeta;
+ _originalName: string | undefined = undefined;
+ _deleted: boolean = false;
+ _name: string;
+
+ /**
+ * Was this index newly created in the current transaction?
+ */
+ _justCreated: boolean = false;
get objectStore(): IDBObjectStore {
return this._objectStore;
}
- get _schema(): Schema {
- return this._objectStore._transaction._db._schema;
- }
-
get keyPath(): IDBKeyPath | IDBKeyPath[] {
- return this._schema.objectStores[this._objectStore.name].indexes[this._name]
- .keyPath;
+ return this._indexMeta.keyPath;
}
get multiEntry(): boolean {
- return this._schema.objectStores[this._objectStore.name].indexes[this._name]
- .multiEntry;
+ return this._indexMeta.multiEntry;
}
get unique(): boolean {
- return this._schema.objectStores[this._objectStore.name].indexes[this._name]
- .unique;
+ return this._indexMeta.multiEntry;
}
get _backend(): Backend {
return this._objectStore._backend;
}
+ constructor(
+ objectStore: BridgeIDBObjectStore,
+ name: string,
+ indexMeta: IndexMeta,
+ ) {
+ this._name = name;
+ this._objectStore = objectStore;
+ this._indexMeta = indexMeta;
+ }
+
_confirmStartedBackendTransaction(): { btx: DatabaseTransaction } {
return this._objectStore._confirmStartedBackendTransaction();
}
@@ -1069,20 +1108,6 @@ export class BridgeIDBIndex implements IDBIndex {
this._objectStore._confirmActiveTransaction();
}
- private _name: string;
-
- public _deleted: boolean = false;
-
- /**
- * Was this index newly created in the current transaction?
- */
- _justCreated: boolean = false;
-
- constructor(objectStore: BridgeIDBObjectStore, name: string) {
- this._name = name;
- this._objectStore = objectStore;
- }
-
get name() {
return this._name;
}
@@ -1107,18 +1132,39 @@ export class BridgeIDBIndex implements IDBIndex {
if (newName === oldName) {
return;
}
-
+ if (this._originalName != null) {
+ this._originalName = oldName;
+ }
this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
+ this._applyNameChange(oldName, newName);
+ if (this._objectStore._objectStoreMeta.indexSet.indexOf(name) >= 0) {
+ throw new Error("internal invariant violated");
+ }
+ }
- this._objectStore._transaction._db._schema =
- this._backend.getCurrentTransactionSchema(btx);
-
- this._objectStore._indexesCache.delete(oldName);
- this._objectStore._indexesCache.set(newName, this);
+ _applyNameChange(oldName: string, newName: string) {
+ this._objectStore._indexHandlesCache.delete(oldName);
+ this._objectStore._indexHandlesCache.set(newName, this);
+ const indexSet = this._objectStore._objectStoreMeta.indexSet;
+ const indexIdx = indexSet.indexOf(oldName);
+ indexSet[indexIdx] = newName;
+ indexSet.sort();
this._name = newName;
+ }
- if (this._objectStore._indexNames.indexOf(name) >= 0) {
- throw new Error("internal invariant violated");
+ _applyDelete() {
+ this._objectStore._indexHandlesCache.delete(this._name);
+ const indexSet = this._objectStore._objectStoreMeta.indexSet;
+ const indexIdx = indexSet.indexOf(this._name);
+ indexSet.splice(indexIdx, 1);
+ }
+
+ _abort() {
+ if (this._originalName != null) {
+ this._applyNameChange(this._name, this._originalName);
+ }
+ if (this._justCreated) {
+ this._deleted = true;
}
}
@@ -1199,34 +1245,23 @@ export class BridgeIDBIndex implements IDBIndex {
}
private _confirmIndexExists() {
- const storeSchema = this._schema.objectStores[this._objectStore._name];
- if (!storeSchema) {
- throw new InvalidStateError(
- `no schema for object store '${this._objectStore._name}'`,
- );
- }
- if (!storeSchema.indexes[this._name]) {
- throw new InvalidStateError(
- `no schema for index '${this._name}' of object store '${this._objectStore._name}'`,
- );
- }
- }
-
- get(key: BridgeIDBKeyRange | IDBValidKey) {
if (this._deleted) {
throw new InvalidStateError();
}
if (this._objectStore._deleted) {
throw new InvalidStateError();
}
- this._confirmActiveTransaction();
+ }
+
+ get(key: BridgeIDBKeyRange | IDBValidKey) {
this._confirmIndexExists();
+ this._confirmActiveTransaction();
if (!(key instanceof BridgeIDBKeyRange)) {
key = BridgeIDBKeyRange._valueToKeyRange(key);
}
- const getReq: RecordGetRequest = {
+ const getReq: IndexGetQuery = {
direction: "next",
indexName: this._name,
limit: 1,
@@ -1237,7 +1272,7 @@ export class BridgeIDBIndex implements IDBIndex {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, getReq);
+ const result = await this._backend.getIndexRecords(btx, getReq);
if (result.count == 0) {
return undefined;
}
@@ -1273,7 +1308,7 @@ export class BridgeIDBIndex implements IDBIndex {
count = -1;
}
- const getReq: RecordGetRequest = {
+ const getReq: IndexGetQuery = {
direction: "next",
indexName: this._name,
limit: count,
@@ -1284,7 +1319,7 @@ export class BridgeIDBIndex implements IDBIndex {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, getReq);
+ const result = await this._backend.getIndexRecords(btx, getReq);
const values = result.values;
if (!values) {
throw Error("invariant violated");
@@ -1307,7 +1342,7 @@ export class BridgeIDBIndex implements IDBIndex {
key = BridgeIDBKeyRange._valueToKeyRange(key);
}
- const getReq: RecordGetRequest = {
+ const getReq: IndexGetQuery = {
direction: "next",
indexName: this._name,
limit: 1,
@@ -1318,7 +1353,7 @@ export class BridgeIDBIndex implements IDBIndex {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, getReq);
+ const result = await this._backend.getIndexRecords(btx, getReq);
if (result.count == 0) {
return undefined;
}
@@ -1351,7 +1386,7 @@ export class BridgeIDBIndex implements IDBIndex {
count = -1;
}
- const getReq: RecordGetRequest = {
+ const getReq: IndexGetQuery = {
direction: "next",
indexName: this._name,
limit: count,
@@ -1362,7 +1397,7 @@ export class BridgeIDBIndex implements IDBIndex {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, getReq);
+ const result = await this._backend.getIndexRecords(btx, getReq);
const primaryKeys = result.primaryKeys;
if (!primaryKeys) {
throw Error("invariant violated");
@@ -1388,7 +1423,7 @@ export class BridgeIDBIndex implements IDBIndex {
key = BridgeIDBKeyRange.only(valueToKey(key));
}
- const getReq: RecordGetRequest = {
+ const getReq: IndexGetQuery = {
direction: "next",
indexName: this._name,
limit: 1,
@@ -1399,7 +1434,7 @@ export class BridgeIDBIndex implements IDBIndex {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, getReq);
+ const result = await this._backend.getIndexRecords(btx, getReq);
return result.count;
};
@@ -1415,7 +1450,6 @@ export class BridgeIDBIndex implements IDBIndex {
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#range-concept
-/** @public */
export class BridgeIDBKeyRange {
public static only(value: IDBValidKey) {
if (arguments.length === 0) {
@@ -1525,10 +1559,8 @@ export class BridgeIDBKeyRange {
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
-/** @public */
export class BridgeIDBObjectStore implements IDBObjectStore {
- _indexesCache: Map<string, BridgeIDBIndex> = new Map();
-
+ _indexHandlesCache: Map<string, BridgeIDBIndex> = new Map();
_transaction: BridgeIDBTransaction;
/**
@@ -1536,41 +1568,43 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
*/
_debugName: string | undefined = undefined;
+ // Was the object store (not the handle, but the underlying store)
+ // created in this upgrade transaction?
_justCreated: boolean = false;
+ _originalName: string | undefined = undefined;
+ _objectStoreMeta: ObjectStoreMeta;
+
get transaction(): IDBTransaction {
return this._transaction;
}
get autoIncrement(): boolean {
- return this._schema.objectStores[this._name].autoIncrement;
- }
-
- get _indexNames(): FakeDOMStringList {
- return fakeDOMStringList(
- Object.keys(this._schema.objectStores[this._name].indexes),
- ).sort();
+ return this._objectStoreMeta.autoIncrement;
}
get indexNames(): DOMStringList {
- return this._indexNames as DOMStringList;
+ return fakeDOMStringList([...this._objectStoreMeta.indexSet]);
}
get keyPath(): IDBKeyPath | IDBKeyPath[] {
- return this._schema.objectStores[this._name].keyPath!;
+ // Bug in th official type declarations. The spec
+ // allows returning null here.
+ return this._objectStoreMeta.keyPath!;
}
_name: string;
- get _schema(): Schema {
- return this._transaction._db._schema;
- }
-
_deleted: boolean = false;
- constructor(transaction: BridgeIDBTransaction, name: string) {
+ constructor(
+ transaction: BridgeIDBTransaction,
+ name: string,
+ objectStoreMeta: ObjectStoreMeta,
+ ) {
this._name = name;
this._transaction = transaction;
+ this._objectStoreMeta = objectStoreMeta;
}
get name() {
@@ -1620,26 +1654,56 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
let { btx } = this._confirmStartedBackendTransaction();
newName = String(newName);
-
const oldName = this._name;
-
if (newName === oldName) {
return;
}
-
+ if (this._originalName == null) {
+ this._originalName = this._name;
+ }
this._backend.renameObjectStore(btx, oldName, newName);
- this._transaction._db._schema =
- this._backend.getCurrentTransactionSchema(btx);
+ this._applyNameChange(oldName, newName);
+ }
+ _applyNameChange(oldName: string, newName: string) {
+ this._transaction._scope.delete(oldName);
+ this._transaction._scope.add(newName);
// We don't modify scope, as the scope of the transaction
// doesn't matter if we're in an upgrade transaction.
this._transaction._objectStoresCache.delete(oldName);
this._transaction._objectStoresCache.set(newName, this);
this._transaction._cachedObjectStoreNames = undefined;
-
+ const objectStoreSet = this._transaction._db._objectStoreSet;
+ const oldIdx = objectStoreSet.indexOf(oldName);
+ objectStoreSet[oldIdx] = newName;
+ objectStoreSet.sort();
this._name = newName;
}
+ _applyDelete() {
+ this._deleted = true;
+ this._transaction._objectStoresCache.delete(this._name);
+ this._transaction._cachedObjectStoreNames = undefined;
+ const objectStoreSet = this._transaction._db._objectStoreSet;
+ const oldIdx = objectStoreSet.indexOf(this._name);
+ objectStoreSet.splice(oldIdx, 1);
+ }
+
+ /**
+ * Roll back changes to the handle after an abort.
+ */
+ _abort() {
+ if (this._originalName != null) {
+ this._applyNameChange(this._name, this._originalName);
+ }
+ if (this._justCreated) {
+ this._applyDelete();
+ }
+ }
+
+ /**
+ * "To add or put with handle, value, key, and no-overwrite flag, run these steps:"
+ */
public _store(value: any, key: IDBValidKey | undefined, overwrite: boolean) {
if (BridgeIDBFactory.enableTracing) {
console.log(
@@ -1647,6 +1711,12 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
);
}
+ if (this._deleted) {
+ throw new InvalidStateError(
+ "tried to call 'put' on a deleted object store",
+ );
+ }
+
if (!this._transaction._active) {
throw new TransactionInactiveError();
}
@@ -1655,14 +1725,21 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
throw new ReadOnlyError();
}
- const { keyPath, autoIncrement } = this._schema.objectStores[this._name];
+ const { keyPath, autoIncrement } = this._objectStoreMeta;
if (key !== null && key !== undefined) {
valueToKey(key);
}
// We only call this to synchronously verify the request.
- makeStoreKeyValue(value, key, 1, autoIncrement, keyPath);
+ // FIXME: The backend should do that!
+ makeStoreKeyValue({
+ value: value,
+ key: key,
+ currentKeyGenerator: 1,
+ autoIncrement,
+ keyPath,
+ });
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
@@ -1684,11 +1761,6 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
if (arguments.length === 0) {
throw new TypeError();
}
- if (this._deleted) {
- throw new InvalidStateError(
- "tried to call 'put' on a deleted object store",
- );
- }
return this._store(value, key, true);
}
@@ -1696,9 +1768,6 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
if (arguments.length === 0) {
throw new TypeError();
}
- if (!this._schema.objectStores[this._name]) {
- throw new InvalidStateError("object store does not exist");
- }
return this._store(value, key, false);
}
@@ -1767,10 +1836,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
}
}
- const recordRequest: RecordGetRequest = {
+ const recordRequest: ObjectStoreGetQuery = {
objectStoreName: this._name,
- indexName: undefined,
- lastIndexPosition: undefined,
lastObjectStorePosition: undefined,
direction: "next",
limit: 1,
@@ -1783,7 +1850,10 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
console.log("running get operation:", recordRequest);
}
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, recordRequest);
+ const result = await this._backend.getObjectStoreRecords(
+ btx,
+ recordRequest,
+ );
if (BridgeIDBFactory.enableTracing) {
console.log("get operation result count:", result.count);
@@ -1833,10 +1903,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
let keyRange: BridgeIDBKeyRange | null = simplifyRange(query);
- const recordRequest: RecordGetRequest = {
+ const recordRequest: ObjectStoreGetQuery = {
objectStoreName: this._name,
- indexName: undefined,
- lastIndexPosition: undefined,
lastObjectStorePosition: undefined,
direction: "next",
limit: count,
@@ -1849,7 +1917,10 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
console.log("running getAll operation:", recordRequest);
}
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, recordRequest);
+ const result = await this._backend.getObjectStoreRecords(
+ btx,
+ recordRequest,
+ );
if (BridgeIDBFactory.enableTracing) {
console.log("get operation result count:", result.count);
@@ -1887,10 +1958,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
let keyRange: BridgeIDBKeyRange | null = simplifyRange(query);
- const recordRequest: RecordGetRequest = {
+ const recordRequest: ObjectStoreGetQuery = {
objectStoreName: this._name,
- indexName: undefined,
- lastIndexPosition: undefined,
lastObjectStorePosition: undefined,
direction: "next",
limit: 1,
@@ -1903,7 +1972,10 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
console.log("running getKey operation:", recordRequest);
}
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, recordRequest);
+ const result = await this._backend.getObjectStoreRecords(
+ btx,
+ recordRequest,
+ );
if (BridgeIDBFactory.enableTracing) {
console.log("getKey operation result count:", result.count);
@@ -1965,10 +2037,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
}
}
- const recordRequest: RecordGetRequest = {
+ const recordRequest: ObjectStoreGetQuery = {
objectStoreName: this._name,
- indexName: undefined,
- lastIndexPosition: undefined,
lastObjectStorePosition: undefined,
direction: "next",
limit: count,
@@ -1978,7 +2048,10 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, recordRequest);
+ const result = await this._backend.getObjectStoreRecords(
+ btx,
+ recordRequest,
+ );
const primaryKeys = result.primaryKeys;
if (!primaryKeys) {
@@ -2121,7 +2194,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
throw new InvalidStateError();
}
- if (this._indexNames.indexOf(indexName) >= 0) {
+ if (this._objectStoreMeta.indexSet.indexOf(indexName) >= 0) {
throw new ConstraintError();
}
@@ -2140,6 +2213,9 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
unique,
);
+ this._objectStoreMeta.indexSet.push(indexName);
+ this._objectStoreMeta.indexSet.sort();
+
const idx = this.index(indexName);
idx._justCreated = true;
return idx;
@@ -2154,13 +2230,20 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
if (this._transaction._finished) {
throw new InvalidStateError();
}
-
- const index = this._indexesCache.get(name);
+ const index = this._indexHandlesCache.get(name);
if (index !== undefined) {
return index;
}
- const newIndex = new BridgeIDBIndex(this, name);
- this._indexesCache.set(name, newIndex);
+ const indexMeta = this._backend.getIndexMeta(
+ this._backendConnection,
+ this._name,
+ name,
+ );
+ if (!indexMeta) {
+ throw new NotFoundError();
+ }
+ const newIndex = new BridgeIDBIndex(this, name, indexMeta);
+ this._indexHandlesCache.set(name, newIndex);
this._transaction._usedIndexes.push(newIndex);
return newIndex;
}
@@ -2180,12 +2263,15 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
const { btx } = this._confirmStartedBackendTransaction();
- const index = this._indexesCache.get(indexName);
+ const index = this._indexHandlesCache.get(indexName);
if (index !== undefined) {
index._deleted = true;
- this._indexesCache.delete(indexName);
+ this._indexHandlesCache.delete(indexName);
}
+ const indexIdx = this._objectStoreMeta.indexSet.indexOf(indexName);
+ this._objectStoreMeta.indexSet.splice(indexIdx, 1);
+
this._backend.deleteIndex(btx, this._name, indexName);
}
@@ -2198,11 +2284,9 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
key = BridgeIDBKeyRange.only(valueToKey(key));
}
- const recordGetRequest: RecordGetRequest = {
+ const recordGetRequest: ObjectStoreGetQuery = {
direction: "next",
- indexName: undefined,
- lastIndexPosition: undefined,
- limit: -1,
+ limit: 0,
objectStoreName: this._name,
lastObjectStorePosition: undefined,
range: key,
@@ -2211,7 +2295,10 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
const operation = async () => {
const { btx } = this._confirmStartedBackendTransaction();
- const result = await this._backend.getRecords(btx, recordGetRequest);
+ const result = await this._backend.getObjectStoreRecords(
+ btx,
+ recordGetRequest,
+ );
return result.count;
};
@@ -2223,7 +2310,6 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
}
}
-/** @public */
export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
_result: any = null;
_error: Error | null | undefined = null;
@@ -2294,7 +2380,6 @@ export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
}
}
-/** @public */
export class BridgeIDBOpenDBRequest
extends BridgeIDBRequest
implements IDBOpenDBRequest
@@ -2343,7 +2428,6 @@ function waitMacroQueue(): Promise<void> {
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
-/** @public */
export class BridgeIDBTransaction
extends FakeEventTarget
implements IDBTransaction
@@ -2390,13 +2474,9 @@ export class BridgeIDBTransaction
get objectStoreNames(): DOMStringList {
if (!this._cachedObjectStoreNames) {
- if (this._openRequest) {
- this._cachedObjectStoreNames = this._db.objectStoreNames;
- } else {
- this._cachedObjectStoreNames = fakeDOMStringList(
- Array.from(this._scope).sort(),
- );
- }
+ this._cachedObjectStoreNames = fakeDOMStringList(
+ Array.from(this._scope).sort(),
+ );
}
return this._cachedObjectStoreNames;
}
@@ -2496,41 +2576,34 @@ export class BridgeIDBTransaction
}
}
+ // All steps before happened synchronously. Now
+ // we asynchronously roll back the backend transaction,
+ // if necessary/possible.
+
+ const maybeBtx = this._backendTransaction;
+ if (maybeBtx) {
+ this._backend.rollback(maybeBtx);
+ }
+
// "Any object stores and indexes which were created during the
// transaction are now considered deleted for the purposes of other
// algorithms."
if (this._db._upgradeTransaction) {
for (const os of this._usedObjectStores) {
- if (os._justCreated) {
- os._deleted = true;
- }
+ os._abort();
}
for (const ind of this._usedIndexes) {
- if (ind._justCreated) {
- ind._deleted = true;
- }
+ ind._abort();
}
}
+ this._db._version = this._db._initialVersion;
+
// ("abort a transaction", step 5.1)
if (this._openRequest) {
this._db._upgradeTransaction = null;
}
- // All steps before happened synchronously. Now
- // we asynchronously roll back the backend transaction,
- // if necessary/possible.
-
- const maybeBtx = this._backendTransaction;
- if (maybeBtx) {
- this._db._schema = this._backend.getInitialTransactionSchema(maybeBtx);
- // Only roll back if we actually executed the scheduled operations.
- await this._backend.rollback(maybeBtx);
- this._backendTransaction = undefined;
- } else {
- this._db._schema = this._backend.getSchema(this._db._backendConnection);
- }
-
queueTask(() => {
const event = new FakeEvent("abort", {
bubbles: true,
@@ -2560,22 +2633,29 @@ export class BridgeIDBTransaction
throw new TransactionInactiveError();
}
- if (!this._db._schema.objectStores[name]) {
+ if (!this._scope.has(name)) {
throw new NotFoundError();
}
- if (!this._db._upgradeTransaction) {
- if (!this._scope.has(name)) {
- throw new NotFoundError();
- }
- }
-
const objectStore = this._objectStoresCache.get(name);
if (objectStore !== undefined) {
return objectStore;
}
- const newObjectStore = new BridgeIDBObjectStore(this, name);
+ const objectStoreMeta = this._backend.getObjectStoreMeta(
+ this._db._backendConnection,
+ name,
+ );
+
+ if (!objectStoreMeta) {
+ throw new NotFoundError();
+ }
+
+ const newObjectStore = new BridgeIDBObjectStore(
+ this,
+ name,
+ objectStoreMeta,
+ );
this._objectStoresCache.set(name, newObjectStore);
this._usedObjectStores.push(newObjectStore);
return newObjectStore;