release: WRNexusJS 0.5.10
This commit is contained in:
@@ -23,14 +23,21 @@ interface ExecMeta {
|
||||
insertId?: number | bigint;
|
||||
}
|
||||
|
||||
function runnerFor(client: BunSqlClient): TxHandle {
|
||||
/** Convert the framework's portable positional placeholders for PostgreSQL. */
|
||||
export function sqlForDialect(sql: string, dialect: Dialect): string {
|
||||
if (dialect !== "postgres" || !sql.includes("?")) return sql;
|
||||
let index = 0;
|
||||
return sql.replace(/\?/g, () => `$${++index}`);
|
||||
}
|
||||
|
||||
function runnerFor(client: BunSqlClient, dialect: Dialect): TxHandle {
|
||||
return {
|
||||
async query(sql, params = []): Promise<Row[]> {
|
||||
const rows = (await client.unsafe(sql, params)) as Iterable<Row>;
|
||||
const rows = (await client.unsafe(sqlForDialect(sql, dialect), params)) as Iterable<Row>;
|
||||
return Array.from(rows);
|
||||
},
|
||||
async exec(sql, params = []) {
|
||||
const meta = (await client.unsafe(sql, params)) as ExecMeta;
|
||||
const meta = (await client.unsafe(sqlForDialect(sql, dialect), params)) as ExecMeta;
|
||||
const id = meta.lastInsertRowid ?? meta.insertId;
|
||||
return {
|
||||
changes: Number(meta.affectedRows ?? meta.count ?? 0),
|
||||
@@ -44,13 +51,13 @@ function runnerFor(client: BunSqlClient): TxHandle {
|
||||
export function bunSql(url: string, dialect: Dialect): Driver {
|
||||
const Ctor = (Bun as unknown as { SQL: new (u: string) => BunSqlClient }).SQL;
|
||||
const client = new Ctor(url);
|
||||
const runner = runnerFor(client);
|
||||
const runner = runnerFor(client, dialect);
|
||||
return {
|
||||
dialect,
|
||||
query: runner.query,
|
||||
exec: runner.exec,
|
||||
transaction(fn) {
|
||||
return client.begin((tx) => fn(runnerFor(tx)));
|
||||
return client.begin((tx) => fn(runnerFor(tx, dialect)));
|
||||
},
|
||||
close() {
|
||||
return client.close();
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
import type { Db } from "./driver.ts";
|
||||
|
||||
const DEFAULT = "default";
|
||||
const registry = new Map<string, Db>();
|
||||
type DbFactory = () => Db;
|
||||
type RegistryEntry = { db?: Db; factory?: DbFactory };
|
||||
const registry = new Map<string, RegistryEntry>();
|
||||
|
||||
/** Set the default database (called by the runtime at startup). */
|
||||
export function setDb(db: Db): Db;
|
||||
@@ -21,7 +23,7 @@ export function setDb(name: string, db: Db): Db;
|
||||
export function setDb(a: string | Db, b?: Db): Db {
|
||||
const name = typeof a === "string" ? a : DEFAULT;
|
||||
const db = typeof a === "string" ? b! : a;
|
||||
registry.set(name, db);
|
||||
registry.set(name, { db });
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -30,10 +32,18 @@ export function registerDb(name: string, db: Db): Db {
|
||||
return setDb(name, db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a named database without opening its connection pool. The first
|
||||
* `getDb(name)` call creates and caches the connection.
|
||||
*/
|
||||
export function registerLazyDb(name: string, factory: DbFactory): void {
|
||||
registry.set(name, { factory });
|
||||
}
|
||||
|
||||
/** The default database, or a named one. Throws if it isn't configured. */
|
||||
export function getDb(name = DEFAULT): Db {
|
||||
const db = registry.get(name);
|
||||
if (!db) {
|
||||
const entry = registry.get(name);
|
||||
if (!entry) {
|
||||
throw new Error(
|
||||
name === DEFAULT
|
||||
? "No database configured. Add `db: { driver, url }` to wrnexus.config.ts."
|
||||
@@ -41,7 +51,11 @@ export function getDb(name = DEFAULT): Db {
|
||||
`(e.g. databases: { ${name}: { driver, url } }).`,
|
||||
);
|
||||
}
|
||||
return db;
|
||||
if (!entry.db) {
|
||||
if (!entry.factory) throw new Error(`Database '${name}' has no connection factory.`);
|
||||
entry.db = entry.factory();
|
||||
}
|
||||
return entry.db;
|
||||
}
|
||||
|
||||
/** Whether the default (or a named) database has been configured. */
|
||||
@@ -56,6 +70,8 @@ export function databaseNames(): string[] {
|
||||
|
||||
/** Close every configured database and clear the registry. */
|
||||
export async function closeDatabases(): Promise<void> {
|
||||
for (const db of registry.values()) await db.close();
|
||||
for (const entry of registry.values()) {
|
||||
if (entry.db) await entry.db.close();
|
||||
}
|
||||
registry.clear();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,15 @@ export { v, table, Column } from "./schema.ts";
|
||||
export type { Model, Columns, ColumnDef, BaseType } from "./schema.ts";
|
||||
export { createDb } from "./driver.ts";
|
||||
export type { Db, Driver, Row, ExecResult, TxHandle } from "./driver.ts";
|
||||
export { setDb, getDb, hasDb, registerDb, databaseNames, closeDatabases } from "./client.ts";
|
||||
export {
|
||||
setDb,
|
||||
getDb,
|
||||
hasDb,
|
||||
registerDb,
|
||||
registerLazyDb,
|
||||
databaseNames,
|
||||
closeDatabases,
|
||||
} from "./client.ts";
|
||||
export { createTableSql } from "./sql.ts";
|
||||
export type { Dialect } from "./sql.ts";
|
||||
export {
|
||||
|
||||
@@ -65,6 +65,7 @@ export async function appliedMigrations(db: Db): Promise<string[]> {
|
||||
|
||||
/** Apply an ordered migration list (each in a transaction). Returns applied names. */
|
||||
export async function applyMigrations(db: Db, migrations: readonly Migration[]): Promise<string[]> {
|
||||
if (migrations.length === 0) return [];
|
||||
const applied = new Set(await appliedMigrations(db));
|
||||
const pending = migrations.filter((migration) => !applied.has(migration.name));
|
||||
const done: string[] = [];
|
||||
|
||||
Reference in New Issue
Block a user