preact-missing-hooks
Version:
A lightweight, extendable collection of missing React-like hooks for Preact — plus fresh, powerful new ones designed specifically for modern Preact apps.
102 lines (93 loc) • 3.42 kB
text/typescript
/**
* Database controller: table(name), transaction(storeNames, mode, callback, options).
* @module indexedDB/dbController
*/
import type { IndexedDBConfig, TransactionOptions } from "./types";
import type { ITableController } from "./tableController";
import {
createTableController,
createTransactionTableController,
} from "./tableController";
/** Transaction context passed to the callback: provides table(name) bound to this transaction. */
export interface TransactionContext {
/** Returns a table controller bound to this transaction. Use for all ops inside the callback. */
table: (name: string) => ITableController;
}
/**
* Database controller built from an open IDBDatabase.
* Exposes table(name) and transaction(...).
*/
export interface IDBController {
/** Underlying IDBDatabase (read-only). */
readonly db: IDBDatabase;
/** Returns true if an object store with the given name exists. */
hasTable: (name: string) => boolean;
/** Returns a table controller for the given store (each op opens its own transaction). */
table: (name: string) => ITableController;
/**
* Runs a callback inside a single transaction. All operations in the callback use the same transaction.
* @param storeNames - Object store names to include in the transaction.
* @param mode - 'readonly' | 'readwrite'.
* @param callback - Async or sync function receiving { table(name) }. Return value is ignored; await all ops inside.
* @param options - Optional onSuccess/onError callbacks.
* @returns Promise that resolves when the transaction completes (after all requests and the callback).
*/
transaction: <T = void>(
storeNames: string[],
mode: IDBTransactionMode,
callback: (tx: TransactionContext) => T | Promise<T>,
options?: TransactionOptions
) => Promise<void>;
}
function withTransactionCallbacks(
promise: Promise<void>,
options?: TransactionOptions
): Promise<void> {
if (!options) return promise;
return promise
.then(() => options.onSuccess?.())
.catch((err: DOMException) => {
options.onError?.(err);
throw err;
});
}
/**
* Creates a database controller from an open IDBDatabase instance.
*/
export function createDBController(
db: IDBDatabase,
_config: IndexedDBConfig
): IDBController {
void _config; // Reserved for future config options
return {
get db(): IDBDatabase {
return db;
},
hasTable(name: string): boolean {
return db.objectStoreNames.contains(name);
},
table(name: string): ITableController {
return createTableController(db, name);
},
transaction<T = void>(
storeNames: string[],
mode: IDBTransactionMode,
callback: (tx: TransactionContext) => T | Promise<T>,
options?: TransactionOptions
): Promise<void> {
const tx = db.transaction(storeNames, mode);
const txContext: TransactionContext = {
table: (tableName: string) =>
createTransactionTableController(tx, tableName),
};
const txPromise = new Promise<void>((resolve, reject) => {
tx.oncomplete = () => resolve();
tx.onerror = () =>
reject(tx.error ?? new DOMException("Transaction failed"));
});
const callbackResult = callback(txContext);
const promise = Promise.resolve(callbackResult).then(() => txPromise);
return withTransactionCallbacks(promise, options);
},
};
}