@voltro/sql-postgres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +781 -0
- package/dist/index.d.ts +375 -0
- package/dist/index.js +530 -0
- package/package.json +47 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import { ChangeEvent } from '@voltro/database';
|
|
2
|
+
import { ChangeStrategy } from '@voltro/database';
|
|
3
|
+
import { ConfigError } from 'effect';
|
|
4
|
+
import { ConnectionConfig } from '@voltro/database';
|
|
5
|
+
import { Context } from 'effect';
|
|
6
|
+
import { DataStore } from '@voltro/database';
|
|
7
|
+
import { DialectReplicationAdapter } from '@voltro/database';
|
|
8
|
+
import { Effect } from 'effect';
|
|
9
|
+
import { Layer } from 'effect';
|
|
10
|
+
import { ManagedRuntime } from 'effect';
|
|
11
|
+
import { PgClient } from '@effect/sql-pg';
|
|
12
|
+
import { Predicate } from '@voltro/database';
|
|
13
|
+
import { QueryDescriptor } from '@voltro/database';
|
|
14
|
+
import { RawSqlFragment } from '@voltro/database/sql';
|
|
15
|
+
import { RetryDecision } from '@voltro/database';
|
|
16
|
+
import { Row } from '@voltro/database';
|
|
17
|
+
import { SqlClient } from '@effect/sql';
|
|
18
|
+
import { SqlClient as SqlClient_2 } from '@effect/sql/SqlClient';
|
|
19
|
+
import { SqlDialect } from '@voltro/database';
|
|
20
|
+
import { SqlError } from '@effect/sql';
|
|
21
|
+
import { TransactionConnection } from '@effect/sql/SqlClient';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Parse a `ConnectionConfig` from the cross-dialect interface into the
|
|
25
|
+
* postgres-specific `PostgresConnection` shape.
|
|
26
|
+
*
|
|
27
|
+
* Resolution order:
|
|
28
|
+
* 1. If `url` is present, parse it (`postgres://user:pw@host:port/db`).
|
|
29
|
+
* 2. Otherwise use discrete fields.
|
|
30
|
+
* 3. Anything missing falls back to canonical defaults
|
|
31
|
+
* (localhost / 5432 / app / app / app) so dev-mode `voltro dev`
|
|
32
|
+
* without env config still boots against a default-config postgres.
|
|
33
|
+
*
|
|
34
|
+
* TLS: an explicit `config.ssl` wins; otherwise the URL's `?sslmode=` /
|
|
35
|
+
* `?ssl=` query decides (see `sslFromUrlQuery`); otherwise unset — the
|
|
36
|
+
* driver default. `ssl: true` maps to `sslmode=require` semantics,
|
|
37
|
+
* `ssl: false` forces plaintext (see `sslDriverOption` for the exact
|
|
38
|
+
* driver options).
|
|
39
|
+
*/
|
|
40
|
+
export declare const connectionFromConfig: (config: ConnectionConfig) => PostgresConnection;
|
|
41
|
+
|
|
42
|
+
export declare type DatabaseConnectionLayer = ReturnType<typeof makePostgresSqlLayer>;
|
|
43
|
+
|
|
44
|
+
export declare type DatabaseConnectionLayerInput = Parameters<typeof makePostgresSqlLayer>[0];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Construct a `PostgresDataStore`. The owned `ManagedRuntime` keeps the
|
|
48
|
+
* connection pool alive for the lifetime of the store; `close()` disposes it.
|
|
49
|
+
*/
|
|
50
|
+
export declare const makePostgresDataStore: (options: PostgresDataStoreOptions) => Promise<PostgresDataStore>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build a `PgClient` Layer from explicit field values.
|
|
54
|
+
*
|
|
55
|
+
* Marked exported because the CLI's migrate / dbCommand still construct
|
|
56
|
+
* the layer directly from environment values; once those callsites move
|
|
57
|
+
* to the dialect resolver they'll go through `postgresDialect.makeSqlLayer`
|
|
58
|
+
* and this becomes an internal helper.
|
|
59
|
+
*
|
|
60
|
+
* When `schema` is set, every pooled connection opens with
|
|
61
|
+
* `search_path = <schema>` (the PG `options` startup parameter, applied by
|
|
62
|
+
* the server BEFORE any query — no pool-rotation race), so introspection
|
|
63
|
+
* (`current_schema()`), unqualified DDL, and runtime queries all target it.
|
|
64
|
+
* `@effect/sql-pg`'s config can't carry that param, so we hand it a
|
|
65
|
+
* pre-built `pg.Pool` via `layerFromPool`. No schema → the unchanged
|
|
66
|
+
* `layerConfig` path (zero behaviour change).
|
|
67
|
+
*/
|
|
68
|
+
export declare const makePostgresSqlLayer: (options: PostgresConnection) => ReturnType<typeof PgClient.layerConfig>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The cross-dialect `SqlDialect.makeSqlLayer` implementation for postgres.
|
|
72
|
+
* Takes a generic `ConnectionConfig`, parses it via `connectionFromConfig`,
|
|
73
|
+
* and produces the same PgClient Layer that direct callers would build.
|
|
74
|
+
*/
|
|
75
|
+
export declare const makePostgresSqlLayerFromConfig: (config: ConnectionConfig) => ReturnType<typeof PgClient.layerConfig>;
|
|
76
|
+
|
|
77
|
+
export { PgClient }
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Internal handle a `PostgresDataStore` exposes so this adapter can
|
|
81
|
+
* issue raw SQL against the same managed runtime + connection pool.
|
|
82
|
+
*
|
|
83
|
+
* The framework's `ReplicatedDataStore` typing only sees a generic
|
|
84
|
+
* `DataStore`, so this adapter casts at the call site after checking
|
|
85
|
+
* for the friend-handle's presence — same pattern the dispatcher
|
|
86
|
+
* uses for transactional view internals.
|
|
87
|
+
*/
|
|
88
|
+
declare interface PostgresAdapterFriend {
|
|
89
|
+
readonly runEffect: <A, E>(effect: Effect.Effect<A, E, SqlClient_2>) => Promise<A>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export declare interface PostgresConnection {
|
|
93
|
+
readonly host: string;
|
|
94
|
+
readonly port: number;
|
|
95
|
+
readonly username: string;
|
|
96
|
+
readonly password: string;
|
|
97
|
+
readonly database: string;
|
|
98
|
+
/** Connection-pool size; defaults to 10. */
|
|
99
|
+
readonly maxConnections?: number;
|
|
100
|
+
/** TLS. `true` = `sslmode=require` semantics (encrypt, skip certificate
|
|
101
|
+
* verification — see `sslDriverOption`); `false` = force plaintext (also
|
|
102
|
+
* overrides a `PGSSLMODE` the driver would otherwise pick up from the
|
|
103
|
+
* process env); unset = the driver default (plaintext unless `PGSSLMODE`
|
|
104
|
+
* says otherwise). */
|
|
105
|
+
readonly ssl?: boolean;
|
|
106
|
+
/** Pin the connection `search_path` to this schema (env `DB_SCHEMA`).
|
|
107
|
+
* See `ConnectionConfig.schema`. */
|
|
108
|
+
readonly schema?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export declare class PostgresDataStore implements DataStore {
|
|
112
|
+
private readonly sql;
|
|
113
|
+
private readonly runtime;
|
|
114
|
+
private readonly changeStrategy;
|
|
115
|
+
private readonly cdcChannel;
|
|
116
|
+
private readonly emitter;
|
|
117
|
+
private cdcFiber;
|
|
118
|
+
/** In-flight count of `transactional()` calls. `close()` waits for
|
|
119
|
+
* this to drop to 0 (or its grace period to expire) before disposing
|
|
120
|
+
* the runtime — preventing connection-pool teardown mid-COMMIT. */
|
|
121
|
+
private inflightTxns;
|
|
122
|
+
constructor(sql: SqlClient.SqlClient, runtime: ManagedRuntime.ManagedRuntime<SqlClient.SqlClient | PgClient.PgClient, never>, changeStrategy: ChangeStrategy, cdcChannel: string);
|
|
123
|
+
/**
|
|
124
|
+
* Bind a per-request tenant NAMESPACE (a postgres SCHEMA). The returned
|
|
125
|
+
* view runs every operation inside a transaction whose first statement
|
|
126
|
+
* is `SET LOCAL search_path TO "<namespace>"`, so unqualified table
|
|
127
|
+
* names resolve to that tenant's schema — and the setting RESETS at
|
|
128
|
+
* commit/rollback. This is mandatory on a pooled connection: a bare
|
|
129
|
+
* `SET search_path` would persist on the connection and leak into the
|
|
130
|
+
* NEXT request that checks the same connection out of the pool. `SET
|
|
131
|
+
* LOCAL` is transaction-scoped, so the leak window is closed.
|
|
132
|
+
*
|
|
133
|
+
* `null` returns `this` — the shared-schema default (no search_path
|
|
134
|
+
* manipulation).
|
|
135
|
+
*/
|
|
136
|
+
withNamespace(namespace: string | null): DataStore;
|
|
137
|
+
/* Excluded from this release type: runInNamespace */
|
|
138
|
+
/**
|
|
139
|
+
* Friend-handle the postgres replication adapter reads via a
|
|
140
|
+
* structural check on `DataStore` (declared in `./replicationAdapter.ts`).
|
|
141
|
+
* The adapter needs raw SQL access against THIS store's managed
|
|
142
|
+
* runtime to issue `pg_current_wal_lsn()` / `pg_last_wal_replay_lsn()`
|
|
143
|
+
* — without a friend handle it would need its own connection pool +
|
|
144
|
+
* config, which would double the deployment cost.
|
|
145
|
+
*
|
|
146
|
+
* The handle stays on the store class as a public-but-prefixed
|
|
147
|
+
* property so the type cast in `adapterFriend(store)` resolves
|
|
148
|
+
* without exporting the runtime to the wider API surface.
|
|
149
|
+
*/
|
|
150
|
+
readonly __postgresReplicationFriend: PostgresAdapterFriend;
|
|
151
|
+
/**
|
|
152
|
+
* Core write/read path. Both the public-store API (no txn) and the
|
|
153
|
+
* per-transactional-view (with txn) flow through these, with explicit
|
|
154
|
+
* txn-context + event-sink params so concurrent transactions remain
|
|
155
|
+
* fully isolated. The public methods pass `null/null`; the view passes
|
|
156
|
+
* its own captured TxnContext + per-call events buffer.
|
|
157
|
+
*/
|
|
158
|
+
private executeQuery;
|
|
159
|
+
private executeInsert;
|
|
160
|
+
private executeUpdate;
|
|
161
|
+
private executeUpsert;
|
|
162
|
+
private executeInsertIgnore;
|
|
163
|
+
private executeInsertMany;
|
|
164
|
+
private executePatchJson;
|
|
165
|
+
private executeDelete;
|
|
166
|
+
/** Inside a transaction → push into the per-call events buffer (drained
|
|
167
|
+
* on commit, dropped on throw); outside → emit live. */
|
|
168
|
+
private routeEvent;
|
|
169
|
+
query(descriptor: QueryDescriptor): Promise<ReadonlyArray<Row>>;
|
|
170
|
+
raw<T extends object = Row>(fragment: RawSqlFragment, _opts?: {
|
|
171
|
+
dependsOn?: ReadonlyArray<string>;
|
|
172
|
+
}): Promise<ReadonlyArray<T>>;
|
|
173
|
+
/**
|
|
174
|
+
* Run a query, applying eager-loads when present.
|
|
175
|
+
*
|
|
176
|
+
* Path A (fast): compile to ONE roundtrip via `compileEagerJson` →
|
|
177
|
+
* postgres' `to_jsonb(parent.*) || jsonb_build_object('rel', ...)`
|
|
178
|
+
* shape. Each parent comes back with relations already nested as
|
|
179
|
+
* jsonb. Decoder restores Date types per schema.
|
|
180
|
+
*
|
|
181
|
+
* Path B (walker fallback): when compilation returns null
|
|
182
|
+
* (registry miss, unsupported feature, etc.) OR the JSON-agg
|
|
183
|
+
* execution throws, run the base SELECT + the portable walker.
|
|
184
|
+
* Walker is the canonical correctness path; JSON-agg is the perf
|
|
185
|
+
* layer.
|
|
186
|
+
*
|
|
187
|
+
* The fallback-on-throw catches dialect quirks I couldn't predict
|
|
188
|
+
* up front — anything that breaks the JSON-agg query (driver
|
|
189
|
+
* compatibility, schema feature) silently degrades to walker
|
|
190
|
+
* instead of surfacing a routing-level error. The log line on
|
|
191
|
+
* fallback makes the degradation visible during dev.
|
|
192
|
+
*/
|
|
193
|
+
private runWithEager;
|
|
194
|
+
/** Friend accessor for the transactional view — same eager-aware
|
|
195
|
+
* path as the public `query()` but pinned to the view's txn. */
|
|
196
|
+
getInternalRunWithEager(): (d: QueryDescriptor, txn: TxnContext | null) => Promise<ReadonlyArray<Row>>;
|
|
197
|
+
insert(table: string, row: Row): Promise<Row>;
|
|
198
|
+
insertMany(table: string, rows: ReadonlyArray<Row>): Promise<ReadonlyArray<Row>>;
|
|
199
|
+
patchJson(table: string, primaryKey: string, path: string, value: unknown): Promise<Row | null>;
|
|
200
|
+
update(table: string, primaryKey: string, patch: Readonly<Record<string, unknown>>): Promise<Row | null>;
|
|
201
|
+
delete(table: string, primaryKey: string): Promise<boolean>;
|
|
202
|
+
updateMany(table: string, patch: Readonly<Record<string, unknown>>, options: {
|
|
203
|
+
where: Predicate;
|
|
204
|
+
}): Promise<number>;
|
|
205
|
+
deleteMany(table: string, options: {
|
|
206
|
+
where: Predicate;
|
|
207
|
+
}): Promise<number>;
|
|
208
|
+
/**
|
|
209
|
+
* Q9 v2 — single-statement `UPDATE ... WHERE <pred> RETURNING *`.
|
|
210
|
+
* Postgres supports RETURNING on UPDATE; we use it to fan out the
|
|
211
|
+
* per-row ChangeEvent reactive subscribers expect, without paying the
|
|
212
|
+
* SELECT-then-update round-trip cost. The predicate lives on the write
|
|
213
|
+
* itself, so the match is a CAS: a row that stopped matching between a
|
|
214
|
+
* caller's read and this write is never patched. When an ambient `txn`
|
|
215
|
+
* is present (the transactional view) the statement routes to that
|
|
216
|
+
* captured connection so the CAS holds inside the transaction too —
|
|
217
|
+
* this is why the view forwards here instead of SELECT-ids-then-apply-
|
|
218
|
+
* by-id, which under READ COMMITTED could patch a row that no longer
|
|
219
|
+
* matches.
|
|
220
|
+
*/
|
|
221
|
+
private executeUpdateMany;
|
|
222
|
+
/**
|
|
223
|
+
* Single-statement `DELETE ... WHERE <pred> RETURNING *` — the set-based
|
|
224
|
+
* mirror of {@link executeUpdateMany}. The returned rows ARE the
|
|
225
|
+
* old-images we fan out as per-row delete ChangeEvents. Same
|
|
226
|
+
* predicate-CAS + ambient-txn routing rationale as updateMany.
|
|
227
|
+
*/
|
|
228
|
+
private executeDeleteMany;
|
|
229
|
+
upsert(table: string, row: Row, options: {
|
|
230
|
+
conflictColumns: ReadonlyArray<string>;
|
|
231
|
+
update?: ReadonlyArray<string> | ((existing: Row) => Readonly<Record<string, unknown>>);
|
|
232
|
+
}): Promise<Row>;
|
|
233
|
+
insertIgnore(table: string, row: Row, options: {
|
|
234
|
+
conflictColumns: ReadonlyArray<string>;
|
|
235
|
+
}): Promise<Row>;
|
|
236
|
+
/* Excluded from this release type: emitChange */
|
|
237
|
+
/* Excluded from this release type: getInternalExecuteQuery */
|
|
238
|
+
/* Excluded from this release type: getInternalExecuteInsert */
|
|
239
|
+
/* Excluded from this release type: getInternalExecuteInsertMany */
|
|
240
|
+
/* Excluded from this release type: getInternalExecutePatchJson */
|
|
241
|
+
/* Excluded from this release type: getInternalExecuteUpdate */
|
|
242
|
+
/* Excluded from this release type: getInternalExecuteDelete */
|
|
243
|
+
/* Excluded from this release type: getInternalExecuteUpdateMany */
|
|
244
|
+
/* Excluded from this release type: getInternalExecuteDeleteMany */
|
|
245
|
+
/* Excluded from this release type: getInternalExecuteUpsert */
|
|
246
|
+
/* Excluded from this release type: getInternalExecuteInsertIgnore */
|
|
247
|
+
/**
|
|
248
|
+
* Run `work` inside a real Postgres transaction.
|
|
249
|
+
*
|
|
250
|
+
* Each call to `transactional()` is fully independent — two concurrent
|
|
251
|
+
* invocations run on TWO separate Connections from the pool, BEGIN/
|
|
252
|
+
* COMMIT/ROLLBACK on their own connections, see their own (uncommitted)
|
|
253
|
+
* writes via the per-call view passed to `work`, and don't conflict.
|
|
254
|
+
*
|
|
255
|
+
* Mechanism:
|
|
256
|
+
* 1. `sql.withTransaction(effect)` checks out a Connection from the
|
|
257
|
+
* pool, issues `BEGIN`, and provides the `TransactionConnection`
|
|
258
|
+
* service to `effect`. On effect success → `COMMIT` + release;
|
|
259
|
+
* on failure → `ROLLBACK` + release.
|
|
260
|
+
* 2. Inside `effect` we capture the `TransactionConnection` tuple
|
|
261
|
+
* and construct a `PostgresTransactionalView` that owns the
|
|
262
|
+
* captured TxnContext + an events buffer. We pass it to `work`.
|
|
263
|
+
* 3. `work` calls `tx.insert/update/delete/query` on the view; the
|
|
264
|
+
* view forwards to the parent's private execute* methods with
|
|
265
|
+
* its TxnContext explicitly attached. Every statement therefore
|
|
266
|
+
* routes to the SAME Connection as BEGIN — atomic at the DB level.
|
|
267
|
+
* 4. ChangeEvents queue in the view's buffer; on commit they drain
|
|
268
|
+
* to the parent's emitter. On throw they're dropped.
|
|
269
|
+
*
|
|
270
|
+
* Resilience:
|
|
271
|
+
* - Automatic retry on `serialization_failure` (40001) and
|
|
272
|
+
* `deadlock_detected` (40P01) with exponential backoff (10ms base,
|
|
273
|
+
* up to 3 attempts). Each retry rebuilds a fresh view — the
|
|
274
|
+
* aborted attempt's events were never drained, so the retry's
|
|
275
|
+
* subscribers see exactly one event-set (the winning attempt's).
|
|
276
|
+
* - The whole `transactional()` boundary is wrapped in an
|
|
277
|
+
* `Effect.withSpan('store.transactional')` so OpenTelemetry
|
|
278
|
+
* collectors see one span per logical mutation, with retry counts
|
|
279
|
+
* and committed-event counts as attributes.
|
|
280
|
+
*/
|
|
281
|
+
transactional<T>(work: (tx: DataStore) => Promise<T>): Promise<T>;
|
|
282
|
+
onChange(listener: (event: ChangeEvent) => void): () => void;
|
|
283
|
+
/** Cross-instance reactivity seam — emit an externally-sourced event to
|
|
284
|
+
* local subscribers without re-persisting. Both the LISTEN/NOTIFY CDC
|
|
285
|
+
* consumer and `@voltro/plugin-broadcast` route through here. See
|
|
286
|
+
* `DataStore.injectExternalChange`. */
|
|
287
|
+
/** 'fleet' under LISTEN/NOTIFY CDC (every replica gets the full stream);
|
|
288
|
+
* 'local' under inline emission. See DataStore.changeScope. */
|
|
289
|
+
get changeScope(): 'local' | 'fleet';
|
|
290
|
+
injectExternalChange(event: ChangeEvent): void;
|
|
291
|
+
/** Run an arbitrary Effect against the underlying SqlClient. */
|
|
292
|
+
run<A, E>(effect: Effect.Effect<A, E, SqlClient.SqlClient>): Promise<A>;
|
|
293
|
+
/**
|
|
294
|
+
* Tear down the connection pool + CDC consumer.
|
|
295
|
+
*
|
|
296
|
+
* Waits up to `gracePeriodMs` for in-flight `transactional()` calls to
|
|
297
|
+
* complete before disposing the runtime. Without this, a graceful
|
|
298
|
+
* shutdown that races a mid-COMMIT mutation could see the connection
|
|
299
|
+
* pool yanked out from under the transaction — undefined outcome (the
|
|
300
|
+
* write may or may not land, depending on whether COMMIT had been
|
|
301
|
+
* flushed to disk).
|
|
302
|
+
*
|
|
303
|
+
* Defaults to a 5-second grace period — long enough for typical
|
|
304
|
+
* mutations to finish, short enough that a shutdown isn't blocked
|
|
305
|
+
* indefinitely by a stuck transaction. After the grace period
|
|
306
|
+
* expires, logs a warning and proceeds with disposal anyway (the
|
|
307
|
+
* shutdown must complete).
|
|
308
|
+
*/
|
|
309
|
+
close(gracePeriodMs?: number): Promise<void>;
|
|
310
|
+
/** Liveness probe — `SELECT 1`. Rejects if the pool can't answer. */
|
|
311
|
+
ping(): Promise<void>;
|
|
312
|
+
/**
|
|
313
|
+
* Subscribe to the Postgres NOTIFY channel and translate each notification
|
|
314
|
+
* into a ChangeEvent. Called automatically from `makePostgresDataStore`
|
|
315
|
+
* when `changeStrategy: 'cdc'`.
|
|
316
|
+
*/
|
|
317
|
+
startCdcConsumer(): Promise<void>;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export declare interface PostgresDataStoreOptions {
|
|
321
|
+
/**
|
|
322
|
+
* Layer that provides the postgres SQL client. `makePostgresSqlLayer({...})`
|
|
323
|
+
* returns `Layer<PgClient | SqlClient, ConfigError | SqlError>`, which is
|
|
324
|
+
* exactly this shape.
|
|
325
|
+
*/
|
|
326
|
+
readonly sqlLayer: Layer.Layer<SqlClient.SqlClient | PgClient.PgClient, ConfigError.ConfigError | SqlError.SqlError, never>;
|
|
327
|
+
/** Optional tracer layer (from `buildTracingLayer`). When provided, every
|
|
328
|
+
* `Effect.withSpan` inside the store's runtime — most importantly
|
|
329
|
+
* `transactional()` — emits real OpenTelemetry spans. Absent → spans
|
|
330
|
+
* become no-ops. Typed `Layer<never>` because Layer's provided-services
|
|
331
|
+
* channel is contravariant — `never` is the widest acceptor that
|
|
332
|
+
* absorbs both `Layer.empty` and real tracer layers (which provide
|
|
333
|
+
* OTel's Resource service). */
|
|
334
|
+
readonly tracerLayer?: Layer.Layer<never, never, never>;
|
|
335
|
+
/** Change emission strategy. Defaults to 'inline'. */
|
|
336
|
+
readonly changeStrategy?: ChangeStrategy;
|
|
337
|
+
/** Postgres NOTIFY channel name when changeStrategy is 'cdc'. Defaults to 'framework_changes'. */
|
|
338
|
+
readonly cdcChannel?: string;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* The dialect singleton — what `loadDialect()` returns and what every
|
|
343
|
+
* dialect-aware caller (CLI buildStore, migrate, workflow layer)
|
|
344
|
+
* receives.
|
|
345
|
+
*
|
|
346
|
+
* `compileContains` keeps `ILIKE ... ESCAPE '\\'` semantics; the
|
|
347
|
+
* centralised `sqlCompiler` routes `contains` through the dialect, with
|
|
348
|
+
* this as the postgres-side dispatch target.
|
|
349
|
+
*/
|
|
350
|
+
export declare const postgresDialect: SqlDialect;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Build a Postgres replication adapter.
|
|
354
|
+
*
|
|
355
|
+
* The store the adapter operates against MUST expose the
|
|
356
|
+
* `__postgresReplicationFriend` handle the framework's
|
|
357
|
+
* `PostgresDataStore` attaches at construction time. The adapter
|
|
358
|
+
* throws a clear error if the handle is missing — surfaces
|
|
359
|
+
* "wrong store passed" at the routing boundary instead of
|
|
360
|
+
* downstream as a SQL error.
|
|
361
|
+
*/
|
|
362
|
+
export declare const postgresReplicationAdapter: () => DialectReplicationAdapter;
|
|
363
|
+
|
|
364
|
+
/** `SqlDialect.retryFilter` implementation for postgres. */
|
|
365
|
+
export declare const postgresRetryFilter: (err: unknown) => RetryDecision;
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Captured inside `transactional()`'s `withTransaction` scope. Holds the
|
|
369
|
+
* `TransactionConnection` context tuple `[Connection, depth]` so we can
|
|
370
|
+
* explicitly provide it to each inner statement's Effect — without this,
|
|
371
|
+
* statements run on the shared pool and bypass our `BEGIN`.
|
|
372
|
+
*/
|
|
373
|
+
declare type TxnContext = Context.Tag.Service<typeof TransactionConnection>;
|
|
374
|
+
|
|
375
|
+
export { }
|