Add initial stab at annotating utils
This commit is contained in:
parent
4fb93ad104
commit
0c80f78e9b
1 changed files with 38 additions and 21 deletions
|
@ -25,7 +25,7 @@ let needsSyncPromise = false;
|
|||
If this is the case, promises need to be resolved
|
||||
synchronously from the idb request handler to prevent the transaction from closing prematurely.
|
||||
*/
|
||||
export async function checkNeedsSyncPromise() {
|
||||
export async function checkNeedsSyncPromise(): Promise<boolean> {
|
||||
// important to have it turned off while doing the test,
|
||||
// otherwise reqAsPromise would not fail
|
||||
needsSyncPromise = false;
|
||||
|
@ -49,51 +49,57 @@ export async function checkNeedsSyncPromise() {
|
|||
}
|
||||
|
||||
// storage keys are defined to be unsigned 32bit numbers in KeyLimits, which is assumed by idb
|
||||
export function encodeUint32(n) {
|
||||
export function encodeUint32(n: number): string {
|
||||
const hex = n.toString(16);
|
||||
return "0".repeat(8 - hex.length) + hex;
|
||||
}
|
||||
|
||||
// used for logs where timestamp is part of key, which is larger than 32 bit
|
||||
export function encodeUint64(n) {
|
||||
export function encodeUint64(n: number): string {
|
||||
const hex = n.toString(16);
|
||||
return "0".repeat(16 - hex.length) + hex;
|
||||
}
|
||||
|
||||
export function decodeUint32(str) {
|
||||
export function decodeUint32(str: string): number {
|
||||
return parseInt(str, 16);
|
||||
}
|
||||
|
||||
export function openDatabase(name, createObjectStore, version, idbFactory = window.indexedDB) {
|
||||
type CreateObjectStore = (db : IDBDatabase, txn: IDBTransaction | null, oldVersion: number, version: number) => any
|
||||
|
||||
export function openDatabase(name: string, createObjectStore: CreateObjectStore, version: number, idbFactory: IDBFactory = window.indexedDB): Promise<IDBDatabase> {
|
||||
const req = idbFactory.open(name, version);
|
||||
req.onupgradeneeded = (ev) => {
|
||||
const db = ev.target.result;
|
||||
const txn = ev.target.transaction;
|
||||
req.onupgradeneeded = (ev : IDBVersionChangeEvent) => {
|
||||
const req = ev.target as IDBRequest<IDBDatabase>;
|
||||
const db = req.result;
|
||||
const txn = req.transaction;
|
||||
const oldVersion = ev.oldVersion;
|
||||
createObjectStore(db, txn, oldVersion, version);
|
||||
};
|
||||
return reqAsPromise(req);
|
||||
}
|
||||
|
||||
export function reqAsPromise(req) {
|
||||
export function reqAsPromise<T>(req: IDBRequest<T>): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
req.addEventListener("success", event => {
|
||||
resolve(event.target.result);
|
||||
resolve((event.target as IDBRequest<T>).result);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
});
|
||||
req.addEventListener("error", event => {
|
||||
const error = new IDBRequestError(event.target);
|
||||
const error = new IDBRequestError(event.target as IDBRequest<T>);
|
||||
reject(error);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function txnAsPromise(txn) {
|
||||
export function txnAsPromise(txn): Promise<void> {
|
||||
let error;
|
||||
return new Promise((resolve, reject) => {
|
||||
txn.addEventListener("complete", () => {
|
||||
resolve();
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
});
|
||||
txn.addEventListener("error", event => {
|
||||
|
@ -112,23 +118,28 @@ export function txnAsPromise(txn) {
|
|||
error = new StorageError(`Transaction on ${dbName} with stores ${storeNames} was aborted.`);
|
||||
}
|
||||
reject(error);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function iterateCursor(cursorRequest, processValue) {
|
||||
type CursorIterator<T> = (value: T, key?: IDBValidKey, cursor?: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey }
|
||||
|
||||
export function iterateCursor<T>(cursorRequest: IDBRequest<IDBCursorWithValue>, processValue: CursorIterator<T>): Promise<boolean> {
|
||||
// TODO: does cursor already have a value here??
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
cursorRequest.onerror = () => {
|
||||
reject(new IDBRequestError(cursorRequest));
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
};
|
||||
// collect results
|
||||
cursorRequest.onsuccess = (event) => {
|
||||
const cursor = event.target.result;
|
||||
const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;
|
||||
if (!cursor) {
|
||||
resolve(false);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
return; // end of results
|
||||
}
|
||||
|
@ -139,6 +150,7 @@ export function iterateCursor(cursorRequest, processValue) {
|
|||
|
||||
if (done) {
|
||||
resolve(true);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
} else if(jumpTo) {
|
||||
cursor.continue(jumpTo);
|
||||
|
@ -151,16 +163,20 @@ export function iterateCursor(cursorRequest, processValue) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function fetchResults(cursor, isDone) {
|
||||
const results = [];
|
||||
await iterateCursor(cursor, (value) => {
|
||||
type Pred<T> = (value: T) => boolean
|
||||
|
||||
export async function fetchResults<T>(cursor: IDBRequest, isDone: Pred<T[]>): Promise<T[]> {
|
||||
const results: T[] = [];
|
||||
await iterateCursor<T>(cursor, (value) => {
|
||||
results.push(value);
|
||||
return {done: isDone(results)};
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
export async function select(db, storeName, toCursor, isDone) {
|
||||
type ToCursor = (store: IDBObjectStore) => IDBRequest
|
||||
|
||||
export async function select<T>(db: IDBDatabase, storeName: string, toCursor: ToCursor, isDone: Pred<T[]>): Promise<T[]> {
|
||||
if (!isDone) {
|
||||
isDone = () => false;
|
||||
}
|
||||
|
@ -173,7 +189,7 @@ export async function select(db, storeName, toCursor, isDone) {
|
|||
return await fetchResults(cursor, isDone);
|
||||
}
|
||||
|
||||
export async function findStoreValue(db, storeName, toCursor, matchesValue) {
|
||||
export async function findStoreValue<T>(db: IDBDatabase, storeName: string, toCursor: ToCursor, matchesValue: Pred<T>): Promise<T> {
|
||||
if (!matchesValue) {
|
||||
matchesValue = () => true;
|
||||
}
|
||||
|
@ -185,7 +201,8 @@ export async function findStoreValue(db, storeName, toCursor, matchesValue) {
|
|||
const store = tx.objectStore(storeName);
|
||||
const cursor = await reqAsPromise(toCursor(store));
|
||||
let match;
|
||||
const matched = await iterateCursor(cursor, (value) => {
|
||||
// @ts-ignore
|
||||
const matched = await iterateCursor<T>(cursor, (value) => {
|
||||
if (matchesValue(value)) {
|
||||
match = value;
|
||||
return true;
|
||||
|
|
Reference in a new issue