forked from mystiq/hydrogen-web
Start migrating utils.js to TypeScript
This commit is contained in:
parent
5579c018d1
commit
cd9fe360a4
12 changed files with 55 additions and 33 deletions
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {iterateCursor, reqAsPromise} from "./utils.js";
|
||||
import {iterateCursor, reqAsPromise} from "./utils";
|
||||
|
||||
export class QueryTarget {
|
||||
constructor(target) {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {Transaction} from "./Transaction.js";
|
||||
import { STORE_NAMES, StorageError } from "../common";
|
||||
import { reqAsPromise } from "./utils.js";
|
||||
import { reqAsPromise } from "./utils";
|
||||
|
||||
const WEBKITEARLYCLOSETXNBUG_BOGUS_KEY = "782rh281re38-boguskey";
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {Storage} from "./Storage.js";
|
||||
import { openDatabase, reqAsPromise } from "./utils.js";
|
||||
import { openDatabase, reqAsPromise } from "./utils";
|
||||
import { exportSession, importSession } from "./export.js";
|
||||
import { schema } from "./schema.js";
|
||||
import { detectWebkitEarlyCloseTxnBug } from "./quirks.js";
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {txnAsPromise} from "./utils.js";
|
||||
import {txnAsPromise} from "./utils";
|
||||
import {StorageError} from "../common";
|
||||
import {Store} from "./Store.js";
|
||||
import {SessionStore} from "./stores/SessionStore.js";
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { iterateCursor, txnAsPromise } from "./utils.js";
|
||||
import { iterateCursor, txnAsPromise } from "./utils";
|
||||
import { STORE_NAMES } from "../common";
|
||||
|
||||
export async function exportSession(db) {
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
|
||||
import {openDatabase, txnAsPromise, reqAsPromise} from "./utils.js";
|
||||
import {openDatabase, txnAsPromise, reqAsPromise} from "./utils";
|
||||
|
||||
// filed as https://bugs.webkit.org/show_bug.cgi?id=222746
|
||||
export async function detectWebkitEarlyCloseTxnBug(idbFactory) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {iterateCursor, reqAsPromise} from "./utils.js";
|
||||
import {iterateCursor, reqAsPromise} from "./utils";
|
||||
import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js";
|
||||
import {RoomMemberStore} from "./stores/RoomMemberStore.js";
|
||||
import {SessionStore} from "./stores/SessionStore.js";
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { encodeUint32, decodeUint32 } from "../utils.js";
|
||||
import { encodeUint32, decodeUint32 } from "../utils";
|
||||
import {KeyLimits} from "../../common";
|
||||
|
||||
function encodeKey(roomId, queueIndex) {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {EventKey} from "../../../room/timeline/EventKey.js";
|
||||
import { StorageError } from "../../common";
|
||||
import { encodeUint32 } from "../utils.js";
|
||||
import { encodeUint32 } from "../utils";
|
||||
import {KeyLimits} from "../../common";
|
||||
|
||||
function encodeKey(roomId, fragmentId, eventIndex) {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import { StorageError } from "../../common";
|
||||
import {KeyLimits} from "../../common";
|
||||
import { encodeUint32 } from "../utils.js";
|
||||
import { encodeUint32 } from "../utils";
|
||||
|
||||
function encodeKey(roomId, fragmentId) {
|
||||
return `${roomId}|${encodeUint32(fragmentId)}`;
|
||||
|
|
|
@ -20,12 +20,15 @@ import { StorageError } from "../common";
|
|||
|
||||
let needsSyncPromise = false;
|
||||
|
||||
export const DONE = { done: true }
|
||||
export const NOT_DONE = { done: false }
|
||||
|
||||
/* should be called on legacy platforms to see
|
||||
if transactions close before draining the microtask queue (IE11 on Windows 7).
|
||||
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 +52,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,33 +121,41 @@ 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, I extends IDBCursor> = I extends IDBCursorWithValue ?
|
||||
(value: T, key: IDBValidKey, cursor: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey } :
|
||||
(value: undefined, key: IDBValidKey, cursor: IDBCursor) => { done: boolean, jumpTo?: IDBValidKey }
|
||||
|
||||
export function iterateCursor<T, I extends IDBCursor = IDBCursorWithValue>(cursorRequest: IDBRequest<I | null>, processValue: CursorIterator<T, I>): 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<I>).result;
|
||||
if (!cursor) {
|
||||
resolve(false);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
return; // end of results
|
||||
}
|
||||
const result = processValue(cursor.value, cursor.key, cursor);
|
||||
const result = processValue(cursor["value"], cursor.key, cursor);
|
||||
// TODO: don't use object for result and assume it's jumpTo when not === true/false or undefined
|
||||
const done = result?.done;
|
||||
const jumpTo = result?.jumpTo;
|
||||
|
||||
if (done) {
|
||||
resolve(true);
|
||||
// @ts-ignore
|
||||
needsSyncPromise && Promise._flush && Promise._flush();
|
||||
} else if(jumpTo) {
|
||||
cursor.continue(jumpTo);
|
||||
|
@ -151,16 +168,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 +194,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 +206,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;
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
// polyfills needed for IE11
|
||||
import Promise from "../../../lib/es6-promise/index.js";
|
||||
import {checkNeedsSyncPromise} from "../../matrix/storage/idb/utils.js";
|
||||
import {checkNeedsSyncPromise} from "../../matrix/storage/idb/utils";
|
||||
|
||||
if (typeof window.Promise === "undefined") {
|
||||
window.Promise = Promise;
|
||||
|
|
Loading…
Reference in a new issue