import type { NormalizedDeleteRangeOptions } from './delete-range.ts'; import { type ScanOptions } from './interface.ts'; /** * The Postgres counterpart of `sqlite-key-value-queries.ts`. The schema is the * same single `kv(key, value)` table, but two Postgres specifics differ from the * SQLite builders and force a separate module: * * - **Numbered placeholders.** Postgres binds parameters as `$1`, `$2`, … in * statement order, not the positional `?` SQLite uses. A builder that appends * bounds dynamically must therefore track the next placeholder index. * - **`COLLATE "C"` on the key.** Postgres `TEXT` sorts by the database locale, * which reorders punctuation and would silently corrupt every prefix-range * scan and `ORDER BY key` the engine relies on. Pinning the primary-key column * to the `C` collation restores byte-wise (codepoint) ordering, matching * SQLite's default `BINARY` collation and the engine's key-layout assumptions. * * Every query is parameterized by a **table reference** so the adapter can point * at a configured `"schema"."table"` instead of the default unqualified `kv` * (see {@link buildPostgresKeyValueQueries}). The reference is interpolated once * at construction, not per query. * * @module storage/postgres-key-value-queries */ /** The default unqualified table reference (resolves through `search_path`). */ export declare const DEFAULT_POSTGRES_TABLE_REFERENCE = "kv"; /** * Validate a Postgres identifier (schema or table name) against a strict * `[a-z_][a-z0-9_]*` pattern. Identifiers cannot be bound as `$n` parameters, so * they must be interpolated into the SQL text — this validation, run once at * construction, is the injection guard that makes interpolation safe. The strict * pattern excludes the `"` quote character, so no quote-doubling is required. * * A thin Postgres-flavored wrapper over the driver-neutral * {@link assertSqlIdentifier} (`./sql-identifier.ts`), which also backs the * Cloudflare Durable Object SQLite adapter's table-name validation. Kept as a * named export with the `'schema' | 'table'` role union and the "Postgres" * wording so existing call sites and error-message assertions stay unchanged. */ export declare function assertPostgresIdentifier(value: string, role: 'schema' | 'table'): void; /** * Resolve the SQL table reference from optional schema/table names. With neither * set, returns the bare unqualified `kv` so existing deployments emit * byte-identical SQL (the default search-path-resolved table). With either set, * returns a fully quoted `"schema"."table"` reference; both names are validated * as strict identifiers first so the interpolation is injection-safe. */ export declare function resolvePostgresTableReference(options: { schema?: string | undefined; table?: string | undefined; }): string; export type PostgresKeyRangeQueryParameter = string | number; /** A fully-built SQL statement and its bound parameters (SELECT or DELETE). */ export type PostgresBuiltQuery = { parameters: PostgresKeyRangeQueryParameter[]; sql: string; }; export declare function buildPostgresPrefixRangeParameters(prefix: string): [string, string]; /** * The complete set of SQL statements an adapter instance runs, all bound to one * `tableReference`. Built once per storage instance via * {@link buildPostgresKeyValueQueries}; the range builders close over the * reference so callers never re-pass it. */ export type PostgresKeyValueQueries = { readonly tableReference: string; readonly createTable: string; readonly selectKeyCollation: string; readonly selectValueByKey: string; readonly upsertValueByKey: string; readonly deleteValueByKey: string; readonly selectKeyPresence: string; readonly countKeysByPrefix: string; readonly deleteKeysByPrefix: string; /** One-statement condition read for `conditionalBatch`: `key = ANY($1)`. */ readonly selectValuesByKeys: string; /** One-statement multi-row upsert for `batch`: `unnest($1::text[], $2::bytea[])`. */ readonly upsertValuesByKeys: string; /** One-statement delete for `batch`: `key = ANY($1)`. */ readonly deleteValuesByKeys: string; keyValueRangeSelect(prefix: string, options?: ScanOptions): PostgresBuiltQuery; keyRangeSelect(prefix: string, options?: ScanOptions): PostgresBuiltQuery; keyRangeDelete(prefix: string, options: NormalizedDeleteRangeOptions): PostgresBuiltQuery; }; /** * Build the full query set for a `kv`-shaped table at `tableReference` (either * the bare unqualified `kv` or a quoted `"schema"."table"`). The reference is * already validated/quoted by {@link resolvePostgresTableReference}; this only * interpolates it into statement text. * * The collation check uses `to_regclass($1)` with the resolved reference so it * is scoped to the configured table — a `kv` table elsewhere on the search path * can never be inspected by mistake. */ export declare function buildPostgresKeyValueQueries(tableReference: string): PostgresKeyValueQueries; /** Begin a transaction at SERIALIZABLE isolation (conditionalBatch's CAS path). */ export declare const PG_BEGIN_SERIALIZABLE = "BEGIN ISOLATION LEVEL SERIALIZABLE"; /** Begin a transaction at READ COMMITTED isolation (the atomic batch() path). */ export declare const PG_BEGIN_READ_COMMITTED = "BEGIN ISOLATION LEVEL READ COMMITTED"; /** * Begin a READ ONLY transaction for the `query()` passthrough. Postgres enforces * this at the database level — a writing statement (including a data-modifying * CTE that a textual SELECT check would miss) errors instead of mutating. */ export declare const PG_BEGIN_READ_ONLY = "BEGIN READ ONLY"; /** Commit the current transaction. */ export declare const PG_COMMIT = "COMMIT"; /** Roll back the current transaction. */ export declare const PG_ROLLBACK = "ROLLBACK"; /** Create the configured schema if it is absent (only when a schema is set). */ export declare function buildPostgresCreateSchema(schema: string): string;