Add initial stab at annotating Store

This commit is contained in:
Danila Fedorin 2021-08-10 15:31:54 -07:00
parent 2b44878332
commit 97a50c835d
2 changed files with 67 additions and 54 deletions

View file

@ -20,15 +20,15 @@ type Reducer<A,B> = (acc: B, val: A) => B
interface QueryTargetInterface<T> {
openCursor: (range?: IDBKeyRange | null , direction?: IDBCursorDirection) => IDBRequest<IDBCursorWithValue | null>
openKeyCursor: (range: IDBKeyRange, direction: IDBCursorDirection) => IDBRequest<IDBCursor | null>
openKeyCursor: (range?: IDBKeyRange, direction?: IDBCursorDirection) => IDBRequest<IDBCursor | null>
supports: (method: string) => boolean
keyPath: string
keyPath: string | string[]
get: (key: IDBValidKey) => IDBRequest<T | null>
getKey: (key: IDBValidKey) => IDBRequest<IDBValidKey | undefined>
}
export class QueryTarget<T> {
private _target: QueryTargetInterface<T>
protected _target: QueryTargetInterface<T>
constructor(target: QueryTargetInterface<T>) {
this._target = target;
@ -60,7 +60,11 @@ export class QueryTarget<T> {
} else {
return reqAsPromise(this._target.get(key)).then(value => {
if (value) {
return value[this._target.keyPath];
let keyPath = this._target.keyPath;
if (typeof keyPath === "string") {
keyPath = [keyPath];
}
return keyPath.reduce((obj, key) => obj[key], value);
}
});
}

View file

@ -19,126 +19,135 @@ import {IDBRequestAttemptError} from "./error";
const LOG_REQUESTS = false;
function logRequest(method, params, source) {
function logRequest(method: string, params: any[], source: any) {
const storeName = source?.name;
const databaseName = source?.transaction?.db?.name;
console.info(`${databaseName}.${storeName}.${method}(${params.map(p => JSON.stringify(p)).join(", ")})`);
}
class QueryTargetWrapper {
constructor(qt) {
class QueryTargetWrapper<T> {
private _qt: IDBIndex | IDBObjectStore
constructor(qt: IDBIndex | IDBObjectStore) {
this._qt = qt;
}
get keyPath() {
if (this._qt.objectStore) {
return this._qt.objectStore.keyPath;
get keyPath(): string | string[] {
if (this._qt["objectStore"]) {
return (this._qt as IDBIndex).objectStore.keyPath;
} else {
return this._qt.keyPath;
}
}
supports(methodName) {
get _qtStore(): IDBObjectStore {
return this._qt as IDBObjectStore;
}
supports(methodName: string): boolean {
return !!this._qt[methodName];
}
openKeyCursor(...params) {
openKeyCursor(range?: IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursor | null> {
try {
// not supported on Edge 15
if (!this._qt.openKeyCursor) {
LOG_REQUESTS && logRequest("openCursor", params, this._qt);
return this.openCursor(...params);
LOG_REQUESTS && logRequest("openCursor", [range, direction], this._qt);
return this.openCursor(range, direction);
}
LOG_REQUESTS && logRequest("openKeyCursor", params, this._qt);
return this._qt.openKeyCursor(...params);
LOG_REQUESTS && logRequest("openKeyCursor", [range, direction], this._qt);
return this._qt.openKeyCursor(range, direction)
} catch(err) {
throw new IDBRequestAttemptError("openKeyCursor", this._qt, err, params);
throw new IDBRequestAttemptError("openKeyCursor", this._qt, err, [range, direction]);
}
}
openCursor(...params) {
openCursor(range?: IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null> {
try {
LOG_REQUESTS && logRequest("openCursor", params, this._qt);
return this._qt.openCursor(...params);
LOG_REQUESTS && logRequest("openCursor", [], this._qt);
return this._qt.openCursor(range, direction)
} catch(err) {
throw new IDBRequestAttemptError("openCursor", this._qt, err, params);
throw new IDBRequestAttemptError("openCursor", this._qt, err, [range, direction]);
}
}
put(...params) {
put(item: T, key?: IDBValidKey): IDBRequest<IDBValidKey> {
try {
LOG_REQUESTS && logRequest("put", params, this._qt);
return this._qt.put(...params);
LOG_REQUESTS && logRequest("put", [item, key], this._qt);
return this._qtStore.put(item, key);
} catch(err) {
throw new IDBRequestAttemptError("put", this._qt, err, params);
throw new IDBRequestAttemptError("put", this._qt, err, [item, key]);
}
}
add(...params) {
add(item: T, key?: IDBValidKey): IDBRequest<IDBValidKey> {
try {
LOG_REQUESTS && logRequest("add", params, this._qt);
return this._qt.add(...params);
LOG_REQUESTS && logRequest("add", [item, key], this._qt);
return this._qtStore.add(item, key);
} catch(err) {
throw new IDBRequestAttemptError("add", this._qt, err, params);
throw new IDBRequestAttemptError("add", this._qt, err, [item, key]);
}
}
get(...params) {
get(key: IDBValidKey): IDBRequest<T> {
try {
LOG_REQUESTS && logRequest("get", params, this._qt);
return this._qt.get(...params);
LOG_REQUESTS && logRequest("get", [key], this._qt);
return this._qt.get(key);
} catch(err) {
throw new IDBRequestAttemptError("get", this._qt, err, params);
throw new IDBRequestAttemptError("get", this._qt, err, [key]);
}
}
getKey(...params) {
getKey(key: IDBValidKey): IDBRequest<IDBValidKey | undefined> {
try {
LOG_REQUESTS && logRequest("getKey", params, this._qt);
return this._qt.getKey(...params);
LOG_REQUESTS && logRequest("getKey", [key], this._qt);
return this._qt.getKey(key)
} catch(err) {
throw new IDBRequestAttemptError("getKey", this._qt, err, params);
throw new IDBRequestAttemptError("getKey", this._qt, err, [key]);
}
}
delete(...params) {
delete(key: IDBValidKey | IDBKeyRange): IDBRequest<undefined> {
try {
LOG_REQUESTS && logRequest("delete", params, this._qt);
return this._qt.delete(...params);
LOG_REQUESTS && logRequest("delete", [key], this._qt);
return this._qtStore.delete(key);
} catch(err) {
throw new IDBRequestAttemptError("delete", this._qt, err, params);
throw new IDBRequestAttemptError("delete", this._qt, err, [key]);
}
}
index(...params) {
index(name: string): IDBIndex {
try {
return this._qt.index(...params);
return this._qtStore.index(name);
} catch(err) {
// TODO: map to different error? this is not a request
throw new IDBRequestAttemptError("index", this._qt, err, params);
throw new IDBRequestAttemptError("index", this._qt, err, [name]);
}
}
}
export class Store extends QueryTarget {
constructor(idbStore, transaction) {
super(new QueryTargetWrapper(idbStore));
export class Store<T> extends QueryTarget<T> {
private _transaction: IDBTransaction
constructor(idbStore: IDBObjectStore, transaction: IDBTransaction) {
super(new QueryTargetWrapper<T>(idbStore));
this._transaction = transaction;
}
get IDBKeyRange() {
// @ts-ignore
return this._transaction.IDBKeyRange;
}
get _idbStore() {
return this._target;
get _idbStore(): QueryTargetWrapper<T> {
return (this._target as QueryTargetWrapper<T>);
}
index(indexName) {
return new QueryTarget(new QueryTargetWrapper(this._idbStore.index(indexName)));
index(indexName: string): QueryTarget<T> {
return new QueryTarget<T>(new QueryTargetWrapper<T>(this._idbStore.index(indexName)));
}
put(value) {
put(value: T) {
// If this request fails, the error will bubble up to the transaction and abort it,
// which is the behaviour we want. Therefore, it is ok to not create a promise for this
// request and await it.
@ -152,12 +161,12 @@ export class Store extends QueryTarget {
this._idbStore.put(value);
}
add(value) {
add(value: T) {
// ok to not monitor result of request, see comment in `put`.
this._idbStore.add(value);
}
delete(keyOrKeyRange) {
delete(keyOrKeyRange: IDBValidKey | IDBKeyRange) {
// ok to not monitor result of request, see comment in `put`.
this._idbStore.delete(keyOrKeyRange);
}