/** * Database provider contract for LibDashStore. * * A provider wraps a concrete database driver and exposes: * - query(sql, params) -> { rows, rowsAffected, insertId } * - transaction(fn) -> runs fn(runner) in a tx, commit/rollback * - exec(proc, {inputs,outputs}) -> stored procedure call (optional capability) * - initialize() / purge() -> schema lifecycle * - pool -> the underlying driver handle (transitional) * * @typedef {Object} QueryResult * @property {Array} rows Result rows (mssql `recordset` equivalent). * @property {number} rowsAffected Number of affected rows (mssql `rowsAffected[0]`). * @property {number|null} insertId Last inserted id when applicable, else null. * * @typedef {Object} DatabaseProvider * @property {(sql: string, params?: Object) => Promise} query * @property {(fn: (runner: DatabaseProvider) => Promise<*>) => Promise<*>} transaction * @property {() => Promise} initialize * @property {() => Promise} purge * @property {*} pool */ /** * Checks whether an error is a unique-constraint violation. * @param {any} err * @returns {boolean} */ export function isUniqueConstraintError(err) { return ( err?.number === 2627 || err?.number === 2601 || err?.code === 'SQLITE_CONSTRAINT_UNIQUE' || err?.code === 'SQLITE_CONSTRAINT_PRIMARYKEY' ); } /** * Checks whether an error is a foreign-key-constraint violation. * @param {any} err * @returns {boolean} */ export function isForeignKeyConstraintError(err) { return ( err?.number === 547 || err?.code === 'SQLITE_CONSTRAINT_FOREIGNKEY' ); } export const SLOW_QUERY_THRESHOLD_MS = 20; /** * Logs a SQL statement to the console if execution time exceeded SLOW_QUERY_THRESHOLD_MS (20ms). * * @param {string} sql * @param {number} durationMs * @param {object} [params] */ export function logSlowQuery(sql, durationMs, params = null) { if (durationMs > SLOW_QUERY_THRESHOLD_MS) { const timeStr = `${durationMs.toFixed(1)}ms`; console.log(`[SQL >20ms] (${timeStr})\n${typeof sql === 'string' ? sql.trim() : sql}`); if (params && Object.keys(params).length > 0) { console.log('Params:', params); } } }