1import { assert, it } from "@effect/vitest";
2import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient";
3import * as Effect from "effect/Effect";
4import * as Schema from "effect/Schema";
5import * as SqlClient from "effect/sql/SqlClient";
6
7import { PersistenceDecodeError, toPersistenceSqlError } from "./Errors.ts";
8
9const decodeRuntimePayload = Schema.decodeUnknownEffect(
10 Schema.Struct({
11 runtimePayload: Schema.Struct({
12 attempt: Schema.Number,
13 }),
14 }),
15);
16
17it.effect("names a real SQLite condition without copying query data", () =>
18 Effect.gen(function* () {
19 const sql = yield* SqlClient.SqlClient;
20 const payload = "sql-private-sentinel";
21 yield* sql`CREATE TABLE error_test (private_column TEXT PRIMARY KEY)`;
22 yield* sql`INSERT INTO error_test VALUES (${payload})`;
23 const cause = yield* Effect.flip(sql`INSERT INTO error_test VALUES (${payload})`);
24 const error = toPersistenceSqlError("OrchestrationCommandReceiptRepository.upsert:query")(
25 cause,
26 );
27
28 assert.equal(error.detail, "SQLITE(1555) constraint failed");
29 assert.equal(error.cause, cause);
30 assert.notInclude(error.message, payload);
31 assert.notInclude(error.message, "private_column");
32 }).pipe(Effect.provide(NodeSqliteClient.layer({ filename: ":memory:" }))),
33);
34
35it("reads the condition through a wrapping driver error", () => {
36 const driver = Object.assign(new Error("locked"), { errcode: 5, errstr: "database is locked" });
37 const error = toPersistenceSqlError("AuthSessionRepository.list:query")(
38 new Error("Failed to prepare statement", { cause: driver }),
39 );
40
41 assert.equal(error.detail, "SQLITE(5) database is locked");
42});
43
44it.effect("maps schema errors without copying rejected payloads into diagnostics", () =>
45 Effect.gen(function* () {
46 const rejectedPayload = "runtime-payload-secret-sentinel";
47 const cause = yield* Effect.flip(
48 decodeRuntimePayload({
49 runtimePayload: {
50 attempt: rejectedPayload,
51 },
52 }),
53 );
54 const error = PersistenceDecodeError.fromSchemaError(
55 "ProviderSessionRuntimeRepository.list:decodeRows",
56 cause,
57 );
58
59 assert.equal(error.operation, "ProviderSessionRuntimeRepository.list:decodeRows");
60 assert.equal(error.cause, cause);
61 assert.notInclude(error.issue, rejectedPayload);
62 assert.notInclude(error.message, rejectedPayload);
63 assert.include(error.issue, "InvalidType");
64 }),
65);