From d51d4271fdbfc6cc14cccfac997639dd1f32e734 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Tue, 12 May 2026 20:31:57 +0000 Subject: [PATCH] docs: document set_config transaction-local gotcha in pgsql-test README and AGENTS.md --- postgres/pgsql-test/AGENTS.md | 15 +++++++++++++++ postgres/pgsql-test/README.md | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/postgres/pgsql-test/AGENTS.md b/postgres/pgsql-test/AGENTS.md index 4c50c576b0..c9d06d892c 100644 --- a/postgres/pgsql-test/AGENTS.md +++ b/postgres/pgsql-test/AGENTS.md @@ -29,6 +29,21 @@ beforeEach(() => db.beforeEach()); afterEach(() => db.afterEach()); ``` +## Transaction-Local Context + +`setContext()` uses `set_config('key', 'value', true)` — the `true` makes settings **transaction-local**. This means: + +- **In `it()` blocks:** Works automatically. `beforeEach()` starts a transaction, so context persists across queries. +- **In `beforeAll()`:** No active transaction. Context is lost between queries. Wrap context-dependent operations in explicit `db.begin()` / `db.commit()`. + +```ts +// In beforeAll — explicit transaction required +await db.begin(); +db.setContext({ role: 'authenticated', 'jwt.claims.user_id': userId }); +await db.query('...'); // context persists +await db.commit(); +``` + ## Seeding Notes - For raw SQL seeding, use `seed.sqlfile([...paths])`. diff --git a/postgres/pgsql-test/README.md b/postgres/pgsql-test/README.md index 6f3d3ad01f..4252c96780 100644 --- a/postgres/pgsql-test/README.md +++ b/postgres/pgsql-test/README.md @@ -191,7 +191,19 @@ db.setContext({ }); ``` -This applies the settings using `SET LOCAL` statements, ensuring they persist only for the current transaction and maintain proper isolation between tests. +This applies the settings using `SET LOCAL` and `set_config(..., true)` statements, ensuring they persist only for the current transaction and maintain proper isolation between tests. + +> **⚠️ Important:** `set_config(..., true)` is **transaction-local**. Inside test bodies (`it()` blocks), `beforeEach()` has already started a transaction, so context persists across queries automatically. However, in `beforeAll()` there is no active transaction — each query runs in auto-commit mode and context is lost between calls. If you need context-aware operations in `beforeAll()`, wrap them in explicit `db.begin()` / `db.commit()`: +> +> ```ts +> beforeAll(async () => { +> ({ db, teardown } = await getConnections()); +> await db.begin(); +> db.setContext({ role: 'authenticated', 'jwt.claims.user_id': '123' }); +> await db.query('SELECT current_user_id()'); // context persists within transaction +> await db.commit(); +> }); +> ``` #### Testing Role-Based Access