import { type SQL, sql } from 'drizzle-orm'; interface ChangesReader { get(query: SQL): T; } function affectedRows(result: unknown): number { const changes = Array.isArray(result) ? result[0] : result && typeof result === 'object' && 'changes' in result ? result.changes : undefined; if (changes === undefined) { throw new Error('SQLite mutation did not return an affected-row count'); } if (!Number.isSafeInteger(changes) || (changes as number) < 0) { throw new Error('SQLite returned an invalid affected-row count'); } return changes as number; } /** * Run a synchronous Bun/Drizzle mutation and read SQLite's connection-local * `changes()` value before any other JavaScript can use that connection. * * Bun's statement `.run().changes` includes writes performed by FTS triggers, * so it cannot report the number of top-level Articles/Feeds affected. SQLite's * `changes()` excludes auxiliary trigger work. Keeping both calls synchronous * and adjacent also avoids a count/select race without materializing RETURNING * rows or holding an async transaction open. */ export function runAndCountChanges(connection: ChangesReader, mutation: () => unknown): number { mutation(); return affectedRows(connection.get(sql`select changes()`)); }