idb-bridge: test cases, package structure and missing functionality

This commit is contained in:
Florian Dold 2019-07-31 01:33:23 +02:00
parent 16ecbc9f17
commit bcefbd7aab
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
13 changed files with 407 additions and 92 deletions

View File

@ -0,0 +1,3 @@
{
"editor.tabSize": 2
}

View File

@ -42,12 +42,14 @@ import {
Backend,
DatabaseTransaction,
RecordStoreRequest,
StoreLevel,
} from "./backend-interface";
import BridgeIDBFactory from "./BridgeIDBFactory";
/**
* http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
*/
class BridgeIDBCursor {
export class BridgeIDBCursor {
_request: BridgeIDBRequest | undefined;
private _gotValue: boolean = false;
@ -119,14 +121,24 @@ class BridgeIDBCursor {
get primaryKey() {
return this._primaryKey;
}
set primaryKey(val) {
/* For babel */
}
protected get _isValueCursor(): boolean {
return false;
}
/**
* https://w3c.github.io/IndexedDB/#iterate-a-cursor
*/
async _iterate(key?: Key, primaryKey?: Key): Promise<any> {
BridgeIDBFactory.enableTracing &&
console.log(
`iterating cursor os=${this._objectStoreName},idx=${this._indexName}`,
);
BridgeIDBFactory.enableTracing && console.log("cursor type ", this.toString());
const recordGetRequest: RecordGetRequest = {
direction: this.direction,
indexName: this._indexName,
@ -145,7 +157,10 @@ class BridgeIDBCursor {
let response = await this._backend.getRecords(btx, recordGetRequest);
if (response.count === 0) {
console.log("cursor is returning empty result");
if (BridgeIDBFactory.enableTracing) {
console.log("cursor is returning empty result");
}
this._gotValue = false;
return null;
}
@ -153,8 +168,10 @@ class BridgeIDBCursor {
throw Error("invariant failed");
}
console.log("request is:", JSON.stringify(recordGetRequest));
console.log("get response is:", JSON.stringify(response));
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];
@ -204,20 +221,23 @@ class BridgeIDBCursor {
throw new InvalidStateError();
}
if (!this._gotValue || !this.hasOwnProperty("value")) {
if (!this._gotValue || !this._isValueCursor) {
throw new InvalidStateError();
}
const storeReq: RecordStoreRequest = {
overwrite: true,
key: this._primaryKey,
value: value,
objectStoreName: this._objectStoreName,
storeLevel: StoreLevel.UpdateExisting,
};
const operation = async () => {
if (BridgeIDBFactory.enableTracing) {
console.log("updating at cursor")
}
const { btx } = this.source._confirmActiveTransaction();
this._backend.storeRecord(btx, storeReq);
await this._backend.storeRecord(btx, storeReq);
};
return transaction._execRequestAsync({
operation,
@ -318,7 +338,7 @@ class BridgeIDBCursor {
throw new InvalidStateError();
}
if (!this._gotValue || !this.hasOwnProperty("value")) {
if (!this._gotValue || !this._isValueCursor) {
throw new InvalidStateError();
}

View File

@ -16,32 +16,35 @@
import BridgeIDBCursor from "./BridgeIDBCursor";
import {
CursorRange,
CursorSource,
BridgeIDBCursorDirection,
Value,
CursorRange,
CursorSource,
BridgeIDBCursorDirection,
Value,
} from "./util/types";
class BridgeIDBCursorWithValue extends BridgeIDBCursor {
get value(): Value {
return this._value;
}
get value(): Value {
return this._value;
}
constructor(
source: CursorSource,
objectStoreName: string,
indexName: string | undefined,
range: CursorRange,
direction: BridgeIDBCursorDirection,
request?: any,
) {
super(source, objectStoreName, indexName, range, direction, request, false);
}
protected get _isValueCursor(): boolean {
return true;
}
public toString() {
return "[object IDBCursorWithValue]";
}
constructor(
source: CursorSource,
objectStoreName: string,
indexName: string | undefined,
range: CursorRange,
direction: BridgeIDBCursorDirection,
request?: any,
) {
super(source, objectStoreName, indexName, range, direction, request, false);
}
public toString() {
return "[object IDBCursorWithValue]";
}
}
export default BridgeIDBCursorWithValue;

View File

@ -50,7 +50,7 @@ const confirmActiveTransaction = (
};
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
class BridgeIDBIndex {
export class BridgeIDBIndex {
objectStore: BridgeIDBObjectStore;
get _schema(): Schema {

View File

@ -113,21 +113,20 @@ class BridgeIDBKeyRange {
static _valueToKeyRange(value: any, nullDisallowedFlag: boolean = false) {
if (value instanceof BridgeIDBKeyRange) {
return value;
return value;
}
if (value === null || value === undefined) {
if (nullDisallowedFlag) {
throw new DataError();
}
return new BridgeIDBKeyRange(undefined, undefined, false, false);
if (nullDisallowedFlag) {
throw new DataError();
}
return new BridgeIDBKeyRange(undefined, undefined, false, false);
}
const key = valueToKey(value);
return BridgeIDBKeyRange.only(key);
}
}
export default BridgeIDBKeyRange;

View File

@ -46,6 +46,7 @@ import {
DatabaseTransaction,
RecordGetRequest,
ResultLevel,
StoreLevel,
} from "./backend-interface";
import BridgeIDBFactory from "./BridgeIDBFactory";
@ -137,7 +138,7 @@ class BridgeIDBObjectStore {
objectStoreName: this._name,
key: key,
value: value,
overwrite,
storeLevel: overwrite ? StoreLevel.AllowOverwrite : StoreLevel.NoOverwrite,
});
};
@ -158,7 +159,7 @@ class BridgeIDBObjectStore {
return this._store(value, key, false);
}
public delete(key: Key) {
public delete(key: Key | BridgeIDBKeyRange) {
if (arguments.length === 0) {
throw new TypeError();
}
@ -167,13 +168,17 @@ class BridgeIDBObjectStore {
throw new ReadOnlyError();
}
if (!(key instanceof BridgeIDBKeyRange)) {
key = valueToKey(key);
let keyRange: BridgeIDBKeyRange;
if (key instanceof BridgeIDBKeyRange) {
keyRange = key;
} else {
keyRange = BridgeIDBKeyRange.only(valueToKey(key));
}
const operation = async () => {
const { btx } = this._confirmActiveTransaction();
return this._backend.deleteRecord(btx, this._name, key);
return this._backend.deleteRecord(btx, this._name, keyRange);
}
return this.transaction._execRequestAsync({
@ -183,12 +188,20 @@ class BridgeIDBObjectStore {
}
public get(key?: BridgeIDBKeyRange | Key) {
if (BridgeIDBFactory.enableTracing) {
console.log(`getting from object store ${this._name} key ${key}`);
}
if (arguments.length === 0) {
throw new TypeError();
}
if (!(key instanceof BridgeIDBKeyRange)) {
key = valueToKey(key);
let keyRange: BridgeIDBKeyRange;
if (key instanceof BridgeIDBKeyRange) {
keyRange = key;
} else {
keyRange = BridgeIDBKeyRange.only(valueToKey(key));
}
const recordRequest: RecordGetRequest = {
@ -199,16 +212,24 @@ class BridgeIDBObjectStore {
direction: "next",
limit: 1,
resultLevel: ResultLevel.Full,
range: key,
range: keyRange,
};
const operation = async () => {
if (BridgeIDBFactory.enableTracing) {
console.log("running get operation:", recordRequest);
}
const { btx } = this._confirmActiveTransaction();
const result = await this._backend.getRecords(
btx,
recordRequest,
);
if (result.count == 0) {
if (BridgeIDBFactory.enableTracing) {
console.log("get operation result count:", result.count);
}
if (result.count === 0) {
return undefined;
}
const values = result.values;

View File

@ -174,12 +174,12 @@ class BridgeIDBTransaction extends FakeEventTarget {
*/
public async _start() {
if (BridgeIDBFactory.enableTracing) {
console.log(`TRACE: IDBTransaction._start, ${this._requests.length} queued`);
console.log(
`TRACE: IDBTransaction._start, ${this._requests.length} queued`,
);
}
this._started = true;
console.log("beginning transaction");
if (!this._backendTransaction) {
this._backendTransaction = await this._backend.beginTransaction(
this.db._backendConnection,
@ -188,8 +188,6 @@ class BridgeIDBTransaction extends FakeEventTarget {
);
}
console.log("beginTransaction completed");
// Remove from request queue - cursor ones will be added back if necessary by cursor.continue and such
let operation;
let request;
@ -208,16 +206,17 @@ class BridgeIDBTransaction extends FakeEventTarget {
if (!request.source) {
// Special requests like indexes that just need to run some code, with error handling already built into
// operation
console.log("running operation without source");
await operation();
} else {
console.log("running operation with source");
let event;
try {
BridgeIDBFactory.enableTracing &&
console.log("TRACE: running operation in transaction");
const result = await operation();
if (BridgeIDBFactory.enableTracing) {
console.log("TRACE: tx operation finished with success");
}
BridgeIDBFactory.enableTracing &&
console.log(
"TRACE: operation in transaction finished with success",
);
request.readyState = "done";
request.result = result;
request.error = undefined;
@ -295,7 +294,7 @@ class BridgeIDBTransaction extends FakeEventTarget {
if (!this.error) {
if (BridgeIDBFactory.enableTracing) {
console.log("dispatching 'complete' event");
console.log("dispatching 'complete' event on transaction");
}
const event = new FakeEvent("complete");
event.eventPath = [this, this.db];

View File

@ -235,3 +235,60 @@ test("Spec: Example 1 Part 3", async t => {
t.pass();
});
test("simple deletion", async t => {
const backend = new MemoryBackend();
const idb = new BridgeIDBFactory(backend);
const request = idb.open("library");
request.onupgradeneeded = () => {
const db = request.result;
const store = db.createObjectStore("books", { keyPath: "isbn" });
const titleIndex = store.createIndex("by_title", "title", { unique: true });
const authorIndex = store.createIndex("by_author", "author");
};
const db: BridgeIDBDatabase = await promiseFromRequest(request);
t.is(db.name, "library");
const tx = db.transaction("books", "readwrite");
tx.oncomplete = () => {
console.log("oncomplete called");
};
const store = tx.objectStore("books");
store.put({ title: "Quarry Memories", author: "Fred", isbn: 123456 });
store.put({ title: "Water Buffaloes", author: "Fred", isbn: 234567 });
store.put({ title: "Bedrock Nights", author: "Barney", isbn: 345678 });
await promiseFromTransaction(tx);
const tx2 = db.transaction("books", "readwrite");
const store2 = tx2.objectStore("books");
const req1 = store2.get(234567);
await promiseFromRequest(req1);
t.is(req1.readyState, "done");
t.is(req1.result.author, "Fred");
store2.delete(123456);
const req2 = store2.get(123456);
await promiseFromRequest(req2);
t.is(req2.readyState, "done");
t.is(req2.result, undefined);
const req3 = store2.get(234567);
await promiseFromRequest(req3);
t.is(req3.readyState, "done");
t.is(req3.result.author, "Fred");
await promiseFromTransaction(tx2);
t.pass();
});

View File

@ -8,6 +8,7 @@ import {
RecordGetRequest,
RecordGetResponse,
ResultLevel,
StoreLevel,
} from "./backend-interface";
import structuredClone from "./util/structuredClone";
import {
@ -655,10 +656,10 @@ export class MemoryBackend implements Backend {
async deleteRecord(
btx: DatabaseTransaction,
objectStoreName: string,
range: import("./BridgeIDBKeyRange").default,
range: BridgeIDBKeyRange,
): Promise<void> {
if (this.enableTracing) {
console.log(`TRACING: deleteRecord`);
console.log(`TRACING: deleteRecord from store ${objectStoreName}`);
}
const myConn = this.connectionsByTransaction[btx.transactionCookie];
if (!myConn) {
@ -671,7 +672,112 @@ export class MemoryBackend implements Backend {
if (db.txLevel < TransactionLevel.Write) {
throw Error("only allowed in write transaction");
}
throw Error("not implemented");
if (typeof range !== "object") {
throw Error("deleteRecord got invalid range (must be object)");
}
if (!("lowerOpen" in range)) {
throw Error("deleteRecord got invalid range (sanity check failed, 'lowerOpen' missing)");
}
const schema = myConn.modifiedSchema
? myConn.modifiedSchema
: db.committedSchema;
const objectStore = myConn.objectStoreMap[objectStoreName];
if (!objectStore.modifiedData) {
objectStore.modifiedData = objectStore.originalData;
}
let modifiedData = objectStore.modifiedData;
let currKey: Key | undefined;
if (range.lower === undefined || range.lower === null) {
currKey = modifiedData.minKey();
} else {
currKey = range.lower;
// We have a range with an lowerOpen lower bound, so don't start
// deleting the upper bound. Instead start with the next higher key.
if (range.lowerOpen && currKey !== undefined) {
currKey = modifiedData.nextHigherKey(currKey);
}
}
// invariant: (currKey is undefined) or (currKey is a valid key)
while (true) {
if (currKey === undefined) {
// nothing more to delete!
break;
}
if (range.upper !== null && range.upper !== undefined) {
if (range.upperOpen && compareKeys(currKey, range.upper) === 0) {
// We have a range that's upperOpen, so stop before we delete the upper bound.
break;
}
if ((!range.upperOpen) && compareKeys(currKey, range.upper) > 0) {
// The upper range is inclusive, only stop if we're after the upper range.
break;
}
}
const storeEntry = modifiedData.get(currKey);
if (!storeEntry) {
throw Error("assertion failed");
}
for (const indexName of schema.objectStores[objectStoreName].indexes) {
const index = myConn.indexMap[indexName];
if (!index) {
throw Error("index referenced by object store does not exist");
}
const indexProperties = schema.indexes[indexName];
this.deleteFromIndex(index, storeEntry.primaryKey, storeEntry.value, indexProperties);
}
modifiedData = modifiedData.without(currKey);
currKey = modifiedData.nextHigherKey(currKey);
}
objectStore.modifiedData = modifiedData;
}
private deleteFromIndex(
index: Index,
primaryKey: Key,
value: Value,
indexProperties: IndexProperties,
): void {
if (this.enableTracing) {
console.log(
`deleteFromIndex(${index.modifiedName || index.originalName})`,
);
}
if (value === undefined || value === null) {
throw Error("cannot delete null/undefined value from index");
}
let indexData = index.modifiedData || index.originalData;
const indexKeys = getIndexKeys(
value,
indexProperties.keyPath,
indexProperties.multiEntry,
);
for (const indexKey of indexKeys) {
const existingRecord = indexData.get(indexKey);
if (!existingRecord) {
throw Error("db inconsistent: expected index entry missing");
}
const newPrimaryKeys = existingRecord.primaryKeys.filter((x) => compareKeys(x, primaryKey) !== 0);
if (newPrimaryKeys.length === 0) {
index.originalData = indexData.without(indexKey);
} else {
const newIndexRecord = {
indexKey,
primaryKeys: newPrimaryKeys,
}
index.modifiedData = indexData.with(indexKey, newIndexRecord, true);
}
}
}
async getRecords(
@ -705,6 +811,18 @@ export class MemoryBackend implements Backend {
range = req.range;
}
if (typeof range !== "object") {
throw Error(
"getRecords was given an invalid range (sanity check failed, not an object)",
);
}
if (!("lowerOpen" in range)) {
throw Error(
"getRecords was given an invalid range (sanity check failed, lowerOpen missing)",
);
}
let numResults = 0;
let indexKeys: Key[] = [];
let primaryKeys: Key[] = [];
@ -779,20 +897,21 @@ export class MemoryBackend implements Backend {
compareKeys(indexEntry.indexKey, req.lastIndexPosition) === 0
) {
let pos = forward ? 0 : indexEntry.primaryKeys.length - 1;
console.log("number of primary keys", indexEntry.primaryKeys.length);
console.log("start pos is", pos);
this.enableTracing &&
console.log("number of primary keys", indexEntry.primaryKeys.length);
this.enableTracing && console.log("start pos is", pos);
// Advance past the lastObjectStorePosition
do {
const cmpResult = compareKeys(
req.lastObjectStorePosition,
indexEntry.primaryKeys[pos],
);
console.log("cmp result is", cmpResult);
this.enableTracing && console.log("cmp result is", cmpResult);
if ((forward && cmpResult < 0) || (!forward && cmpResult > 0)) {
break;
}
pos += forward ? 1 : -1;
console.log("now pos is", pos);
this.enableTracing && console.log("now pos is", pos);
} while (pos >= 0 && pos < indexEntry.primaryKeys.length);
// Make sure we're at least at advancedPrimaryPos
@ -815,8 +934,10 @@ export class MemoryBackend implements Backend {
primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
}
console.log("subPos=", primkeySubPos);
console.log("indexPos=", indexPos);
if (this.enableTracing) {
console.log("subPos=", primkeySubPos);
console.log("indexPos=", indexPos);
}
while (1) {
if (req.limit != 0 && numResults == req.limit) {
@ -867,12 +988,16 @@ export class MemoryBackend implements Backend {
}
}
if (!skip) {
console.log(`not skipping!, subPos=${primkeySubPos}`);
if (this.enableTracing) {
console.log(`not skipping!, subPos=${primkeySubPos}`);
}
indexKeys.push(indexEntry.indexKey);
primaryKeys.push(indexEntry.primaryKeys[primkeySubPos]);
numResults++;
} else {
console.log("skipping!");
if (this.enableTracing) {
console.log("skipping!");
}
}
primkeySubPos += forward ? 1 : -1;
}
@ -885,7 +1010,7 @@ export class MemoryBackend implements Backend {
if (!result) {
throw Error("invariant violated");
}
values.push(result);
values.push(result.value);
}
}
} else {
@ -905,7 +1030,9 @@ export class MemoryBackend implements Backend {
// Advance store position if we are either still at the last returned
// store key, or if we are currently not on a key.
const storeEntry = storeData.get(storePos);
console.log("store entry:", storeEntry);
if (this.enableTracing) {
console.log("store entry:", storeEntry);
}
if (
!storeEntry ||
(req.lastObjectStorePosition !== undefined &&
@ -915,7 +1042,9 @@ export class MemoryBackend implements Backend {
}
} else {
storePos = forward ? storeData.minKey() : storeData.maxKey();
console.log("setting starting store store pos to", storePos);
if (this.enableTracing) {
console.log("setting starting store pos to", storePos);
}
}
while (1) {
@ -940,7 +1069,7 @@ export class MemoryBackend implements Backend {
}
if (req.resultLevel >= ResultLevel.Full) {
values.push(res);
values.push(res.value);
}
numResults++;
@ -983,30 +1112,50 @@ export class MemoryBackend implements Backend {
const schema = myConn.modifiedSchema
? myConn.modifiedSchema
: db.committedSchema;
const objectStore = myConn.objectStoreMap[storeReq.objectStoreName];
const storeKeyResult: StoreKeyResult = makeStoreKeyValue(
storeReq.value,
storeReq.key,
objectStore.modifiedKeyGenerator || objectStore.originalKeyGenerator,
schema.objectStores[storeReq.objectStoreName].autoIncrement,
schema.objectStores[storeReq.objectStoreName].keyPath,
);
let key = storeKeyResult.key;
let value = storeKeyResult.value;
objectStore.modifiedKeyGenerator = storeKeyResult.updatedKeyGenerator;
if (!objectStore.modifiedData) {
objectStore.modifiedData = objectStore.originalData;
}
const modifiedData = objectStore.modifiedData;
const hasKey = modifiedData.has(key);
if (hasKey && !storeReq.overwrite) {
throw Error("refusing to overwrite");
let key;
let value;
if (storeReq.storeLevel === StoreLevel.UpdateExisting) {
if (storeReq.key === null || storeReq.key === undefined) {
throw Error("invalid update request (key not given)");
}
if (!objectStore.modifiedData.has(storeReq.key)) {
throw Error("invalid update request (record does not exist)");
}
key = storeReq.key;
value = storeReq.value;
} else {
const storeKeyResult: StoreKeyResult = makeStoreKeyValue(
storeReq.value,
storeReq.key,
objectStore.modifiedKeyGenerator || objectStore.originalKeyGenerator,
schema.objectStores[storeReq.objectStoreName].autoIncrement,
schema.objectStores[storeReq.objectStoreName].keyPath,
);
key = storeKeyResult.key;
value = storeKeyResult.value;
objectStore.modifiedKeyGenerator = storeKeyResult.updatedKeyGenerator;
const hasKey = modifiedData.has(key);
if (hasKey && storeReq.storeLevel !== StoreLevel.AllowOverwrite) {
throw Error("refusing to overwrite");
}
}
objectStore.modifiedData = modifiedData.with(key, value, true);
const objectStoreRecord: ObjectStoreRecord = {
primaryKey: key,
value: value,
};
objectStore.modifiedData = modifiedData.with(key, objectStoreRecord, true);
for (const indexName of schema.objectStores[storeReq.objectStoreName]
.indexes) {

View File

@ -41,6 +41,12 @@ export enum ResultLevel {
Full,
}
export enum StoreLevel {
NoOverwrite,
AllowOverwrite,
UpdateExisting,
}
export interface RecordGetRequest {
direction: BridgeIDBCursorDirection;
objectStoreName: string;
@ -94,7 +100,7 @@ export interface RecordStoreRequest {
objectStoreName: string;
value: Value;
key: Key | undefined;
overwrite: boolean;
storeLevel: StoreLevel;
}
export interface Backend {

View File

@ -0,0 +1,60 @@
import { BridgeIDBFactory } from "./BridgeIDBFactory";
import { BridgeIDBCursor } from "./BridgeIDBCursor";
import { BridgeIDBIndex } from "./BridgeIDBIndex";
import BridgeIDBDatabase from "./BridgeIDBDatabase";
import BridgeIDBKeyRange from "./BridgeIDBKeyRange";
import BridgeIDBObjectStore from "./BridgeIDBObjectStore";
import BridgeIDBOpenDBRequest from "./BridgeIDBOpenDBRequest";
import BridgeIDBRequest from "./BridgeIDBRequest";
import BridgeIDBTransaction from "./BridgeIDBTransaction";
import BridgeIDBVersionChangeEvent from "./BridgeIDBVersionChangeEvent";
export { BridgeIDBFactory, BridgeIDBCursor };
export { MemoryBackend } from "./MemoryBackend";
// globalThis polyfill, see https://mathiasbynens.be/notes/globalthis
(function() {
if (typeof globalThis === "object") return;
Object.defineProperty(Object.prototype, "__magic__", {
get: function() {
return this;
},
configurable: true, // This makes it possible to `delete` the getter later.
});
// @ts-ignore: polyfill magic
__magic__.globalThis = __magic__; // lolwat
// @ts-ignore: polyfill magic
delete Object.prototype.__magic__;
})();
/**
* Populate the global name space such that the given IndexedDB factory is made
* available globally.
*/
export function shimIndexedDB(factory: BridgeIDBFactory): void {
// @ts-ignore: shimming
globalThis.indexedDB = factory;
// @ts-ignore: shimming
globalThis.IDBCursor = BridgeIDBCursor;
// @ts-ignore: shimming
globalThis.IDBKeyRange = BridgeIDBKeyRange;
// @ts-ignore: shimming
globalThis.IDBDatabase = BridgeIDBDatabase;
// @ts-ignore: shimming
globalThis.IDBFactory = BridgeIDBFactory;
// @ts-ignore: shimming
globalThis.IDBIndex = BridgeIDBIndex;
// @ts-ignore: shimming
globalThis.IDBKeyRange = BridgeIDBKeyRange;
// @ts-ignore: shimming
globalThis.IDBObjectStore = BridgeIDBObjectStore;
// @ts-ignore: shimming
globalThis.IDBOpenDBRequest = BridgeIDBOpenDBRequest;
// @ts-ignore: shimming
globalThis.IDBRequest = BridgeIDBRequest;
// @ts-ignore: shimming
globalThis.IDBTransaction = BridgeIDBTransaction;
// @ts-ignore: shimming
globalThis.IDBVersionChangeEvent = BridgeIDBVersionChangeEvent;
}

View File

@ -54,7 +54,6 @@ const invokeEventListeners = (event: FakeEvent, obj: FakeEventTarget) => {
continue;
}
console.log(`invoking ${event.type} event listener`, listener);
// @ts-ignore
listener.callback.call(event.currentTarget, event);
}
@ -81,7 +80,6 @@ const invokeEventListeners = (event: FakeEvent, obj: FakeEventTarget) => {
type: event.type,
};
if (!stopped(event, listener)) {
console.log(`invoking on${event.type} event listener`, listener);
// @ts-ignore
listener.callback.call(event.currentTarget, event);
}
@ -100,7 +98,7 @@ abstract class FakeEventTarget {
public readonly onupgradeneeded: EventCallback | null | undefined;
public readonly onversionchange: EventCallback | null | undefined;
static enableTracing: boolean = true;
static enableTracing: boolean = false;
public addEventListener(
type: EventType,

View File

@ -18,7 +18,7 @@ export function makeStoreKeyValue(
autoIncrement: boolean,
keyPath: KeyPath | null,
): StoreKeyResult {
const haveKey = key !== undefined && key !== null;
const haveKey = key !== null && key !== undefined;
const haveKeyPath = keyPath !== null && keyPath !== undefined;
// This models a decision table on (haveKey, haveKeyPath, autoIncrement)