refactor(db): typed query helpers, shared test FormData helper
CI / check (push) Successful in 4m10s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m4s

Replace raw db.execute tuple casts with queryRows/rowsFrom/execResult/
affectedRows helpers from lib/db, drop redundant mysql2 casts on typed
query builders, and centralize per-test fakeForm into test/fake-form.
Update db mocks in tests so helpers resolve against mocked execute.
This commit is contained in:
openhands committed 2026-09-17 21:02:57 +02:00
1 parent 2e25b39364
commit 8638e81444
116 files changed
+866 -897

No files matched your search

@@ -2,7 +2,10 @@ import { MySqlDialect } from "drizzle-orm/mysql-core";
import { beforeEach, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({ execute: vi.fn(), error: vi.fn() }));
vi.mock("@/lib/db", () => ({ db: { execute: mocks.execute } }));
vi.mock("@/lib/db", async () => ({
...(await import("@/test/db-helpers")).createDbHelpers(mocks.execute),
db: { execute: mocks.execute },
}));
vi.mock("@/lib/logger", () => ({ logger: { error: mocks.error } }));
import { effectRepository, listEffects } from "./server";
+23 -26
View File
@@ -1,7 +1,7 @@
import "server-only";
import { randomUUID } from "node:crypto";
import { sql } from "drizzle-orm";
import { db } from "@/lib/db";
import { db, queryRows, rowsFrom } from "@/lib/db";
import { logger } from "@/lib/logger";
import { isDeliveryReference } from "./delivery-diagnostics";
import {
@@ -26,15 +26,14 @@ export async function runOperation<T>(
await tx.execute(
sql`INSERT INTO cms_operations (id,actor_id,kind,request_key,request_hash) VALUES (${randomUUID()},${input.actorId},${input.kind},${input.key},${hash}) ON DUPLICATE KEY UPDATE id=id`,
);
const [rows] = await tx.execute(
sql`SELECT id,request_hash AS requestHash,result_json AS resultJson FROM cms_operations WHERE actor_id=${input.actorId} AND kind=${input.kind} AND request_key=${input.key} FOR UPDATE`,
);
const row = (
rows as unknown as Array<{
id: string;
requestHash: string;
resultJson: string | null;
}>
const row = rowsFrom<{
id: string;
requestHash: string;
resultJson: string | null;
}>(
await tx.execute(
sql`SELECT id,request_hash AS requestHash,result_json AS resultJson FROM cms_operations WHERE actor_id=${input.actorId} AND kind=${input.kind} AND request_key=${input.key} FOR UPDATE`,
),
)[0];
if (!row) throw new Error("Operation unavailable");
if (row.requestHash !== hash) throw new OperationConflict();
@@ -61,16 +60,15 @@ export async function enqueueEffect(
export const effectRepository = {
async claim(): Promise<EffectClaim | null> {
return db.transaction(async (tx) => {
const [rows] = await tx.execute(
sql`SELECT id,operation_id AS operationId,topic,attempts FROM cms_outbox WHERE (status='pending' AND available_at<=UTC_TIMESTAMP(3)) OR (status='running' AND lease_until<UTC_TIMESTAMP(3)) ORDER BY available_at,id LIMIT 1 FOR UPDATE`,
);
const row = (
rows as unknown as Array<{
id: string;
operationId: string;
topic: EffectTopic;
attempts: number;
}>
const row = rowsFrom<{
id: string;
operationId: string;
topic: EffectTopic;
attempts: number;
}>(
await tx.execute(
sql`SELECT id,operation_id AS operationId,topic,attempts FROM cms_outbox WHERE (status='pending' AND available_at<=UTC_TIMESTAMP(3)) OR (status='running' AND lease_until<UTC_TIMESTAMP(3)) ORDER BY available_at,id LIMIT 1 FOR UPDATE`,
),
)[0];
if (!row) return null;
const token = randomUUID();
@@ -105,10 +103,7 @@ export const effectRepository = {
export async function listEffects(id?: string) {
if (id !== undefined && !isDeliveryReference(id)) return [];
const filter = id === undefined ? sql`` : sql`WHERE e.id=${id}`;
const [rows] = await db.execute(
sql`SELECT e.id,e.operation_id AS operationId,e.topic,e.status,e.attempts,e.last_error AS lastError,e.created_at AS createdAt,e.available_at AS availableAt,o.actor_id AS actorId,o.kind,o.result_json AS resultJson FROM cms_outbox e JOIN cms_operations o ON o.id=e.operation_id ${filter} ORDER BY e.created_at DESC,e.id DESC LIMIT 100`,
);
return rows as unknown as Array<{
return queryRows<{
id: string;
operationId: string;
topic: EffectTopic;
@@ -120,7 +115,9 @@ export async function listEffects(id?: string) {
resultJson: string | null;
actorId: number;
kind: string;
}>;
}>(
sql`SELECT e.id,e.operation_id AS operationId,e.topic,e.status,e.attempts,e.last_error AS lastError,e.created_at AS createdAt,e.available_at AS availableAt,o.actor_id AS actorId,o.kind,o.result_json AS resultJson FROM cms_outbox e JOIN cms_operations o ON o.id=e.operation_id ${filter} ORDER BY e.created_at DESC,e.id DESC LIMIT 100`,
);
}
export async function retryEffect(id: string) {
if (
@@ -130,6 +127,6 @@ export async function retryEffect(id: string) {
const [result] = await db.execute(
sql`UPDATE cms_outbox SET status='pending',attempts=0,available_at=UTC_TIMESTAMP(3),last_error=NULL WHERE id=${id} AND status='failed'`,
);
if ((result as unknown as { affectedRows: number }).affectedRows !== 1)
if (result.affectedRows !== 1)
throw new Error("Delivery is no longer available for retry");
}