import type { BindValue, Database } from "@db/sqlite"; /** * Construct a SQL query with placeholders for values. * * This function takes a template string and interpolates it with the given * values, replacing placeholders with `?`. * * @example * const query = sqlPartial`SELECT * FROM events WHERE id = ${1} OR id = ${2}`; * // query = { * // query: 'SELECT * FROM events WHERE id = ? OR id = ?', * // values: ['1', '2'] * // } * * @param {TemplateStringsArray} segments A template string * @param {...BindValue[]} values Values to interpolate * @returns {{ query: string, values: BindValue[] }} A SQL query with placeholders */ export function sqlPartial( segments: TemplateStringsArray, ...values: BindValue[] ) { return { query: segments.reduce( (acc, str, i) => acc + str + (i < values.length ? "?" : ""), "", ), values: values, }; } /** * Construct a SQL query with placeholders for values and return a function * that executes that query on a database. * * This is a convenience wrapper around `sqlPartial` and `sqlPartialRunner`. * * @example * const run = sql`SELECT * FROM events WHERE id = ${1} OR id = ${2}`, * const results = run(db); * * @param {TemplateStringsArray} segments A template string * @param {...BindValue[]} values Values to interpolate * @returns {Function} A function that takes a Database and returns the query results */ export function sql(segments: TemplateStringsArray, ...values: BindValue[]) { return sqlPartialRunner(sqlPartial(segments, ...values)); } /** * Combine multiple partial queries into a single query. * * This function takes any number of partial queries with values and combines * them into a single query. * * @example * const query1 = { query: 'SELECT * FROM foo', values: [] }; * const query2 = { query: 'WHERE bar = ?', values: ['5'] }; * const query = mixQuery(query1, query2); * // query = { * // query: 'SELECT * FROM foo WHERE bar = ?', * // values: ['5'] * // } * * @param {...{ query: string, values: BindValue[] }} queries Partial queries * @returns {{ query: string, values: BindValue[] }} A combined query */ export function mixQuery(...queries: { query: string; values: BindValue[] }[]) { const { query, values } = queries.reduce( (acc, { query, values }) => ({ query: `${acc.query} ${query}`, values: [...acc.values, ...values], }), { query: "", values: [] }, ); return { query, values }; } /** * Executes a SQL query against a database. * * This function takes a query object containing a SQL query string with placeholders * and an array of values. It returns a function that, when given a Database instance, * prepares the query and executes it, returning all results. * * @param {Object} query An object containing the SQL query string and corresponding values * @returns {Function} A function that takes a Database instance and returns the query results */ export function sqlPartialRunner(query: { query: string; values: BindValue[]; }) { const run = (db: Database) => db.prepare(query.query).all(...query.values); return run; }