import { env } from "cloudflare:workers"; import { countD1, countD1Rows, timed } from "./perf"; type D1Value = string | number | null; export function stmt(sql: string, ...params: D1Value[]): D1PreparedStatement { return env.DB.prepare(sql).bind(...params); } const count = (ms: number) => countD1(ms); export async function first(sql: string, ...params: D1Value[]): Promise { return timed(count, () => stmt(sql, ...params).first()); } function rows(result: D1Result): void { countD1Rows(result.meta?.rows_read ?? 0, result.meta?.rows_written ?? 0); } export async function all(sql: string, ...params: D1Value[]): Promise { const result = await timed(count, () => stmt(sql, ...params).all()); rows(result); return result.results; } export async function run(sql: string, ...params: D1Value[]): Promise { const result = await timed(count, () => stmt(sql, ...params).run()); rows(result); return result; } export async function batch(statements: D1PreparedStatement[]): Promise { if (statements.length === 0) return []; const results = await timed(count, () => env.DB.batch(statements)); for (const result of results) rows(result); return results; } export function placeholders(count: number): string { return Array.from({ length: count }, () => "?").join(", "); } /** D1 allows at most 100 bound parameters per statement; keep IN-lists well below that. */ export const MAX_IN_LIST = 90; export function chunks(items: T[], size = MAX_IN_LIST): T[][] { const out: T[][] = []; for (let index = 0; index < items.length; index += size) out.push(items.slice(index, index + size)); return out; }