/** * Postgres placeholder conversion + shared pool lifecycle. */ import { afterEach, describe, expect, test } from "bun:test"; import { closeSharedPostgresClients, connectPostgres, isPostgresConnectionNoise, isSharedPostgresPaused, pauseSharedPostgresClients, PostgresDriverError, resumeSharedPostgresClients, SharedPostgresPausedError, sharedPostgresClient, toPostgresParams, } from "./postgres.ts"; afterEach(async () => { resumeSharedPostgresClients(); await closeSharedPostgresClients(); }); describe("toPostgresParams", () => { test("rewrites ? only when values are bound", () => { expect(toPostgresParams("SELECT * FROM t WHERE id = ?", ["a"])).toBe( "SELECT * FROM t WHERE id = $1", ); expect(toPostgresParams("INSERT INTO t (a, b) VALUES (?, ?)", [1, 2])).toBe( "INSERT INTO t (a, b) VALUES ($1, $2)", ); }); test("leaves jsonb ? operators unchanged when there are no values", () => { const sql = "SELECT current_setting('oke.scopes', true)::jsonb ? p_scope"; expect(toPostgresParams(sql)).toBe(sql); expect(toPostgresParams(sql, [])).toBe(sql); }); }); describe("closeSharedPostgresClients", () => { test("a different max is a different pool on the same URL", () => { const url = "postgres://127.0.0.1:9/oke-pool-max-shared-test"; const small = sharedPostgresClient(url, 8); const large = sharedPostgresClient(url, 20); expect(large).not.toBe(small); expect(sharedPostgresClient(url, 20)).toBe(large); expect(sharedPostgresClient(url)).toBe(small); }); test("drops cached pools so the next checkout is a new client", async () => { const url = "postgres://127.0.0.1:9/oke-close-shared-test"; const first = sharedPostgresClient(url); expect(sharedPostgresClient(url)).toBe(first); await closeSharedPostgresClients(); const second = sharedPostgresClient(url); expect(second).not.toBe(first); }); test("holder close is a no-op so seed stop cannot leave a dead cached pool", async () => { const url = "postgres://127.0.0.1:9/oke-holder-close-shared-test"; const first = sharedPostgresClient(url); await first.close?.({ timeout: 1 }); // Same live pool — journal/instances close during in-process seed must not // tear Bun.SQL while the map still hands out this client. expect(sharedPostgresClient(url)).toBe(first); await expect(first.close?.({ timeout: 1 })).resolves.toBeUndefined(); }); }); describe("pauseSharedPostgresClients", () => { test("blocks new pools and fails soft on existing wrappers", async () => { const url = "postgres://127.0.0.1:9/oke-pause-shared-test"; const sql = await connectPostgres({ url }); const held = sharedPostgresClient(url); await pauseSharedPostgresClients(); expect(isSharedPostgresPaused()).toBe(true); expect(() => sharedPostgresClient(url)).toThrow(SharedPostgresPausedError); await expect(sql.query("SELECT 1")).rejects.toBeInstanceOf(SharedPostgresPausedError); // Fleet wrappers (journal / clock / instances) call .unsafe on the held client. expect(() => held.unsafe("SELECT 1")).toThrow(SharedPostgresPausedError); resumeSharedPostgresClients(); expect(isSharedPostgresPaused()).toBe(false); const next = sharedPostgresClient(url); expect(next).toBeDefined(); }); test("isPostgresConnectionNoise matches Bun close / refuse codes", () => { expect( isPostgresConnectionNoise({ code: "ERR_POSTGRES_CONNECTION_CLOSED", message: "Connection closed", }), ).toBe(true); expect( isPostgresConnectionNoise({ code: "ERR_POSTGRES_CONNECTION_REFUSED", message: "Failed to connect", }), ).toBe(true); expect(isPostgresConnectionNoise(new SharedPostgresPausedError())).toBe(true); expect(isPostgresConnectionNoise(new Error("relation missing"))).toBe(false); }); }); describe("PostgresDriverError", () => { test("a non-Error rejection copies SQLSTATE fields and sets cause", async () => { const cause = { code: "ERR_POSTGRES_SERVER_ERROR", errno: "23505", constraint: "users_pkey", table: "users", column: "id", message: "duplicate key", }; const conn = await connectPostgres({ client: { async unsafe() { throw cause; }, }, }); let caught: unknown; try { await conn.query("SELECT 1"); } catch (err) { caught = err; } finally { await conn.close(); } expect(caught).toBeInstanceOf(PostgresDriverError); const wrapped = caught as PostgresDriverError; expect(wrapped.code).toBe("ERR_POSTGRES_SERVER_ERROR"); expect(wrapped.errno).toBe("23505"); expect(wrapped.constraint).toBe("users_pkey"); expect(wrapped.table).toBe("users"); expect(wrapped.column).toBe("id"); expect(wrapped.cause).toBe(cause); }); test("an Error rejection is rethrown unchanged", async () => { const original = Object.assign(new Error("duplicate key"), { code: "23505", errno: "23505", }); const conn = await connectPostgres({ client: { async unsafe() { throw original; }, }, }); let caught: unknown; try { await conn.query("SELECT 1"); } catch (err) { caught = err; } finally { await conn.close(); } expect(caught).toBe(original); }); });