summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-02-19 18:05:48 +0100
committerFlorian Dold <florian@dold.me>2024-02-19 18:05:48 +0100
commite951075d2ef52fa8e9e7489c62031777c3a7e66b (patch)
tree64208c09a9162f3a99adccf30edc36de1ef884ef /packages/taler-wallet-core/src/util
parente975740ac4e9ba4bc531226784d640a018c00833 (diff)
downloadwallet-core-e951075d2ef52fa8e9e7489c62031777c3a7e66b.tar.gz
wallet-core-e951075d2ef52fa8e9e7489c62031777c3a7e66b.tar.bz2
wallet-core-e951075d2ef52fa8e9e7489c62031777c3a7e66b.zip
wallet-core: flatten directory structure
Diffstat (limited to 'packages/taler-wallet-core/src/util')
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.ts4
-rw-r--r--packages/taler-wallet-core/src/util/query.ts831
2 files changed, 2 insertions, 833 deletions
diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts
index 0f6316bce..f33891c88 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.ts
@@ -64,8 +64,8 @@ import { InternalWalletState } from "../internal-wallet-state.js";
import {
getMerchantPaymentBalanceDetails,
getPeerPaymentBalanceDetailsInTx,
-} from "../operations/balance.js";
-import { getAutoRefreshExecuteThreshold } from "../operations/common.js";
+} from "../balance.js";
+import { getAutoRefreshExecuteThreshold } from "../common.js";
import { checkDbInvariant, checkLogicInvariant } from "./invariants.js";
const logger = new Logger("coinSelection.ts");
diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts
deleted file mode 100644
index 90a3cac70..000000000
--- a/packages/taler-wallet-core/src/util/query.ts
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Database query abstractions.
- * @module Query
- * @author Florian Dold
- */
-
-/**
- * Imports.
- */
-import {
- IDBCursor,
- IDBDatabase,
- IDBFactory,
- IDBKeyPath,
- IDBKeyRange,
- IDBRequest,
- IDBTransaction,
- IDBValidKey,
- IDBVersionChangeEvent,
-} from "@gnu-taler/idb-bridge";
-import { Codec, Logger, openPromise } from "@gnu-taler/taler-util";
-
-const logger = new Logger("query.ts");
-
-/**
- * Exception that should be thrown by client code to abort a transaction.
- */
-export const TransactionAbort = Symbol("transaction_abort");
-
-/**
- * Options for an index.
- */
-export interface IndexOptions {
- /**
- * If true and the path resolves to an array, create an index entry for
- * each member of the array (instead of one index entry containing the full array).
- *
- * Defaults to false.
- */
- multiEntry?: boolean;
-
- /**
- * Database version that this store was added in, or
- * undefined if added in the first version.
- */
- versionAdded?: number;
-
- /**
- * Does this index enforce unique keys?
- *
- * Defaults to false.
- */
- unique?: boolean;
-}
-
-function requestToPromise(req: IDBRequest): Promise<any> {
- const stack = Error("Failed request was started here.");
- return new Promise((resolve, reject) => {
- req.onsuccess = () => {
- resolve(req.result);
- };
- req.onerror = () => {
- console.error("error in DB request", req.error);
- reject(req.error);
- console.error("Request failed:", stack);
- };
- });
-}
-
-type CursorResult<T> = CursorEmptyResult<T> | CursorValueResult<T>;
-
-interface CursorEmptyResult<T> {
- hasValue: false;
-}
-
-interface CursorValueResult<T> {
- hasValue: true;
- value: T;
-}
-
-class TransactionAbortedError extends Error {
- constructor(m: string) {
- super(m);
-
- // Set the prototype explicitly.
- Object.setPrototypeOf(this, TransactionAbortedError.prototype);
- }
-}
-
-class ResultStream<T> {
- private currentPromise: Promise<void>;
- private gotCursorEnd = false;
- private awaitingResult = false;
-
- constructor(private req: IDBRequest) {
- this.awaitingResult = true;
- let p = openPromise<void>();
- this.currentPromise = p.promise;
- req.onsuccess = () => {
- if (!this.awaitingResult) {
- throw Error("BUG: invariant violated");
- }
- const cursor = req.result;
- if (cursor) {
- this.awaitingResult = false;
- p.resolve();
- p = openPromise<void>();
- this.currentPromise = p.promise;
- } else {
- this.gotCursorEnd = true;
- p.resolve();
- }
- };
- req.onerror = () => {
- p.reject(req.error);
- };
- }
-
- async toArray(): Promise<T[]> {
- const arr: T[] = [];
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- arr.push(x.value);
- } else {
- break;
- }
- }
- return arr;
- }
-
- async map<R>(f: (x: T) => R): Promise<R[]> {
- const arr: R[] = [];
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- arr.push(f(x.value));
- } else {
- break;
- }
- }
- return arr;
- }
-
- async mapAsync<R>(f: (x: T) => Promise<R>): Promise<R[]> {
- const arr: R[] = [];
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- arr.push(await f(x.value));
- } else {
- break;
- }
- }
- return arr;
- }
-
- async forEachAsync(f: (x: T) => Promise<void>): Promise<void> {
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- await f(x.value);
- } else {
- break;
- }
- }
- }
-
- async forEach(f: (x: T) => void): Promise<void> {
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- f(x.value);
- } else {
- break;
- }
- }
- }
-
- async filter(f: (x: T) => boolean): Promise<T[]> {
- const arr: T[] = [];
- while (true) {
- const x = await this.next();
- if (x.hasValue) {
- if (f(x.value)) {
- arr.push(x.value);
- }
- } else {
- break;
- }
- }
- return arr;
- }
-
- async next(): Promise<CursorResult<T>> {
- if (this.gotCursorEnd) {
- return { hasValue: false };
- }
- if (!this.awaitingResult) {
- const cursor: IDBCursor | undefined = this.req.result;
- if (!cursor) {
- throw Error("assertion failed");
- }
- this.awaitingResult = true;
- cursor.continue();
- }
- await this.currentPromise;
- if (this.gotCursorEnd) {
- return { hasValue: false };
- }
- const cursor = this.req.result;
- if (!cursor) {
- throw Error("assertion failed");
- }
- return { hasValue: true, value: cursor.value };
- }
-}
-
-/**
- * Return a promise that resolves to the opened IndexedDB database.
- */
-export function openDatabase(
- idbFactory: IDBFactory,
- databaseName: string,
- databaseVersion: number | undefined,
- onVersionChange: () => void,
- onUpgradeNeeded: (
- db: IDBDatabase,
- oldVersion: number,
- newVersion: number,
- upgradeTransaction: IDBTransaction,
- ) => void,
-): Promise<IDBDatabase> {
- return new Promise<IDBDatabase>((resolve, reject) => {
- const req = idbFactory.open(databaseName, databaseVersion);
- req.onerror = (event) => {
- // @ts-expect-error
- reject(new Error(`database opening error`, { cause: req.error }));
- };
- req.onsuccess = (e) => {
- req.result.onversionchange = (evt: IDBVersionChangeEvent) => {
- logger.info(
- `handling versionchange on ${databaseName} from ${evt.oldVersion} to ${evt.newVersion}`,
- );
- req.result.close();
- onVersionChange();
- };
- resolve(req.result);
- };
- req.onupgradeneeded = (e) => {
- const db = req.result;
- const newVersion = e.newVersion;
- if (!newVersion) {
- // @ts-expect-error
- throw Error("upgrade needed, but new version unknown", {
- cause: req.error,
- });
- }
- const transaction = req.transaction;
- if (!transaction) {
- // @ts-expect-error
- throw Error("no transaction handle available in upgrade handler", {
- cause: req.error,
- });
- }
- logger.info(
- `handling upgradeneeded event on ${databaseName} from ${e.oldVersion} to ${e.newVersion}`,
- );
- onUpgradeNeeded(db, e.oldVersion, newVersion, transaction);
- };
- });
-}
-
-export interface IndexDescriptor {
- name: string;
- keyPath: IDBKeyPath | IDBKeyPath[];
- multiEntry?: boolean;
- unique?: boolean;
- versionAdded?: number;
-}
-
-export interface StoreDescriptor<RecordType> {
- _dummy: undefined & RecordType;
- keyPath?: IDBKeyPath | IDBKeyPath[];
- autoIncrement?: boolean;
- /**
- * Database version that this store was added in, or
- * undefined if added in the first version.
- */
- versionAdded?: number;
-}
-
-export interface StoreOptions {
- keyPath?: IDBKeyPath | IDBKeyPath[];
- autoIncrement?: boolean;
-
- /**
- * First minor database version that this store was added in, or
- * undefined if added in the first version.
- */
- versionAdded?: number;
-}
-
-export function describeContents<RecordType = never>(
- options: StoreOptions,
-): StoreDescriptor<RecordType> {
- return {
- keyPath: options.keyPath,
- _dummy: undefined as any,
- autoIncrement: options.autoIncrement,
- versionAdded: options.versionAdded,
- };
-}
-
-export function describeIndex(
- name: string,
- keyPath: IDBKeyPath | IDBKeyPath[],
- options: IndexOptions = {},
-): IndexDescriptor {
- return {
- keyPath,
- name,
- multiEntry: options.multiEntry,
- unique: options.unique,
- versionAdded: options.versionAdded,
- };
-}
-
-interface IndexReadOnlyAccessor<RecordType> {
- iter(query?: IDBKeyRange | IDBValidKey): ResultStream<RecordType>;
- get(query: IDBValidKey): Promise<RecordType | undefined>;
- getAll(
- query?: IDBKeyRange | IDBValidKey,
- count?: number,
- ): Promise<RecordType[]>;
- count(query?: IDBValidKey): Promise<number>;
-}
-
-type GetIndexReadOnlyAccess<RecordType, IndexMap> = {
- [P in keyof IndexMap]: IndexReadOnlyAccessor<RecordType>;
-};
-
-interface IndexReadWriteAccessor<RecordType> {
- iter(query: IDBKeyRange | IDBValidKey): ResultStream<RecordType>;
- get(query: IDBValidKey): Promise<RecordType | undefined>;
- getAll(
- query?: IDBKeyRange | IDBValidKey,
- count?: number,
- ): Promise<RecordType[]>;
- count(query?: IDBValidKey): Promise<number>;
-}
-
-type GetIndexReadWriteAccess<RecordType, IndexMap> = {
- [P in keyof IndexMap]: IndexReadWriteAccessor<RecordType>;
-};
-
-export interface StoreReadOnlyAccessor<RecordType, IndexMap> {
- get(key: IDBValidKey): Promise<RecordType | undefined>;
- getAll(
- query?: IDBKeyRange | IDBValidKey,
- count?: number,
- ): Promise<RecordType[]>;
- iter(query?: IDBValidKey): ResultStream<RecordType>;
- indexes: GetIndexReadOnlyAccess<RecordType, IndexMap>;
-}
-
-export interface InsertResponse {
- /**
- * Key of the newly inserted (via put/add) record.
- */
- key: IDBValidKey;
-}
-
-export interface StoreReadWriteAccessor<RecordType, IndexMap> {
- get(key: IDBValidKey): Promise<RecordType | undefined>;
- getAll(
- query?: IDBKeyRange | IDBValidKey,
- count?: number,
- ): Promise<RecordType[]>;
- iter(query?: IDBValidKey): ResultStream<RecordType>;
- put(r: RecordType, key?: IDBValidKey): Promise<InsertResponse>;
- add(r: RecordType, key?: IDBValidKey): Promise<InsertResponse>;
- delete(key: IDBValidKey): Promise<void>;
- indexes: GetIndexReadWriteAccess<RecordType, IndexMap>;
-}
-
-export interface StoreWithIndexes<
- StoreName extends string,
- RecordType,
- IndexMap,
-> {
- storeName: StoreName;
- store: StoreDescriptor<RecordType>;
- indexMap: IndexMap;
-
- /**
- * Type marker symbol, to check that the descriptor
- * has been created through the right function.
- */
- mark: Symbol;
-}
-
-const storeWithIndexesSymbol = Symbol("StoreWithIndexesMark");
-
-export function describeStore<StoreName extends string, RecordType, IndexMap>(
- name: StoreName,
- s: StoreDescriptor<RecordType>,
- m: IndexMap,
-): StoreWithIndexes<StoreName, RecordType, IndexMap> {
- return {
- storeName: name,
- store: s,
- indexMap: m,
- mark: storeWithIndexesSymbol,
- };
-}
-
-export function describeStoreV2<
- StoreName extends string,
- RecordType,
- IndexMap extends { [x: string]: IndexDescriptor } = {},
->(args: {
- storeName: StoreName;
- recordCodec: Codec<RecordType>;
- keyPath?: IDBKeyPath | IDBKeyPath[];
- autoIncrement?: boolean;
- /**
- * Database version that this store was added in, or
- * undefined if added in the first version.
- */
- versionAdded?: number;
- indexes?: IndexMap;
-}): StoreWithIndexes<StoreName, RecordType, IndexMap> {
- return {
- storeName: args.storeName,
- store: {
- _dummy: undefined as any,
- autoIncrement: args.autoIncrement,
- keyPath: args.keyPath,
- versionAdded: args.versionAdded,
- },
- indexMap: args.indexes ?? ({} as IndexMap),
- mark: storeWithIndexesSymbol,
- };
-}
-
-type KeyPathComponents = string | number;
-
-/**
- * Follow a key path (dot-separated) in an object.
- */
-type DerefKeyPath<T, P> = P extends `${infer PX extends keyof T &
- KeyPathComponents}`
- ? T[PX]
- : P extends `${infer P0 extends keyof T & KeyPathComponents}.${infer Rest}`
- ? DerefKeyPath<T[P0], Rest>
- : unknown;
-
-/**
- * Return a path if it is a valid dot-separate path to an object.
- * Otherwise, return "never".
- */
-type ValidateKeyPath<T, P> = P extends `${infer PX extends keyof T &
- KeyPathComponents}`
- ? PX
- : P extends `${infer P0 extends keyof T & KeyPathComponents}.${infer Rest}`
- ? `${P0}.${ValidateKeyPath<T[P0], Rest>}`
- : never;
-
-// function foo<T, P>(
-// x: T,
-// p: P extends ValidateKeyPath<T, P> ? P : never,
-// ): void {}
-
-// foo({x: [0,1,2]}, "x.0");
-
-export type StoreNames<StoreMap> = StoreMap extends {
- [P in keyof StoreMap]: StoreWithIndexes<infer SN1, infer SD1, infer IM1>;
-}
- ? keyof StoreMap
- : unknown;
-
-export type DbReadWriteTransaction<
- StoreMap,
- StoresArr extends Array<StoreNames<StoreMap>>,
-> = StoreMap extends {
- [P in string]: StoreWithIndexes<infer _SN1, infer _SD1, infer _IM1>;
-}
- ? {
- [X in StoresArr[number] &
- keyof StoreMap]: StoreMap[X] extends StoreWithIndexes<
- infer _StoreName,
- infer RecordType,
- infer IndexMap
- >
- ? StoreReadWriteAccessor<RecordType, IndexMap>
- : unknown;
- }
- : never;
-
-export type DbReadOnlyTransaction<
- StoreMap,
- StoresArr extends Array<StoreNames<StoreMap>>,
-> = StoreMap extends {
- [P in string]: StoreWithIndexes<infer _SN1, infer _SD1, infer _IM1>;
-}
- ? {
- [X in StoresArr[number] &
- keyof StoreMap]: StoreMap[X] extends StoreWithIndexes<
- infer _StoreName,
- infer RecordType,
- infer IndexMap
- >
- ? StoreReadOnlyAccessor<RecordType, IndexMap>
- : unknown;
- }
- : never;
-
-/**
- * Convert the type of an array to a union of the contents.
- *
- * Example:
- * Input ["foo", "bar"]
- * Output "foo" | "bar"
- */
-export type UnionFromArray<Arr> = Arr extends {
- [X in keyof Arr]: Arr[X] & string;
-}
- ? Arr[keyof Arr & number]
- : unknown;
-
-function runTx<Arg, Res>(
- tx: IDBTransaction,
- arg: Arg,
- f: (t: Arg, t2: IDBTransaction) => Promise<Res>,
-): Promise<Res> {
- const stack = Error("Failed transaction was started here.");
- return new Promise((resolve, reject) => {
- let funResult: any = undefined;
- let gotFunResult = false;
- let transactionException: any = undefined;
- tx.oncomplete = () => {
- // This is a fatal error: The transaction completed *before*
- // the transaction function returned. Likely, the transaction
- // function waited on a promise that is *not* resolved in the
- // microtask queue, thus triggering the auto-commit behavior.
- // Unfortunately, the auto-commit behavior of IDB can't be switched
- // of. There are some proposals to add this functionality in the future.
- if (!gotFunResult) {
- const msg =
- "BUG: transaction closed before transaction function returned";
- logger.error(msg);
- logger.error(`${stack.stack}`);
- reject(Error(msg));
- }
- resolve(funResult);
- };
- tx.onerror = () => {
- logger.error("error in transaction");
- logger.error(`${stack.stack}`);
- };
- tx.onabort = () => {
- let msg: string;
- if (tx.error) {
- msg = `Transaction aborted (transaction error): ${tx.error}`;
- } else if (transactionException !== undefined) {
- msg = `Transaction aborted (exception thrown): ${transactionException}`;
- } else {
- msg = "Transaction aborted (no DB error)";
- }
- logger.error(msg);
- logger.error(`${stack.stack}`);
- reject(new TransactionAbortedError(msg));
- };
- const resP = Promise.resolve().then(() => f(arg, tx));
- resP
- .then((result) => {
- gotFunResult = true;
- funResult = result;
- })
- .catch((e) => {
- if (e == TransactionAbort) {
- logger.trace("aborting transaction");
- } else {
- transactionException = e;
- console.error("Transaction failed:", e);
- console.error(stack);
- tx.abort();
- }
- })
- .catch((e) => {
- console.error("fatal: aborting transaction failed", e);
- });
- });
-}
-
-function makeReadContext(
- tx: IDBTransaction,
- storePick: { [n: string]: StoreWithIndexes<any, any, any> },
-): any {
- const ctx: { [s: string]: StoreReadOnlyAccessor<any, any> } = {};
- for (const storeAlias in storePick) {
- const indexes: { [s: string]: IndexReadOnlyAccessor<any> } = {};
- const swi = storePick[storeAlias];
- const storeName = swi.storeName;
- for (const indexAlias in storePick[storeAlias].indexMap) {
- const indexDescriptor: IndexDescriptor =
- storePick[storeAlias].indexMap[indexAlias];
- const indexName = indexDescriptor.name;
- indexes[indexAlias] = {
- get(key) {
- const req = tx.objectStore(storeName).index(indexName).get(key);
- return requestToPromise(req);
- },
- iter(query) {
- const req = tx
- .objectStore(storeName)
- .index(indexName)
- .openCursor(query);
- return new ResultStream<any>(req);
- },
- getAll(query, count) {
- const req = tx
- .objectStore(storeName)
- .index(indexName)
- .getAll(query, count);
- return requestToPromise(req);
- },
- count(query) {
- const req = tx.objectStore(storeName).index(indexName).count(query);
- return requestToPromise(req);
- },
- };
- }
- ctx[storeAlias] = {
- indexes,
- get(key) {
- const req = tx.objectStore(storeName).get(key);
- return requestToPromise(req);
- },
- getAll(query, count) {
- const req = tx.objectStore(storeName).getAll(query, count);
- return requestToPromise(req);
- },
- iter(query) {
- const req = tx.objectStore(storeName).openCursor(query);
- return new ResultStream<any>(req);
- },
- };
- }
- return ctx;
-}
-
-function makeWriteContext(
- tx: IDBTransaction,
- storePick: { [n: string]: StoreWithIndexes<any, any, any> },
-): any {
- const ctx: { [s: string]: StoreReadWriteAccessor<any, any> } = {};
- for (const storeAlias in storePick) {
- const indexes: { [s: string]: IndexReadWriteAccessor<any> } = {};
- const swi = storePick[storeAlias];
- const storeName = swi.storeName;
- for (const indexAlias in storePick[storeAlias].indexMap) {
- const indexDescriptor: IndexDescriptor =
- storePick[storeAlias].indexMap[indexAlias];
- const indexName = indexDescriptor.name;
- indexes[indexAlias] = {
- get(key) {
- const req = tx.objectStore(storeName).index(indexName).get(key);
- return requestToPromise(req);
- },
- iter(query) {
- const req = tx
- .objectStore(storeName)
- .index(indexName)
- .openCursor(query);
- return new ResultStream<any>(req);
- },
- getAll(query, count) {
- const req = tx
- .objectStore(storeName)
- .index(indexName)
- .getAll(query, count);
- return requestToPromise(req);
- },
- count(query) {
- const req = tx.objectStore(storeName).index(indexName).count(query);
- return requestToPromise(req);
- },
- };
- }
- ctx[storeAlias] = {
- indexes,
- get(key) {
- const req = tx.objectStore(storeName).get(key);
- return requestToPromise(req);
- },
- getAll(query, count) {
- const req = tx.objectStore(storeName).getAll(query, count);
- return requestToPromise(req);
- },
- iter(query) {
- const req = tx.objectStore(storeName).openCursor(query);
- return new ResultStream<any>(req);
- },
- async add(r, k) {
- const req = tx.objectStore(storeName).add(r, k);
- const key = await requestToPromise(req);
- return {
- key: key,
- };
- },
- async put(r, k) {
- const req = tx.objectStore(storeName).put(r, k);
- const key = await requestToPromise(req);
- return {
- key: key,
- };
- },
- delete(k) {
- const req = tx.objectStore(storeName).delete(k);
- return requestToPromise(req);
- },
- };
- }
- return ctx;
-}
-
-/**
- * Type-safe access to a database with a particular store map.
- *
- * A store map is the metadata that describes the store.
- */
-export class DbAccess<StoreMap> {
- constructor(
- private db: IDBDatabase,
- private stores: StoreMap,
- ) {}
-
- idbHandle(): IDBDatabase {
- return this.db;
- }
-
- runAllStoresReadWriteTx<T>(
- txf: (
- tx: DbReadWriteTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
- ) => Promise<T>,
- ): Promise<T> {
- const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
- {};
- const strStoreNames: string[] = [];
- for (const sn of Object.keys(this.stores as any)) {
- const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
- strStoreNames.push(swi.storeName);
- accessibleStores[swi.storeName] = swi;
- }
- const tx = this.db.transaction(strStoreNames, "readwrite");
- const writeContext = makeWriteContext(tx, accessibleStores);
- return runTx(tx, writeContext, txf);
- }
-
- runAllStoresReadOnlyTx<T>(
- txf: (
- tx: DbReadOnlyTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
- ) => Promise<T>,
- ): Promise<T> {
- const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
- {};
- const strStoreNames: string[] = [];
- for (const sn of Object.keys(this.stores as any)) {
- const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
- strStoreNames.push(swi.storeName);
- accessibleStores[swi.storeName] = swi;
- }
- const tx = this.db.transaction(strStoreNames, "readonly");
- const writeContext = makeReadContext(tx, accessibleStores);
- return runTx(tx, writeContext, txf);
- }
-
- runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
- txf: (
- tx: DbReadWriteTransaction<StoreMap, StoreNameArray>,
- ) => Promise<T>,
- ): Promise<T> {
- const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
- {};
- const strStoreNames: string[] = [];
- for (const sn of storeNames) {
- const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
- strStoreNames.push(swi.storeName);
- accessibleStores[swi.storeName] = swi;
- }
- const tx = this.db.transaction(strStoreNames, "readwrite");
- const writeContext = makeWriteContext(tx, accessibleStores);
- return runTx(tx, writeContext, txf);
- }
-
- runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
- txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
- ): Promise<T> {
- const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
- {};
- const strStoreNames: string[] = [];
- for (const sn of storeNames) {
- const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
- strStoreNames.push(swi.storeName);
- accessibleStores[swi.storeName] = swi;
- }
- const tx = this.db.transaction(strStoreNames, "readonly");
- const readContext = makeReadContext(tx, accessibleStores);
- return runTx(tx, readContext, txf);
- }
-}