From 0c80f78e9b1b64247827953ed9e9b64b46ab01ab Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 9 Aug 2021 19:11:49 -0700 Subject: [PATCH] Add initial stab at annotating utils --- src/matrix/storage/idb/utils.ts | 59 +++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/src/matrix/storage/idb/utils.ts b/src/matrix/storage/idb/utils.ts index f90324cd..322d2d21 100644 --- a/src/matrix/storage/idb/utils.ts +++ b/src/matrix/storage/idb/utils.ts @@ -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 { // 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 { 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; + 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(req: IDBRequest): Promise { return new Promise((resolve, reject) => { req.addEventListener("success", event => { - resolve(event.target.result); + resolve((event.target as IDBRequest).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); reject(error); + // @ts-ignore needsSyncPromise && Promise._flush && Promise._flush(); }); }); } -export function txnAsPromise(txn) { +export function txnAsPromise(txn): Promise { 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 = (value: T, key?: IDBValidKey, cursor?: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey } + +export function iterateCursor(cursorRequest: IDBRequest, processValue: CursorIterator): Promise { // TODO: does cursor already have a value here?? - return new Promise((resolve, reject) => { + return new Promise((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).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 = (value: T) => boolean + +export async function fetchResults(cursor: IDBRequest, isDone: Pred): Promise { + const results: T[] = []; + await iterateCursor(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(db: IDBDatabase, storeName: string, toCursor: ToCursor, isDone: Pred): Promise { 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(db: IDBDatabase, storeName: string, toCursor: ToCursor, matchesValue: Pred): Promise { 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(cursor, (value) => { if (matchesValue(value)) { match = value; return true;