litedbmodel 2.0.2 → 2.2.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/README.md +7 -0
- package/dist/DBConditions.d.ts.map +1 -1
- package/dist/DBConditions.js +16 -1
- package/dist/DBConditions.js.map +1 -1
- package/dist/DBHandler.d.ts.map +1 -1
- package/dist/DBHandler.js +6 -0
- package/dist/DBHandler.js.map +1 -1
- package/dist/DBModel.d.ts +84 -2
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +312 -29
- package/dist/DBModel.js.map +1 -1
- package/dist/decorators.d.ts +52 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +127 -24
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/mysql.d.ts.map +1 -1
- package/dist/drivers/mysql.js +12 -2
- package/dist/drivers/mysql.js.map +1 -1
- package/dist/drivers/postgres.d.ts.map +1 -1
- package/dist/drivers/postgres.js +13 -2
- package/dist/drivers/postgres.js.map +1 -1
- package/dist/drivers/sqlite.d.ts +2 -0
- package/dist/drivers/sqlite.d.ts.map +1 -1
- package/dist/drivers/sqlite.js +49 -4
- package/dist/drivers/sqlite.js.map +1 -1
- package/dist/index.cjs +10741 -0
- package/dist/index.d.cts +1 -0
- package/dist/scp/coltype.d.ts +108 -0
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +293 -6
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/connection-routing.d.ts +312 -0
- package/dist/scp/connection-routing.d.ts.map +1 -0
- package/dist/scp/connection-routing.js +394 -0
- package/dist/scp/connection-routing.js.map +1 -0
- package/dist/scp/dbmodel-runtime.d.ts +101 -0
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
- package/dist/scp/dbmodel-runtime.js +174 -0
- package/dist/scp/dbmodel-runtime.js.map +1 -0
- package/dist/scp/decorator-adapter.d.ts +196 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -0
- package/dist/scp/decorator-adapter.js +286 -0
- package/dist/scp/decorator-adapter.js.map +1 -0
- package/dist/scp/emit/emitter.d.ts +108 -0
- package/dist/scp/emit/emitter.d.ts.map +1 -0
- package/dist/scp/emit/emitter.js +782 -0
- package/dist/scp/emit/emitter.js.map +1 -0
- package/dist/scp/emit/endpoint.d.ts +248 -0
- package/dist/scp/emit/endpoint.d.ts.map +1 -0
- package/dist/scp/emit/endpoint.js +20 -0
- package/dist/scp/emit/endpoint.js.map +1 -0
- package/dist/scp/emit/index.d.ts +11 -0
- package/dist/scp/emit/index.d.ts.map +1 -0
- package/dist/scp/emit/index.js +13 -0
- package/dist/scp/emit/index.js.map +1 -0
- package/dist/scp/errors.d.ts +45 -1
- package/dist/scp/errors.d.ts.map +1 -1
- package/dist/scp/errors.js +47 -1
- package/dist/scp/errors.js.map +1 -1
- package/dist/scp/exec-context.d.ts +390 -0
- package/dist/scp/exec-context.d.ts.map +1 -0
- package/dist/scp/exec-context.js +540 -0
- package/dist/scp/exec-context.js.map +1 -0
- package/dist/scp/grouping.d.ts +32 -0
- package/dist/scp/grouping.d.ts.map +1 -0
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -0
- package/dist/scp/index.cjs +6432 -17579
- package/dist/scp/index.d.cts +1 -0
- package/dist/scp/index.d.mts +1 -0
- package/dist/scp/index.d.ts +51 -52
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +189 -152
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +6067 -3659
- package/dist/scp/leaf-transport.d.ts +50 -0
- package/dist/scp/leaf-transport.d.ts.map +1 -0
- package/dist/scp/leaf-transport.js +92 -0
- package/dist/scp/leaf-transport.js.map +1 -0
- package/dist/scp/leaves.d.ts +174 -0
- package/dist/scp/leaves.d.ts.map +1 -0
- package/dist/scp/leaves.js +287 -0
- package/dist/scp/leaves.js.map +1 -0
- package/dist/scp/limit-config.d.ts +118 -0
- package/dist/scp/limit-config.d.ts.map +1 -0
- package/dist/scp/limit-config.js +126 -0
- package/dist/scp/limit-config.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +49 -23
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
- package/dist/scp/makesql/compile-relation.js +101 -76
- package/dist/scp/makesql/compile-relation.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +45 -10
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +50 -10
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/handler.d.ts +1 -1
- package/dist/scp/makesql/handler.d.ts.map +1 -1
- package/dist/scp/makesql/index.d.ts +7 -10
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +19 -30
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/json-array.d.ts +65 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +99 -10
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/json-batch.d.ts.map +1 -1
- package/dist/scp/makesql/json-batch.js +21 -19
- package/dist/scp/makesql/json-batch.js.map +1 -1
- package/dist/scp/makesql/makesql.d.ts +1 -1
- package/dist/scp/makesql/makesql.d.ts.map +1 -1
- package/dist/scp/makesql/mysql-returning.d.ts +93 -0
- package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
- package/dist/scp/makesql/mysql-returning.js +215 -0
- package/dist/scp/makesql/mysql-returning.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +75 -34
- package/dist/scp/makesql/outtype.d.ts.map +1 -1
- package/dist/scp/makesql/outtype.js +91 -118
- package/dist/scp/makesql/outtype.js.map +1 -1
- package/dist/scp/makesql/pool-executor.d.ts +135 -13
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
- package/dist/scp/makesql/pool-executor.js +229 -21
- package/dist/scp/makesql/pool-executor.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +107 -22
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +451 -97
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +7 -8
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +8 -7
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +287 -0
- package/dist/scp/middleware.d.ts.map +1 -0
- package/dist/scp/middleware.js +358 -0
- package/dist/scp/middleware.js.map +1 -0
- package/dist/scp/relation.d.ts +80 -9
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +198 -78
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/tx-options.d.ts +136 -0
- package/dist/scp/tx-options.d.ts.map +1 -0
- package/dist/scp/tx-options.js +184 -0
- package/dist/scp/tx-options.js.map +1 -0
- package/dist/scp/write-bundle.d.ts +131 -0
- package/dist/scp/write-bundle.d.ts.map +1 -0
- package/dist/scp/write-bundle.js +160 -0
- package/dist/scp/write-bundle.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +58 -56
- package/docs/benchmark-chart.svg +166 -166
- package/docs/design/phase-a-execution-context.md +139 -0
- package/package.json +16 -9
- package/dist/scp/authoring-sql.d.ts +0 -134
- package/dist/scp/authoring-sql.d.ts.map +0 -1
- package/dist/scp/authoring-sql.js +0 -191
- package/dist/scp/authoring-sql.js.map +0 -1
- package/dist/scp/authoring.d.ts +0 -155
- package/dist/scp/authoring.d.ts.map +0 -1
- package/dist/scp/authoring.js +0 -162
- package/dist/scp/authoring.js.map +0 -1
- package/dist/scp/catalog.d.ts +0 -94
- package/dist/scp/catalog.d.ts.map +0 -1
- package/dist/scp/catalog.js +0 -234
- package/dist/scp/catalog.js.map +0 -1
- package/dist/scp/codegen.d.ts +0 -189
- package/dist/scp/codegen.d.ts.map +0 -1
- package/dist/scp/codegen.js +0 -421
- package/dist/scp/codegen.js.map +0 -1
- package/dist/scp/find-filter-guard.d.ts +0 -68
- package/dist/scp/find-filter-guard.d.ts.map +0 -1
- package/dist/scp/find-filter-guard.js +0 -88
- package/dist/scp/find-filter-guard.js.map +0 -1
- package/dist/scp/guard.d.ts +0 -43
- package/dist/scp/guard.d.ts.map +0 -1
- package/dist/scp/guard.js +0 -134
- package/dist/scp/guard.js.map +0 -1
- package/dist/scp/makesql/authoring-compile.d.ts +0 -90
- package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
- package/dist/scp/makesql/authoring-compile.js +0 -494
- package/dist/scp/makesql/authoring-compile.js.map +0 -1
- package/dist/scp/makesql/ir.d.ts +0 -42
- package/dist/scp/makesql/ir.d.ts.map +0 -1
- package/dist/scp/makesql/ir.js +0 -66
- package/dist/scp/makesql/ir.js.map +0 -1
- package/dist/scp/makesql/static-bundle.d.ts +0 -187
- package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
- package/dist/scp/makesql/static-bundle.js +0 -1113
- package/dist/scp/makesql/static-bundle.js.map +0 -1
- package/dist/scp/runtime.d.ts +0 -242
- package/dist/scp/runtime.d.ts.map +0 -1
- package/dist/scp/runtime.js +0 -400
- package/dist/scp/runtime.js.map +0 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — the **connection routing + config contract** (Phase C / #87).
|
|
3
|
+
*
|
|
4
|
+
* This module is the **API REFERENCE** for Phase C — the 4 native ports (rust #88 / go #89 / py #90
|
|
5
|
+
* / php #91) mirror THIS contract exactly (config field names + defaults, the connection-registry
|
|
6
|
+
* shape, `withWriter` semantics, and the `connectionFor(intent)` resolution ORDER). It builds ON the
|
|
7
|
+
* Phase A {@link import('./exec-context').ExecutionContext} seam and the Phase A/B owned-connection
|
|
8
|
+
* transaction runtime; it does NOT re-implement the seam — it supplies the pieces
|
|
9
|
+
* {@link import('./exec-context').PooledAsyncContext.connectionFor} uses to complete its resolution.
|
|
10
|
+
*
|
|
11
|
+
* ## The `connectionFor(intent)` resolution order (design §3, v1 `DBModel.ts:313` parity)
|
|
12
|
+
*
|
|
13
|
+
* A statement's connection is resolved in THIS priority (first match wins):
|
|
14
|
+
* 1. **active tx connection** — inside a transaction, always the tx-owned connection (Phase A).
|
|
15
|
+
* 2. **writer scope / writer-sticky** — inside {@link withWriter}, or within `writerStickyDuration`
|
|
16
|
+
* after a transaction (read-your-writes), a READ goes to the WRITER pool (Phase C — here).
|
|
17
|
+
* 3. **read=reader / write=writer** — otherwise a read goes to the reader pool, a write to the
|
|
18
|
+
* writer pool (reader/writer separation; single-pool config ⇒ reader === writer, Phase C).
|
|
19
|
+
* 4. **named-DB routing** — the target pool is selected by `intent.db` (the connection NAME carried
|
|
20
|
+
* by the bundle/model metadata) against the {@link ConnectionRegistry}; absent ⇒ the DEFAULT
|
|
21
|
+
* connection. Named-DB selection happens FIRST (it picks WHICH connection's reader/writer split
|
|
22
|
+
* steps 2-3 then apply to), so the order above is really: pick the named connection, then within
|
|
23
|
+
* it apply tx-pin / writer-sticky / reader-writer. (Phase C, decorator-free — the routing key is
|
|
24
|
+
* config + bundle/model metadata; decorator wiring is Phase F.)
|
|
25
|
+
*
|
|
26
|
+
* ## Backward-compat (the hard constraint)
|
|
27
|
+
*
|
|
28
|
+
* Single DB, `reader === writer` (one pool), empty config, unnamed connection ⇒ BYTE-IDENTICAL to the
|
|
29
|
+
* Phase A/B single-pool behavior. A {@link ConnectionRegistry} built from ONE pool routes every
|
|
30
|
+
* intent to that ONE pool, and the writer-sticky clock only ever diverts to a pool that is the SAME
|
|
31
|
+
* object — so nothing observable changes. The existing `new PooledAsyncContext(pool)` /
|
|
32
|
+
* `new PooledAsyncContext(pool, middleware)` constructors keep working unchanged.
|
|
33
|
+
*/
|
|
34
|
+
import type { AsyncConnectionPool } from './exec-context';
|
|
35
|
+
/**
|
|
36
|
+
* Per-connection database config (C3) — the knobs a pool is built with. Mirrors v1
|
|
37
|
+
* `DBConfig`/`DBHandler` (`src/DBHandler.ts`, `src/types.ts`): connection target + pool sizing +
|
|
38
|
+
* per-statement/keepalive/session knobs. Every field is optional with a documented default; the 4
|
|
39
|
+
* native ports MUST expose the SAME field names + defaults. This is a DATA contract — it describes
|
|
40
|
+
* how to BUILD a pool; the actual `pg.Pool` / `mysql2.createPool` construction lives in the driver
|
|
41
|
+
* adapters (`makesql/pool-executor.ts`), which read these fields.
|
|
42
|
+
*/
|
|
43
|
+
export interface ConnectionConfig {
|
|
44
|
+
/** Driver dialect for this connection. @default 'postgres' */
|
|
45
|
+
readonly driver?: 'postgres' | 'mysql' | 'sqlite';
|
|
46
|
+
/** DB host (server-based dialects). */
|
|
47
|
+
readonly host?: string;
|
|
48
|
+
/** DB port. */
|
|
49
|
+
readonly port?: number;
|
|
50
|
+
/** DB name (or file path for sqlite). */
|
|
51
|
+
readonly database?: string;
|
|
52
|
+
/** Username. */
|
|
53
|
+
readonly user?: string;
|
|
54
|
+
/** Password. */
|
|
55
|
+
readonly password?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Per-statement timeout in MILLISECONDS. Applied as a session `statement_timeout` (PG) /
|
|
58
|
+
* `max_execution_time` (MySQL) so a runaway query is aborted by the SERVER. `0`/absent ⇒ no
|
|
59
|
+
* statement timeout (the engine default). v1 exposed this as `queryTimeout` in SECONDS on the pg
|
|
60
|
+
* CLIENT (`query_timeout`); the v2 contract is server-side ms so it fires uniformly across drivers.
|
|
61
|
+
* @default 0 (no timeout)
|
|
62
|
+
*/
|
|
63
|
+
readonly queryTimeout?: number;
|
|
64
|
+
/** Enable TCP keepalive on pooled connections (recommended for serverless). @default false */
|
|
65
|
+
readonly keepAlive?: boolean;
|
|
66
|
+
/** ms before the first keepalive probe. @default 10000 (when keepAlive) */
|
|
67
|
+
readonly keepAliveInitialDelayMillis?: number;
|
|
68
|
+
/** Minimum pooled connections kept warm. @default 0 */
|
|
69
|
+
readonly minPool?: number;
|
|
70
|
+
/** Maximum pooled connections. @default 10 */
|
|
71
|
+
readonly maxPool?: number;
|
|
72
|
+
/** PG `search_path` set on each pooled connection at checkout (schema routing). */
|
|
73
|
+
readonly searchPath?: string;
|
|
74
|
+
/** MySQL connection charset / PG client_encoding set on each pooled connection. */
|
|
75
|
+
readonly charset?: string;
|
|
76
|
+
}
|
|
77
|
+
/** The resolved (defaults-applied) config the pool builder consumes — no `undefined` holes on the knobs. */
|
|
78
|
+
export interface ResolvedConnectionConfig {
|
|
79
|
+
readonly driver: 'postgres' | 'mysql' | 'sqlite';
|
|
80
|
+
readonly host?: string;
|
|
81
|
+
readonly port?: number;
|
|
82
|
+
readonly database?: string;
|
|
83
|
+
readonly user?: string;
|
|
84
|
+
readonly password?: string;
|
|
85
|
+
readonly queryTimeout: number;
|
|
86
|
+
readonly keepAlive: boolean;
|
|
87
|
+
readonly keepAliveInitialDelayMillis: number;
|
|
88
|
+
readonly minPool: number;
|
|
89
|
+
readonly maxPool: number;
|
|
90
|
+
readonly searchPath?: string;
|
|
91
|
+
readonly charset?: string;
|
|
92
|
+
}
|
|
93
|
+
/** Apply the C3 defaults (queryTimeout=0, keepAlive=false, minPool=0, maxPool=10). */
|
|
94
|
+
export declare function resolveConnectionConfig(config?: ConnectionConfig): ResolvedConnectionConfig;
|
|
95
|
+
/**
|
|
96
|
+
* The SESSION statements a connection must run at checkout to honor a {@link ResolvedConnectionConfig}
|
|
97
|
+
* (issued once per acquired connection, in order). This is the per-dialect mapping the port agents
|
|
98
|
+
* mirror; it is pure (no connection contact) so it is testable in isolation:
|
|
99
|
+
*
|
|
100
|
+
* - **statement timeout** (`queryTimeout` > 0): PG `SET statement_timeout = <ms>`; MySQL
|
|
101
|
+
* `SET SESSION max_execution_time = <ms>` (both server-side, ms).
|
|
102
|
+
* - **searchPath**: PG `SET search_path TO <path>`; MySQL has no schema search path ⇒ ignored.
|
|
103
|
+
* - **charset**: MySQL `SET NAMES <charset>`; PG `SET client_encoding TO <charset>`.
|
|
104
|
+
*
|
|
105
|
+
* A key with no value emits nothing (⇒ empty array for an all-default config ⇒ the session is
|
|
106
|
+
* untouched, backward-compatible). sqlite has no server session ⇒ empty.
|
|
107
|
+
*/
|
|
108
|
+
export declare function sessionStatements(config: ResolvedConnectionConfig): readonly string[];
|
|
109
|
+
/**
|
|
110
|
+
* A reader/writer pool PAIR for ONE named connection (C1). `reader` serves read-intent statements;
|
|
111
|
+
* `writer` serves write-intent statements, `withWriter` reads, and writer-sticky reads. When a
|
|
112
|
+
* connection has no separate replica, `reader === writer` is the SAME pool object — reader/writer
|
|
113
|
+
* routing then always lands on that one pool (the single-pool backward-compat case).
|
|
114
|
+
*/
|
|
115
|
+
export interface ReaderWriterPools {
|
|
116
|
+
readonly reader: AsyncConnectionPool;
|
|
117
|
+
readonly writer: AsyncConnectionPool;
|
|
118
|
+
}
|
|
119
|
+
/** Build a {@link ReaderWriterPools} where reader === writer (single-pool, backward-compat). */
|
|
120
|
+
export declare function singlePoolPair(pool: AsyncConnectionPool): ReaderWriterPools;
|
|
121
|
+
/** Build a {@link ReaderWriterPools} from a distinct reader + writer pool (reader/writer separation). */
|
|
122
|
+
export declare function readerWriterPair(reader: AsyncConnectionPool, writer: AsyncConnectionPool): ReaderWriterPools;
|
|
123
|
+
/** The reserved name of the DEFAULT (unnamed) connection. An `intent.db` of `undefined` uses this. */
|
|
124
|
+
export declare const DEFAULT_CONNECTION = "default";
|
|
125
|
+
/**
|
|
126
|
+
* The multi-DB connection registry (C2): a map from a connection NAME → its {@link ReaderWriterPools}.
|
|
127
|
+
* `connectionFor(intent)` selects the pair by `intent.db` (the connection name the bundle/model
|
|
128
|
+
* metadata carries — decorator-free, from config + metadata; decorator wiring is Phase F), falling
|
|
129
|
+
* back to {@link DEFAULT_CONNECTION} when unnamed. Selecting a name that was never registered is a
|
|
130
|
+
* LOUD error (a real wiring bug — never a silent default fallback, which would run a query on the
|
|
131
|
+
* wrong DB; mirrors the V0 cross-DB relation registry's loud-fail policy).
|
|
132
|
+
*
|
|
133
|
+
* A single-DB deployment registers exactly one connection under {@link DEFAULT_CONNECTION} with
|
|
134
|
+
* `reader === writer` ⇒ every intent routes to that one pool ⇒ byte-identical to Phase A/B.
|
|
135
|
+
*/
|
|
136
|
+
export declare class ConnectionRegistry {
|
|
137
|
+
/** name → reader/writer pools. */
|
|
138
|
+
private readonly connections;
|
|
139
|
+
constructor(connections: ReadonlyMap<string, ReaderWriterPools>);
|
|
140
|
+
/**
|
|
141
|
+
* Build a registry from ONE pool as the default connection (reader === writer). This is the
|
|
142
|
+
* backward-compat path: {@link import('./exec-context').PooledAsyncContext} built from a single
|
|
143
|
+
* pool wraps it here so its `connectionFor` routes every intent to that one pool.
|
|
144
|
+
*/
|
|
145
|
+
static singleDefault(pool: AsyncConnectionPool): ConnectionRegistry;
|
|
146
|
+
/** Fluent builder: start from a default connection's pools, then `.add(name, pools)` more. */
|
|
147
|
+
static fromDefault(pools: ReaderWriterPools): ConnectionRegistryBuilder;
|
|
148
|
+
/** The reader/writer pair for `name` (or {@link DEFAULT_CONNECTION} when `undefined`). Loud on a missing name. */
|
|
149
|
+
pairFor(name: string | undefined): ReaderWriterPools;
|
|
150
|
+
/** The registered connection names (for diagnostics / `closeAllPools`). */
|
|
151
|
+
names(): readonly string[];
|
|
152
|
+
/** Every DISTINCT pool object across all connections (a shared reader===writer counts once). */
|
|
153
|
+
distinctPools(): readonly AsyncConnectionPool[];
|
|
154
|
+
}
|
|
155
|
+
/** Incremental {@link ConnectionRegistry} builder (name → pools). */
|
|
156
|
+
export declare class ConnectionRegistryBuilder {
|
|
157
|
+
private readonly connections;
|
|
158
|
+
/** Register `name` → its reader/writer pools (chainable). Re-adding a name overwrites it. */
|
|
159
|
+
add(name: string, pools: ReaderWriterPools): this;
|
|
160
|
+
/** Finalize into an immutable {@link ConnectionRegistry}. */
|
|
161
|
+
build(): ConnectionRegistry;
|
|
162
|
+
}
|
|
163
|
+
/** True if the current async scope is inside a {@link withWriter} scope. */
|
|
164
|
+
export declare function inWriterScope(): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Run `fn` with reads pinned to the WRITER pool (mirror v1 `DBModel.withWriter`): every read `fn`
|
|
167
|
+
* issues resolves the writer pool (read-your-writes without replication lag), and — because this ALSO
|
|
168
|
+
* enters a {@link import('./tx-options').withReadOnly} scope — ANY write inside `fn` throws
|
|
169
|
+
* {@link import('../types').WriteInReadOnlyContextError}. Nested `withWriter` is idempotent (already
|
|
170
|
+
* in a writer scope ⇒ just run `fn`). Inside a transaction the tx-owned connection already wins in
|
|
171
|
+
* `connectionFor`, so a `withWriter` there is a no-op on routing (matches v1 :2941).
|
|
172
|
+
*
|
|
173
|
+
* @param fn the read-your-writes scope body.
|
|
174
|
+
*/
|
|
175
|
+
export declare function withWriter<R>(fn: () => Promise<R>): Promise<R>;
|
|
176
|
+
/**
|
|
177
|
+
* A writer-sticky CLOCK (C1, read-your-writes; v1 `_shouldUseWriterSticky` :344 + `_lastTransactionTime`).
|
|
178
|
+
* After a transaction (or a bare write) COMMITs, reads within `stickyDurationMs` route to the WRITER
|
|
179
|
+
* pool so a just-committed row is visible despite reader-replica lag. The ctx owns ONE clock instance;
|
|
180
|
+
* the tx runtime `.mark()`s it on every successful write/commit; `connectionFor` reads `.isSticky()`.
|
|
181
|
+
*
|
|
182
|
+
* `useWriterAfterTransaction=false` disables it entirely (`.isSticky()` always false). A single-pool
|
|
183
|
+
* deployment (reader === writer) is unaffected by stickiness — the diverted pool is the same object.
|
|
184
|
+
*/
|
|
185
|
+
export declare class WriterStickyClock {
|
|
186
|
+
private lastWriteAt;
|
|
187
|
+
private readonly enabled;
|
|
188
|
+
private readonly stickyDurationMs;
|
|
189
|
+
/** Injectable clock (tests advance it); defaults to `Date.now`. */
|
|
190
|
+
private readonly now;
|
|
191
|
+
constructor(opts?: {
|
|
192
|
+
useWriterAfterTransaction?: boolean;
|
|
193
|
+
writerStickyDuration?: number;
|
|
194
|
+
now?: () => number;
|
|
195
|
+
});
|
|
196
|
+
/** Record that a write/commit just happened (the tx runtime calls this on success). */
|
|
197
|
+
mark(): void;
|
|
198
|
+
/** Is a read currently sticky-to-writer (within `writerStickyDuration` of the last write)? */
|
|
199
|
+
isSticky(): boolean;
|
|
200
|
+
/** Reset the clock (e.g. between tests / on `closeAllPools`). */
|
|
201
|
+
reset(): void;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The routing configuration a {@link import('./exec-context').PooledAsyncContext} carries to complete
|
|
205
|
+
* its `connectionFor(intent)` resolution (steps 2-4): the multi-DB {@link ConnectionRegistry}, the
|
|
206
|
+
* {@link WriterStickyClock}, and the resolved per-connection {@link ResolvedConnectionConfig} (for the
|
|
207
|
+
* session statements the pool applies). Absent ⇒ the ctx falls back to its single default pool with
|
|
208
|
+
* an always-false sticky clock — the byte-identical Phase A/B path.
|
|
209
|
+
*/
|
|
210
|
+
export interface RoutingConfig {
|
|
211
|
+
readonly registry: ConnectionRegistry;
|
|
212
|
+
readonly sticky: WriterStickyClock;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Resolve WHICH pool serves a statement given its {@link import('./exec-context').StatementIntent}
|
|
216
|
+
* and the routing config — the completion of `connectionFor`'s steps 2-4 (step 1, the tx-pin, is
|
|
217
|
+
* handled by the ctx BEFORE calling this, since only the ctx holds the ALS pin). The order:
|
|
218
|
+
*
|
|
219
|
+
* 1. **named-DB** (`intent.db`) selects the {@link ReaderWriterPools} pair (loud on unknown name).
|
|
220
|
+
* 2. within that pair: a WRITE ⇒ the writer pool.
|
|
221
|
+
* 3. a READ in a {@link withWriter} scope OR within writer-sticky ⇒ the writer pool (read-your-writes).
|
|
222
|
+
* 4. otherwise a READ ⇒ the reader pool.
|
|
223
|
+
*
|
|
224
|
+
* Single-pool (reader === writer) ⇒ every branch returns the same pool (backward-compat).
|
|
225
|
+
*/
|
|
226
|
+
export declare function resolvePool(intent: {
|
|
227
|
+
readonly write: boolean;
|
|
228
|
+
readonly db?: string;
|
|
229
|
+
}, routing: RoutingConfig): AsyncConnectionPool;
|
|
230
|
+
/**
|
|
231
|
+
* The RESET statements that undo {@link sessionStatements} on release (per dialect), so a session
|
|
232
|
+
* knob (`statement_timeout` / `search_path` / `client_encoding` / `max_execution_time` / charset)
|
|
233
|
+
* set for THIS configured connection does NOT leak to the next caller that draws the SAME underlying
|
|
234
|
+
* pooled connection — pg/mysql2 do NOT auto-reset session state on release. `RESET`/`SET … DEFAULT`
|
|
235
|
+
* restores the server default. Only the knobs `config` actually set are reset (an all-default config
|
|
236
|
+
* ⇒ nothing to reset).
|
|
237
|
+
*/
|
|
238
|
+
export declare function sessionResetStatements(config: ResolvedConnectionConfig): readonly string[];
|
|
239
|
+
/**
|
|
240
|
+
* Wrap an {@link AsyncConnectionPool} so every acquired connection first runs the
|
|
241
|
+
* {@link sessionStatements} for `config` (statement timeout / search_path / charset) and, on release,
|
|
242
|
+
* runs {@link sessionResetStatements} to restore the server defaults (so a pooled connection never
|
|
243
|
+
* leaks THIS config's session state to the next caller — pg/mysql2 don't auto-reset on release). A
|
|
244
|
+
* config with no session knobs (all defaults) ⇒ ZERO extra statements ⇒ the wrapper is a transparent
|
|
245
|
+
* passthrough (backward-compat). This is where C3's `queryTimeout`/`searchPath`/`charset` become REAL
|
|
246
|
+
* per-server effects — the acquired connection carries them for the statement(s) that run on it.
|
|
247
|
+
*
|
|
248
|
+
* If a session statement itself fails (e.g. an invalid search_path), the connection is released back
|
|
249
|
+
* as DESTROYED so a mis-configured connection never re-enters the pool. On release, if a statement
|
|
250
|
+
* ERRORED (the connection is possibly aborted — e.g. a fired statement timeout), the reset is SKIPPED
|
|
251
|
+
* and the connection is DESTROYED (a poisoned connection must not re-enter the pool anyway).
|
|
252
|
+
*/
|
|
253
|
+
export declare function configuredPool(pool: AsyncConnectionPool, config: ResolvedConnectionConfig): AsyncConnectionPool;
|
|
254
|
+
/** A pool CLOSER — closes a pool's underlying connections (pg `pool.end()` / mysql2 `pool.end()`). */
|
|
255
|
+
export type PoolCloser = () => Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* A driver's pool factory: BUILD a pool from a {@link ResolvedConnectionConfig}, returning the
|
|
258
|
+
* {@link AsyncConnectionPool} seam adapter plus a {@link PoolCloser}. This is where the CONSTRUCTION
|
|
259
|
+
* knobs — pool sizing (`minPool`/`maxPool`) + `keepAlive`/`keepAliveInitialDelayMillis` — reach the
|
|
260
|
+
* real driver (`new pg.Pool({ max, keepAlive, … })` / `mysql2.createPool({ connectionLimit, … })`),
|
|
261
|
+
* because those are pool-CONSTRUCTION options a pre-built pool can no longer accept.
|
|
262
|
+
*
|
|
263
|
+
* `buildRoutingConfig` OWNS the call to this factory with the RESOLVED config, so the configured
|
|
264
|
+
* sizing/keepAlive is the SOLE source of the pool's cap — there is no second raw `new Pool({max})`
|
|
265
|
+
* path. `role` lets a factory build a distinct replica pool for the reader vs. the writer (e.g. a
|
|
266
|
+
* different host) while sharing the same sizing config; a factory that returns the SAME pool for both
|
|
267
|
+
* roles collapses to single-pool (reader === writer).
|
|
268
|
+
*
|
|
269
|
+
* The module stays driver-AGNOSTIC: the factory is supplied by the peer-dep-owning caller (this file
|
|
270
|
+
* imports no driver). The pool-executor adapters (`makesql/pool-executor.ts`) provide the concrete
|
|
271
|
+
* pg/mysql2 factories; the port agents (#88-91) supply their language's equivalent — the SAME shape.
|
|
272
|
+
*/
|
|
273
|
+
export type PoolFactory = (config: ResolvedConnectionConfig, role: 'reader' | 'writer') => {
|
|
274
|
+
pool: AsyncConnectionPool;
|
|
275
|
+
close: PoolCloser;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* One connection's inputs to {@link buildRoutingConfig}: its NAME (default when absent), its
|
|
279
|
+
* {@link ConnectionConfig} (connection params + sizing + keepAlive + session knobs), and a
|
|
280
|
+
* {@link PoolFactory} that `buildRoutingConfig` CALLS with the resolved config to construct the
|
|
281
|
+
* pool(s) — so sizing/keepAlive are applied at construction and the config is the sole cap source.
|
|
282
|
+
*
|
|
283
|
+
* `separateWriter: true` asks the factory for a DISTINCT writer pool (reader/writer replica split);
|
|
284
|
+
* otherwise the factory's reader pool is reused as the writer (single-pool, reader === writer).
|
|
285
|
+
*/
|
|
286
|
+
export interface ConnectionSetup {
|
|
287
|
+
readonly name?: string;
|
|
288
|
+
readonly config?: ConnectionConfig;
|
|
289
|
+
/** The driver pool factory (built by `buildRoutingConfig` with the resolved config — sizing/keepAlive land here). */
|
|
290
|
+
readonly poolFactory: PoolFactory;
|
|
291
|
+
/** Build a distinct writer pool via the factory (replica split). Default false ⇒ reader === writer. */
|
|
292
|
+
readonly separateWriter?: boolean;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The C3 `setConfig` result: the {@link RoutingConfig} a {@link import('./exec-context').PooledAsyncContext}
|
|
296
|
+
* runs on, plus a `close()` that shuts every constructed pool ({@link closeAllPools}). Build it from
|
|
297
|
+
* one or more {@link ConnectionSetup}s (the one named `default`, or the first unnamed, is the default
|
|
298
|
+
* connection).
|
|
299
|
+
*
|
|
300
|
+
* For each setup: resolve the config, CALL its {@link PoolFactory} to construct the pool(s) — so
|
|
301
|
+
* `minPool`/`maxPool`/`keepAlive`/`keepAliveInitialDelayMillis` are applied at `new Pool()` /
|
|
302
|
+
* `createPool()` time (the config is the SOLE source of the cap) — then wrap each pool with
|
|
303
|
+
* {@link configuredPool} so the SESSION knobs (queryTimeout/searchPath/charset) apply on checkout.
|
|
304
|
+
*/
|
|
305
|
+
export declare function buildRoutingConfig(setups: readonly ConnectionSetup[], stickyOpts?: {
|
|
306
|
+
useWriterAfterTransaction?: boolean;
|
|
307
|
+
writerStickyDuration?: number;
|
|
308
|
+
}): {
|
|
309
|
+
routing: RoutingConfig;
|
|
310
|
+
close: PoolCloser;
|
|
311
|
+
};
|
|
312
|
+
//# sourceMappingURL=connection-routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-routing.d.ts","sourceRoot":"","sources":["../../src/scp/connection-routing.ts"],"names":[],"mappings":"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"}
|