Eve-Relay/utils/queries.ts
2025-02-07 13:39:37 +01:00

97 lines
3.1 KiB
TypeScript

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;
}