feat: centralize application framework primitives
Quality / quality (ubuntu-latest) (push) Failing after 14m38s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-22 23:07:46 +05:30
parent 96e082b943
commit a3ddd39b7b
73 changed files with 1429 additions and 84 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/db",
"version": "0.8.17",
"version": "0.8.18",
"private": true,
"type": "module",
"main": "./src/index.ts",
+28
View File
@@ -63,6 +63,34 @@ export function withTransaction<T>(db: Db, callback: (tx: Db) => Promise<T>): Pr
return db.tx(callback);
}
/** Execute a parameterized compare-and-set update and report whether this caller won. */
export async function compareAndSet(
db: Db,
options: {
table: string;
idColumn?: string;
id: string | number;
stateColumn?: string;
from: string;
to: string;
extra?: Record<string, unknown>;
},
): Promise<boolean> {
const table = identifier(options.table);
const idColumn = identifier(options.idColumn ?? "id");
const stateColumn = identifier(options.stateColumn ?? "status");
const entries = Object.entries(options.extra ?? {});
const assignments = [stateColumn, ...entries.map(([name]) => identifier(name))];
const dialect = db.driver.dialect;
const values = [options.to, ...entries.map(([, value]) => value), options.id, options.from];
const sql = `UPDATE ${table} SET ${assignments
.map((name, index) => `${name} = ${placeholder(dialect, index + 1)}`)
.join(
", ",
)} WHERE ${idColumn} = ${placeholder(dialect, assignments.length + 1)} AND ${stateColumn} = ${placeholder(dialect, assignments.length + 2)}`;
return (await db.exec(sql, values)).changes === 1;
}
/** Conservative default classifier for deadlock/serialization retry errors. */
export function isRetryableTransactionError(error: unknown): boolean {
if (!error || typeof error !== "object") return false;
+1
View File
@@ -54,6 +54,7 @@ export {
exists,
countRows,
withTransaction,
compareAndSet,
retryTransaction,
batch,
databaseHealth,
+12
View File
@@ -5,6 +5,7 @@ import {
createRepository,
databaseHealth,
retryTransaction,
compareAndSet,
} from "../src/index.ts";
import type { Driver, Row } from "../src/index.ts";
@@ -28,6 +29,17 @@ function memoryDriver(): Driver {
}
describe("database helper kit", () => {
test("compareAndSet reports whether the guarded transition won", async () => {
const db = createDb(memoryDriver());
expect(
await compareAndSet(db, {
table: "messages",
id: 1,
from: "pending",
to: "sending",
}),
).toBe(true);
});
test("provides repository CRUD helpers and health checks", async () => {
const db = createDb(memoryDriver());
const repository = createRepository<{ id: number; name: string }>(db, {