70 lines
2.1 KiB
TypeScript
70 lines
2.1 KiB
TypeScript
/**
|
|
* Postgres + MySQL adapters built on Bun's native SQL client (`Bun.SQL`) — no
|
|
* external driver dependency. Both speak the same `Driver` interface; only the
|
|
* dialect (and thus the DDL types + placeholder style) differ.
|
|
*
|
|
* `Bun.SQL` pools connections, so transactions use its managed `begin(fn)` to
|
|
* keep BEGIN/…/COMMIT on one reserved connection.
|
|
*/
|
|
|
|
import type { Dialect } from "../sql.ts";
|
|
import type { Driver, Row, TxHandle } from "../driver.ts";
|
|
|
|
interface BunSqlClient {
|
|
unsafe(query: string, params?: unknown[]): Promise<unknown>;
|
|
begin<T>(fn: (tx: BunSqlClient) => Promise<T>): Promise<T>;
|
|
close(): Promise<void>;
|
|
}
|
|
|
|
interface ExecMeta {
|
|
count?: number;
|
|
affectedRows?: number;
|
|
lastInsertRowid?: number | bigint;
|
|
insertId?: number | bigint;
|
|
}
|
|
|
|
function runnerFor(client: BunSqlClient): TxHandle {
|
|
return {
|
|
async query(sql, params = []): Promise<Row[]> {
|
|
const rows = (await client.unsafe(sql, params)) as Iterable<Row>;
|
|
return Array.from(rows);
|
|
},
|
|
async exec(sql, params = []) {
|
|
const meta = (await client.unsafe(sql, params)) as ExecMeta;
|
|
const id = meta.lastInsertRowid ?? meta.insertId;
|
|
return {
|
|
changes: Number(meta.affectedRows ?? meta.count ?? 0),
|
|
lastInsertId: id != null ? Number(id) : undefined,
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
/** Create a Bun.sql-backed driver for the given connection URL + dialect. */
|
|
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);
|
|
return {
|
|
dialect,
|
|
query: runner.query,
|
|
exec: runner.exec,
|
|
transaction(fn) {
|
|
return client.begin((tx) => fn(runnerFor(tx)));
|
|
},
|
|
close() {
|
|
return client.close();
|
|
},
|
|
};
|
|
}
|
|
|
|
/** PostgreSQL adapter (`postgres://user:pass@host:5432/db`). Placeholders: `$N`. */
|
|
export function postgres(url: string): Driver {
|
|
return bunSql(url, "postgres");
|
|
}
|
|
|
|
/** MySQL adapter (`mysql://user:pass@host:3306/db`). Placeholders: `?`. */
|
|
export function mysql(url: string): Driver {
|
|
return bunSql(url, "mysql");
|
|
}
|