drizzle-orm-node-sqlite
Version:
Drizzle ORM adapter for Node's built-in node:sqlite
122 lines (121 loc) • 4.93 kB
JavaScript
/**
* Internal runners that satisfy Drizzle’s sqlite-proxy contract.
*
* Drizzle will call us with:
* - method: 'run' | 'get' | 'all' | 'values'
* - params: array of bound values for '?' placeholders
* We must return:
* - for 'run': { rows: [] }
* - for 'get': { rows: string[] } (single row, as an array)
* - for 'all'/'values': { rows: string[][] } (array of rows as arrays)
*
* See: https://orm.drizzle.team/docs/connect-drizzle-proxy (row shape details)
*/
/** Convert a single object row → array using an ordered list of columns. */
function toArrayRow(objRow, cols) {
return cols.map((c) => objRow[c.name]);
}
/** Convert an array of object rows → array rows with the provided column list. */
function toArrayRows(objRows, cols) {
return objRows.map((row) => toArrayRow(row, cols));
}
/**
* Build a single-statement runner for Drizzle:
* - Prepares a fresh StatementSync per call
* - Applies statement options (bigints / param ergonomics)
* - Returns rows in the array shapes that Drizzle expects
*
* Node version notes:
* - Node 22: statement.get()/all() return **objects**. No `setReturnArrays()` exists.
* - Node 24+: you can enable array results via:
* * Database option: `new DatabaseSync(path, { returnArrays: true })`
* * Or per-statement: `StatementSync#setReturnArrays(true)`
* We don’t *require* either; if arrays are already returned we just forward them.
*/
export function makeRunner(db, opts = {}) {
function prep(sql) {
const stmt = db.prepare(sql);
// Optional toggles from Node’s API:
if (opts.readBigInts)
stmt.setReadBigInts(true);
if (opts.allowBareNamedParameters)
stmt.setAllowBareNamedParameters(true);
if (opts.allowUnknownNamedParameters)
stmt.setAllowUnknownNamedParameters(true);
// Do NOT call `stmt.setReturnArrays(true)` here. It exists on Node 24+,
// but not on Node 22. We support both by (a) trusting arrays if present,
// otherwise (b) mapping objects → arrays below.
return stmt;
}
/**
* Given a StatementSync and a row (or rows), normalize to array shapes.
* We prefer stmt.columns() when available; otherwise we fall back to the
* property insertion order of the first object row.
*/
function normalizeOneRowToArray(stmt, row) {
const stmtWithCols = stmt;
// Use `columns()` when available (Node 24+ exposes column metadata),
// else derive order from this row’s own keys.
const cols = typeof stmtWithCols.columns === 'function' ? stmtWithCols.columns() : Object.keys(row).map((name) => ({ name }));
return toArrayRow(row, cols);
}
function normalizeManyRowsToArrays(stmt, rows) {
if (rows.length === 0)
return [];
const first = rows[0];
const stmtWithCols = stmt;
// Prefer column metadata when available, otherwise derive from first row’s keys.
const cols = typeof stmtWithCols.columns === 'function' ? stmtWithCols.columns() : Object.keys(first).map((name) => ({ name }));
return toArrayRows(rows, cols);
}
async function runCore(sql, params, method) {
const stmt = prep(sql);
switch (method) {
case 'run': {
// Non-returning statements (INSERT/UPDATE/DELETE/DDL)
stmt.run(...params);
return { rows: [] };
}
case 'get': {
// Single-row result → array
const row = stmt.get(...params);
if (row == null)
return { rows: [] };
if (Array.isArray(row))
return { rows: row }; // Node >=24 with returnArrays
return {
rows: normalizeOneRowToArray(stmt, row),
};
}
case 'all':
case 'values': {
// Multi-row result → array-of-arrays
const rows = stmt.all(...params);
if (rows.length === 0)
return { rows: [] };
if (Array.isArray(rows[0])) {
// Already arrays (Node >=24 with returnArrays)
return { rows: rows };
}
return {
rows: normalizeManyRowsToArrays(stmt, rows),
};
}
}
}
return runCore;
}
/**
* Batch executor for Drizzle’s db.batch([...]).
* We simply run the single-statement executor for each item.
*/
export function makeBatchRunner(db, opts = {}) {
const single = makeRunner(db, opts);
return async function runBatch(queries) {
const results = [];
for (const q of queries) {
results.push(await single(q.sql, q.params, q.method));
}
return results;
};
}