UNPKG

drizzle-orm-node-sqlite

Version:
122 lines (121 loc) 4.93 kB
/** * 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; }; }