Files
star-kitten/packages/util/src/sqlite.ts
T
2026-09-06 11:29:23 -04:00

120 lines
3.3 KiB
TypeScript

import { Database } from 'bun:sqlite';
export function dynamicInsert<T extends {} = any>(db: Database, table: string, item: T) {
const keys = Object.keys(item);
const values = keys.map((k) => item[k]);
const stmt = db.prepare(`INSERT INTO ${table} (${keys.join(', ')}) VALUES (${keys.map((k) => '?').join(', ')})`);
return stmt.run(...values).lastInsertRowid;
}
export function dynamicUpdate<T extends {} = any>(db: Database, table: string, item: T, key: string, keyValue: any) {
const keys = Object.keys(item);
const values = keys.map((k) => item[k]);
const stmt = db.prepare(`UPDATE ${table} SET ${keys.map((k) => `${k} = ?`).join(', ')} WHERE ${key} = ?`);
return stmt.run(...values, keyValue).changes;
}
export interface QueryOptions<T extends {}> {
skip?: number;
limit?: number;
orderBy?: Partial<Record<keyof T, 'ASC' | 'DESC'>>;
}
type Where<T> = Partial<Record<keyof T, any>> & { or?: Partial<Record<keyof T, any>> };
export function select<T extends {}>(db: Database, table: string, options?: QueryOptions<T>, select: string = '*', where?: Where<T>): T[] {
let query = `SELECT ${select} FROM ${table}\n`;
const values = [];
if (where) {
const orConditions: string[] = [];
if (where.or) {
where.or && Object.keys(where.or).forEach((k) => {
values.push(where.or[k]);
orConditions.push(`${k} = ?`);
});
delete where.or;
}
const andConditions: string[] = [];
Object.keys(where).forEach((k) => {
values.push(where[k]);
andConditions.push(`${k} = ?`);
});
if (orConditions.length > 0 || andConditions.length > 0) {
query += 'WHERE ';
const conditions: string[] = [];
if (orConditions.length > 0) {
conditions.push(`(${orConditions.join(' OR ')})`);
}
if (andConditions.length > 0) {
conditions.push(andConditions.join(' AND '));
}
query += conditions.join(' AND ');
}
}
if (options?.orderBy) {
query += `ORDER BY ${Object.keys(options.orderBy)
.map((k) => {
return `${k} ${options.orderBy[k]}`;
})
.join(', ')}\n`;
}
if (options?.limit !== undefined) {
values.push(options.limit);
query += `LIMIT ?`;
if (options?.skip) {
values.push(options.skip);
query += ` OFFSET ?`;
}
}
return db.prepare(query).all(...values) as T[];
}
export function remove<T>(db: Database, table: string, where?: Where<T>) {
let query = `DELETE FROM ${table}`;
const values = [];
if (where) {
const orConditions: string[] = [];
if (where.or) {
where.or && Object.keys(where.or).forEach((k) => {
values.push(where.or[k]);
orConditions.push(`${k} = ?`);
});
delete where.or;
}
const andConditions: string[] = [];
Object.keys(where).forEach((k) => {
values.push(where[k]);
andConditions.push(`${k} = ?`);
});
if (orConditions.length > 0 || andConditions.length > 0) {
query += ' WHERE ';
const conditions: string[] = [];
if (orConditions.length > 0) {
conditions.push(`(${orConditions.join(' OR ')})`);
}
if (andConditions.length > 0) {
conditions.push(andConditions.join(' AND '));
}
query += conditions.join(' AND ');
}
}
return db.prepare(query).run(...values).changes;
}