@accounter/server
Version:
Accounter GraphQL server
50 lines (49 loc) • 2.5 kB
TypeScript
import type { Pool, PoolClient } from 'pg';
/**
* Unique role name per worker. `process.pid` alone is not enough: in Vitest's
* thread pool, parallel workers share one process (and thus one pid), so a random
* suffix is appended to avoid role-name collisions across concurrent test files.
*/
export declare const RLS_TEST_ROLE: string;
/** A table privilege grant: e.g. `{ table: 'sort_codes', privileges: 'INSERT, SELECT' }`. */
export interface RlsRoleGrant {
/** Unqualified table name (schema prefix is added automatically). */
table: string;
/** Comma-separated SQL privileges, e.g. `'SELECT'` or `'INSERT, SELECT'`. */
privileges: string;
}
export interface RlsRoleOptions {
/** Table privileges to grant the role for the queries under test. */
grants?: RlsRoleGrant[];
}
/**
* Idempotently create the per-process non-superuser RLS role and grant it schema
* usage plus any requested table privileges.
*
* `CREATE ROLE` / `GRANT` are not meant to be rolled back per-test, so this runs
* on its own connection outside any test transaction. Call from `beforeAll` and
* pair with {@link dropRlsRole} in `afterAll`.
*/
export declare function ensureRlsRole(pool: Pool, options?: RlsRoleOptions): Promise<void>;
/**
* Drop the RLS role. Mirror of {@link ensureRlsRole}.
*
* A bare `DROP ROLE` would fail while the role still holds the schema/table grants
* from ensureRlsRole — Postgres tracks them in pg_shdepend and refuses to drop a
* role other objects depend on. So we first `DROP OWNED BY`, which revokes every
* privilege granted to the role in the current database, then drop the role. The
* whole thing is guarded on role existence so a failed setup (role never created)
* surfaces the real error instead of a "role does not exist" during teardown.
*/
export declare function dropRlsRole(pool: Pool): Promise<void>;
/**
* Run `fn` with the connection's role dropped to the non-superuser RLS role, so
* Postgres evaluates the RLS policies. The role switch is confined to a SAVEPOINT:
* on success the role is reset and the savepoint released; on any error the
* savepoint is rolled back (which also restores the original role) and the error
* is rethrown for the caller to interpret (e.g. `42501` = WITH CHECK rejection).
*
* Set the relevant `app.*` session variables BEFORE calling this — as superuser,
* before privileges are dropped.
*/
export declare function runAsRlsRole<T>(client: PoolClient, fn: () => Promise<T>): Promise<T>;