@dbsp/adapter-pgsql 1.11.2 → 3.0.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/dist/index.d.ts +1641 -1299
- package/dist/index.js +16770 -13599
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IndexInfo, TruncateOptions, VacuumOptions, AlterColumnOptions, CreateIndexOptions, DropIndexOptions, ExpressionRef, ModelIR as ModelIR$1 } from '@dbsp/core';
|
|
2
2
|
export { normalizeSQL } from '@dbsp/core';
|
|
3
3
|
import * as _dbsp_types from '@dbsp/types';
|
|
4
|
-
import {
|
|
4
|
+
import { DialectCapabilities, ModelIR, ColumnListInput, ParamIntent, JsonAggOrderByEntry, IndexIR, HierarchyIR, Adapter, DbCasing, AdapterLogger, AdapterCapabilities, PlanReport, CompiledNqlQuery, CompileOptions, CompiledQuery, CompileResultWithIncludes, SubqueryIncludeInfo, ExpressionIntent, InsertIntent, InsertFromIntent, UpdateIntent, BatchUpdateIntent, DeleteIntent, UpsertIntent, UpsertFromIntent, RecursivePlanReport, CteQueryIntent, SetOperationIntent, DumpMeta, Dump, AdapterStreamOptions, CompileOnlyAdapter, ColumnIR, MutationReturningItem, WhereIntent, QueryIntent } from '@dbsp/types';
|
|
5
5
|
import * as _pgsql_types from '@pgsql/types';
|
|
6
6
|
import { Node, OnConflictClause, ParamRef } from '@pgsql/types';
|
|
7
7
|
import { Pool, PoolClient } from 'pg';
|
|
@@ -99,6 +99,253 @@ declare function getNamingPluginForDbCasing(casing: 'snake_case' | 'camelCase' |
|
|
|
99
99
|
|
|
100
100
|
type BindingNameRegistry = ReadonlySet<string>;
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Immutable context passed to all handlers during compilation.
|
|
104
|
+
*/
|
|
105
|
+
interface CompilerContext {
|
|
106
|
+
/** Naming convention transformer */
|
|
107
|
+
readonly naming: NamingPlugin;
|
|
108
|
+
/** Schema name for table qualification (optional) */
|
|
109
|
+
readonly schema?: string;
|
|
110
|
+
/** Dialect capabilities for adapter-layer SQL surface gates */
|
|
111
|
+
readonly dialectCapabilities?: DialectCapabilities;
|
|
112
|
+
/** Root table name for the query */
|
|
113
|
+
readonly rootTable: string;
|
|
114
|
+
/** Current table alias (for JOINs) */
|
|
115
|
+
readonly currentAlias?: string;
|
|
116
|
+
/** Final relation path/name → SQL join alias map for relation-aware expression contexts */
|
|
117
|
+
readonly aliases?: ReadonlyMap<string, string>;
|
|
118
|
+
/** Maximum recursive depth (default: 100) */
|
|
119
|
+
readonly maxRecursiveDepth: number;
|
|
120
|
+
/** Optional callback for raw SQL audit trail */
|
|
121
|
+
readonly onRawSQL?: (sql: string) => void;
|
|
122
|
+
/** Default primary key column name for convention fallbacks (default: 'id') */
|
|
123
|
+
readonly defaultPkColumnName?: string;
|
|
124
|
+
/** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
|
|
125
|
+
readonly deriveFkColumnName?: FkColumnDerivation;
|
|
126
|
+
/** Alias of the outer (parent) query — used for FieldRef scope:'outer' resolution in EXISTS subqueries */
|
|
127
|
+
readonly outerAlias?: string;
|
|
128
|
+
/** Query-local CTE/binding names that must not be schema-qualified. */
|
|
129
|
+
readonly bindingNames?: BindingNameRegistry;
|
|
130
|
+
/**
|
|
131
|
+
* Optional callback to compile a QueryIntent into an AST Node (SubLink subselect).
|
|
132
|
+
* Set by PlanCompiler when compiling selectCustomExpression — enables SubqueryExpressionIntent
|
|
133
|
+
* to embed a fully compiled sub-SELECT into the parent SELECT column list.
|
|
134
|
+
*
|
|
135
|
+
* @param query - The inner QueryIntent to compile
|
|
136
|
+
* @param paramOffset - Current outer paramIndex; inner $N are renumbered by this offset
|
|
137
|
+
* @returns The compiled SelectStmt AST node and the inner parameters
|
|
138
|
+
*/
|
|
139
|
+
readonly compileSubquery?: (query: _dbsp_types.QueryIntent, paramOffset: number) => {
|
|
140
|
+
ast: Node;
|
|
141
|
+
parameters: readonly unknown[];
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Optional recursive compiler for NQL-origin SELECT expression values nested
|
|
145
|
+
* inside handler arguments, such as coalesce(upper(name), :fallback) or
|
|
146
|
+
* (price + :a) * :b.
|
|
147
|
+
*/
|
|
148
|
+
readonly compileNqlSelectExpression?: (value: unknown, ctx: CompilerContext, state: CompilerState) => Node;
|
|
149
|
+
/**
|
|
150
|
+
* Optional callback to compile a custom fn() FILTER (WHERE ...) condition.
|
|
151
|
+
* Set by PlanCompiler to keep WHERE-dispatcher dependencies out of expression
|
|
152
|
+
* handlers while still applying FILTER in every expression position.
|
|
153
|
+
*/
|
|
154
|
+
readonly compileCustomFnFilter?: (filterIntent: _dbsp_types.WhereIntent, ctx: CompilerContext, state: CompilerState) => Node | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Optional ModelIR for type-aware parameter casting.
|
|
157
|
+
* When provided, WHERE comparisons emit `$N::type` to eliminate
|
|
158
|
+
* PostgreSQL type inference ambiguity for nullable columns.
|
|
159
|
+
*/
|
|
160
|
+
readonly model?: ModelIR;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Mutable state maintained during compilation.
|
|
164
|
+
*/
|
|
165
|
+
interface CompilerState {
|
|
166
|
+
/** Collected parameters in order */
|
|
167
|
+
parameters: unknown[];
|
|
168
|
+
/** Current parameter index (1-based for PostgreSQL) */
|
|
169
|
+
paramIndex: number;
|
|
170
|
+
/** Registered CTEs for the query */
|
|
171
|
+
ctes: Map<string, Node>;
|
|
172
|
+
/** Table aliases in use */
|
|
173
|
+
aliases: Map<string, string>;
|
|
174
|
+
/** JOIN clauses accumulated */
|
|
175
|
+
joins: Node[];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Base decision interface matching core's PlanDecision structure.
|
|
179
|
+
*/
|
|
180
|
+
interface Decision {
|
|
181
|
+
readonly type: string;
|
|
182
|
+
readonly table?: string;
|
|
183
|
+
readonly column?: string;
|
|
184
|
+
readonly alias?: string;
|
|
185
|
+
readonly operator?: string;
|
|
186
|
+
readonly value?: unknown;
|
|
187
|
+
readonly paramIndex?: number;
|
|
188
|
+
readonly dataType?: string;
|
|
189
|
+
readonly direction?: 'ASC' | 'DESC';
|
|
190
|
+
readonly nulls?: 'FIRST' | 'LAST';
|
|
191
|
+
readonly joinType?: 'inner' | 'left';
|
|
192
|
+
readonly sourceColumn?: ColumnListInput;
|
|
193
|
+
readonly targetColumn?: ColumnListInput;
|
|
194
|
+
readonly targetTable?: string;
|
|
195
|
+
readonly function?: string;
|
|
196
|
+
/** Apply DISTINCT to a SELECT-list aggregate (e.g. COUNT(DISTINCT col)). */
|
|
197
|
+
readonly distinct?: boolean;
|
|
198
|
+
readonly args?: readonly unknown[];
|
|
199
|
+
readonly conditions?: readonly Decision[];
|
|
200
|
+
readonly columns?: readonly string[];
|
|
201
|
+
readonly values?: readonly unknown[];
|
|
202
|
+
readonly set?: readonly {
|
|
203
|
+
column: string;
|
|
204
|
+
value: unknown;
|
|
205
|
+
}[];
|
|
206
|
+
readonly limit?: number | ParamIntent | {
|
|
207
|
+
paramIndex: number;
|
|
208
|
+
};
|
|
209
|
+
readonly offset?: number | ParamIntent | {
|
|
210
|
+
paramIndex: number;
|
|
211
|
+
};
|
|
212
|
+
readonly strategy?: 'join' | 'lateral' | 'json_agg' | 'cte';
|
|
213
|
+
readonly relation?: string;
|
|
214
|
+
readonly relationName?: string;
|
|
215
|
+
readonly relationPath?: string;
|
|
216
|
+
readonly hydrationPrefix?: string;
|
|
217
|
+
readonly include?: readonly Decision[];
|
|
218
|
+
readonly relationType?: 'belongsTo' | 'hasMany' | 'hasOne';
|
|
219
|
+
readonly foreignKey?: ColumnListInput;
|
|
220
|
+
readonly parentKey?: ColumnListInput;
|
|
221
|
+
readonly orderByFallback?: boolean;
|
|
222
|
+
readonly children?: readonly Decision[];
|
|
223
|
+
readonly partition?: readonly string[];
|
|
224
|
+
readonly orderBy?: readonly {
|
|
225
|
+
column: string;
|
|
226
|
+
direction?: 'ASC' | 'DESC';
|
|
227
|
+
}[] | readonly JsonAggOrderByEntry[];
|
|
228
|
+
readonly frame?: string;
|
|
229
|
+
readonly maxDepth?: number;
|
|
230
|
+
readonly pathColumn?: string;
|
|
231
|
+
readonly cycleDetection?: boolean;
|
|
232
|
+
readonly selectColumn?: string;
|
|
233
|
+
readonly aggregate?: string;
|
|
234
|
+
/**
|
|
235
|
+
* Apply DISTINCT to a scalar subquery's aggregate (e.g. AVG(DISTINCT price)).
|
|
236
|
+
* Deliberately NOT named `distinct` — `assertNoDroppedDecisionModifiers`
|
|
237
|
+
* (subquery-emission.ts) treats a top-level `distinct === true` on ANY
|
|
238
|
+
* subquery decision as an unsupported query-level DISTINCT modifier and
|
|
239
|
+
* throws. This field is scoped to the aggregate projection only, so it
|
|
240
|
+
* must not collide with that generic guard.
|
|
241
|
+
*/
|
|
242
|
+
readonly aggregateDistinct?: boolean;
|
|
243
|
+
readonly subqueryOperator?: string;
|
|
244
|
+
readonly traversal?: string;
|
|
245
|
+
readonly traversals?: readonly {
|
|
246
|
+
traversal: string;
|
|
247
|
+
targetColumn?: string;
|
|
248
|
+
}[];
|
|
249
|
+
readonly isRecursive?: boolean;
|
|
250
|
+
readonly fkColumn?: string;
|
|
251
|
+
readonly pkColumn?: string;
|
|
252
|
+
readonly expandRelation?: string;
|
|
253
|
+
readonly relationColumns?: readonly string[];
|
|
254
|
+
readonly columnAliases?: Readonly<Record<string, string>>;
|
|
255
|
+
readonly jsonPath?: readonly unknown[];
|
|
256
|
+
readonly jsonMode?: 'json' | 'text';
|
|
257
|
+
readonly _compiledFilterWhere?: _pgsql_types.Node;
|
|
258
|
+
readonly filterWhere?: _pgsql_types.Node;
|
|
259
|
+
readonly expressionIntent?: unknown;
|
|
260
|
+
readonly escape?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Provenance: the ORIGINAL QueryIntent before lowering.
|
|
263
|
+
* Set by every lowering site (convertIn, convertSubquery, normalizeToDecision,
|
|
264
|
+
* dispatchWhere, mapInSubqueryCondition) so that `buildPredicateSubquerySelect`
|
|
265
|
+
* (subquery-emission.ts) can validate the true caller intent rather than the
|
|
266
|
+
* stripped-down lowered decision fields.
|
|
267
|
+
*
|
|
268
|
+
* Required for IN / scalar / inSubquery / notInSubquery decisions.
|
|
269
|
+
* Optional on other decision types.
|
|
270
|
+
*/
|
|
271
|
+
readonly subqueryIntent?: _dbsp_types.QueryIntent;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Handler for WHERE clause conditions.
|
|
275
|
+
* Transforms condition decisions into PostgreSQL AST expressions.
|
|
276
|
+
*/
|
|
277
|
+
interface WhereHandler {
|
|
278
|
+
/** Operator(s) this handler supports */
|
|
279
|
+
readonly operators: readonly string[];
|
|
280
|
+
/**
|
|
281
|
+
* Compile a WHERE condition to AST.
|
|
282
|
+
* @param decision The condition decision
|
|
283
|
+
* @param ctx Immutable compiler context
|
|
284
|
+
* @param state Mutable compiler state
|
|
285
|
+
* @param dispatch Callback to compile nested conditions
|
|
286
|
+
* @returns PostgreSQL AST node for the condition
|
|
287
|
+
*/
|
|
288
|
+
compile(decision: Decision, ctx: CompilerContext, state: CompilerState, dispatch: WhereDispatcher): Node;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Dispatcher for recursive WHERE compilation.
|
|
292
|
+
*/
|
|
293
|
+
type WhereDispatcher = (decision: Decision, ctx: CompilerContext, state: CompilerState) => Node;
|
|
294
|
+
/**
|
|
295
|
+
* Handler for SELECT expressions.
|
|
296
|
+
* Transforms expression decisions into PostgreSQL AST nodes.
|
|
297
|
+
*/
|
|
298
|
+
interface ExpressionHandler {
|
|
299
|
+
/** Expression type(s) this handler supports */
|
|
300
|
+
readonly types: readonly string[];
|
|
301
|
+
/**
|
|
302
|
+
* Safe to use when a function name comes from NQL text.
|
|
303
|
+
*
|
|
304
|
+
* Raw/escape-hatch handlers must not set this. NQL-origin function names use
|
|
305
|
+
* this opt-in surface only, then fall back to generic FuncCall emission.
|
|
306
|
+
*/
|
|
307
|
+
readonly nqlSafe?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Compile an expression to AST.
|
|
310
|
+
* @param decision The expression decision
|
|
311
|
+
* @param ctx Immutable compiler context
|
|
312
|
+
* @param state Mutable compiler state
|
|
313
|
+
* @returns PostgreSQL AST node for the expression
|
|
314
|
+
*/
|
|
315
|
+
compile(decision: Decision, ctx: CompilerContext, state: CompilerState): Node;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Handler for include/relation strategies.
|
|
319
|
+
* Transforms include decisions into PostgreSQL constructs (JOIN, LATERAL, json_agg, CTE).
|
|
320
|
+
*/
|
|
321
|
+
interface IncludeHandler {
|
|
322
|
+
/** Strategy this handler implements */
|
|
323
|
+
readonly strategy: 'join' | 'lateral' | 'json_agg' | 'cte';
|
|
324
|
+
/**
|
|
325
|
+
* Compile an include to AST.
|
|
326
|
+
* @param decision The include decision
|
|
327
|
+
* @param ctx Immutable compiler context
|
|
328
|
+
* @param state Mutable compiler state
|
|
329
|
+
* @returns Object with modifications to apply
|
|
330
|
+
*/
|
|
331
|
+
compile(decision: Decision, ctx: CompilerContext, state: CompilerState): IncludeResult;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Result of include compilation.
|
|
335
|
+
*/
|
|
336
|
+
interface IncludeResult {
|
|
337
|
+
/** Additional target list items (SELECT columns) */
|
|
338
|
+
targets?: Node[];
|
|
339
|
+
/** JOIN to add to FROM clause */
|
|
340
|
+
join?: Node;
|
|
341
|
+
/** Additional JOINs for cascaded includes (e.g., flat deep nesting) */
|
|
342
|
+
additionalJoins?: Node[];
|
|
343
|
+
/** CTE to add to WITH clause */
|
|
344
|
+
cte?: Node;
|
|
345
|
+
/** Subquery for LATERAL */
|
|
346
|
+
lateral?: Node;
|
|
347
|
+
}
|
|
348
|
+
|
|
102
349
|
type PlanExpressionOrderBy = readonly {
|
|
103
350
|
field: string;
|
|
104
351
|
direction?: 'asc' | 'desc';
|
|
@@ -459,11 +706,9 @@ declare class PlanCompiler {
|
|
|
459
706
|
private compileCaseValue;
|
|
460
707
|
/**
|
|
461
708
|
* Compile a custom ExpressionIntent (customFn, customOp, ref, cast, unary,
|
|
462
|
-
* array, function, subquery, …) to an AST node
|
|
463
|
-
*
|
|
464
|
-
* THEN/ELSE values so both render the full expression surface identically
|
|
465
|
-
* (every expression kind + FILTER), rather than one path silently binding
|
|
466
|
-
* expressions as parameters or dropping FILTER.
|
|
709
|
+
* array, function, subquery, …) to an AST node through the shared expression
|
|
710
|
+
* compiler. Shared by the `selectCustomExpression` target path and CASE
|
|
711
|
+
* THEN/ELSE values so both render the full expression surface identically.
|
|
467
712
|
*/
|
|
468
713
|
private compileCustomExpressionNode;
|
|
469
714
|
private compileInsert;
|
|
@@ -494,7 +739,11 @@ declare function compilePlan(plan: SimplifiedPlanReport, options?: CompilerOptio
|
|
|
494
739
|
interface GenerateDDLOptions {
|
|
495
740
|
/** Include DROP TABLE IF EXISTS statements before CREATE TABLE */
|
|
496
741
|
readonly includeDropStatements?: boolean;
|
|
497
|
-
/**
|
|
742
|
+
/**
|
|
743
|
+
* Database schema name (e.g., 'public', 'tenant_123').
|
|
744
|
+
* Required when emitted DDL would otherwise mix non-default target-scoped
|
|
745
|
+
* custom types/enums with unqualified table SQL.
|
|
746
|
+
*/
|
|
498
747
|
readonly schemaName?: string;
|
|
499
748
|
/**
|
|
500
749
|
* Automatically create indexes on foreign key columns.
|
|
@@ -520,1302 +769,326 @@ interface GenerateDDLOptions {
|
|
|
520
769
|
* @returns Array of DDL statements in dependency order
|
|
521
770
|
*/
|
|
522
771
|
declare function generateDDL(schema: ModelIR, options?: GenerateDDLOptions): string[];
|
|
523
|
-
|
|
772
|
+
declare function generateCreateIndex(tableName: string, idx: IndexIR, schemaName: string | undefined, naming: NamingPlugin): string;
|
|
524
773
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
* Compares two ModelIRs (schema definition vs database state)
|
|
528
|
-
* and produces a structured diff of changes needed.
|
|
774
|
+
* Returns whether the PostgreSQL DDL generator can emit this IndexIR.
|
|
529
775
|
*
|
|
530
|
-
*
|
|
776
|
+
* Keep this as the single representability predicate for generated schema
|
|
777
|
+
* omission and destructive-drop classification: both sides must agree on the
|
|
778
|
+
* exact validation surface used by generateCreateIndex().
|
|
531
779
|
*/
|
|
532
|
-
|
|
533
|
-
type ChangeKind = 'create_table' | 'drop_table' | 'add_column' | 'drop_column' | 'alter_column_type' | 'alter_column_nullable' | 'alter_column_default' | 'alter_column_unique' | 'add_primary_key' | 'drop_primary_key' | 'add_foreign_key' | 'drop_foreign_key' | 'alter_foreign_key' | 'validate_constraint' | 'create_index' | 'drop_index' | 'add_check_constraint' | 'drop_check_constraint' | 'create_enum' | 'alter_enum_add_value' | 'drop_enum' | 'alter_column_collation' | 'alter_column_identity' | 'add_comment' | 'drop_comment' | 'create_extension' | 'drop_extension' | 'create_sequence' | 'alter_sequence' | 'drop_sequence' | 'enable_rls' | 'disable_rls' | 'create_policy' | 'drop_policy';
|
|
534
|
-
interface SchemaChange {
|
|
535
|
-
readonly kind: ChangeKind;
|
|
536
|
-
readonly table: string;
|
|
537
|
-
readonly column?: string;
|
|
538
|
-
readonly destructive: boolean;
|
|
539
|
-
readonly details: string;
|
|
540
|
-
/** Additional metadata for SQL generation */
|
|
541
|
-
readonly meta?: Readonly<Record<string, unknown>>;
|
|
542
|
-
}
|
|
543
|
-
interface DiffSummary {
|
|
544
|
-
readonly tables: {
|
|
545
|
-
readonly added: number;
|
|
546
|
-
readonly dropped: number;
|
|
547
|
-
};
|
|
548
|
-
readonly columns: {
|
|
549
|
-
readonly added: number;
|
|
550
|
-
readonly dropped: number;
|
|
551
|
-
readonly altered: number;
|
|
552
|
-
};
|
|
553
|
-
readonly indexes: {
|
|
554
|
-
readonly added: number;
|
|
555
|
-
readonly dropped: number;
|
|
556
|
-
};
|
|
557
|
-
readonly constraints: {
|
|
558
|
-
readonly added: number;
|
|
559
|
-
readonly dropped: number;
|
|
560
|
-
readonly altered: number;
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
interface SchemaDiff {
|
|
564
|
-
readonly changes: readonly SchemaChange[];
|
|
565
|
-
readonly hasDestructive: boolean;
|
|
566
|
-
readonly summary: DiffSummary;
|
|
567
|
-
}
|
|
568
|
-
interface CompareSchemataOptions {
|
|
569
|
-
/**
|
|
570
|
-
* Database naming convention.
|
|
571
|
-
* When set, schema model names (camelCase) are converted to DB format
|
|
572
|
-
* (e.g. snake_case) before comparison with the introspected model.
|
|
573
|
-
*/
|
|
574
|
-
dbCasing?: DbCasing;
|
|
575
|
-
/** Dialect capabilities — comparisons for unsupported features will be skipped */
|
|
576
|
-
readonly dialectCapabilities?: DialectCapabilities;
|
|
577
|
-
/**
|
|
578
|
-
* When `true`, extensions present in the live DB but absent from the model
|
|
579
|
-
* schema are silently ignored — no `drop_extension` change is emitted for them.
|
|
580
|
-
* Only extensions explicitly declared in the model are managed (created if missing).
|
|
581
|
-
*
|
|
582
|
-
* Use this when the database image pre-installs extensions that the application
|
|
583
|
-
* schema does not own (e.g. pgvector, pg_search bundled in a custom Postgres image).
|
|
584
|
-
* Default: `false` (full-sync behaviour — unmanaged DB extensions produce a
|
|
585
|
-
* `drop_extension` entry).
|
|
586
|
-
*/
|
|
587
|
-
readonly ignoreUnmanagedExtensions?: boolean;
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* Compare two ModelIRs and produce a structured diff.
|
|
591
|
-
*
|
|
592
|
-
* @param schema - The desired schema (from definition)
|
|
593
|
-
* @param db - The current database state (from introspection)
|
|
594
|
-
* @param options - Optional comparison settings (e.g. dbCasing)
|
|
595
|
-
* @returns SchemaDiff with all changes needed to bring DB in sync with schema
|
|
596
|
-
*/
|
|
597
|
-
declare function compareSchemata(schema: ModelIR, db: ModelIR, options?: CompareSchemataOptions): SchemaDiff;
|
|
780
|
+
declare function canGenerateCreateIndex(tableName: string, idx: IndexIR, schemaName?: string | undefined, naming?: NamingPlugin): boolean;
|
|
598
781
|
|
|
599
782
|
/**
|
|
600
|
-
*
|
|
783
|
+
* PostgreSQL Schema Introspection (ADAPTER-006)
|
|
601
784
|
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
785
|
+
* Queries information_schema/pg_catalog to build ModelIR
|
|
786
|
+
* from an existing database. Supports:
|
|
787
|
+
* - Table/column/PK discovery
|
|
788
|
+
* - FK → bidirectional relation inference
|
|
789
|
+
* - Hierarchy detection (adjacency + edge-table)
|
|
790
|
+
* - Include/exclude filtering
|
|
604
791
|
*
|
|
605
|
-
* @module
|
|
792
|
+
* @module introspection
|
|
606
793
|
*/
|
|
607
794
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
readonly includeDestructive?: boolean;
|
|
613
|
-
/** Automatically create indexes on FK columns for new tables (default: true) */
|
|
614
|
-
readonly fkAutoIndex?: boolean;
|
|
615
|
-
/** Dialect capabilities — migration SQL for unsupported features will be filtered */
|
|
616
|
-
readonly dialectCapabilities?: DialectCapabilities;
|
|
795
|
+
/** The minimum every schema-level operation needs: which schema. */
|
|
796
|
+
interface SchemaScopeOptions {
|
|
797
|
+
/** Schema name to operate on (default: 'public') */
|
|
798
|
+
readonly schema?: string;
|
|
617
799
|
}
|
|
618
800
|
/**
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
* 0. DROP FK/CHECK constraints (must drop before referenced tables)
|
|
623
|
-
* 1. DROP indexes
|
|
624
|
-
* 2. DROP columns
|
|
625
|
-
* 3. DROP primary keys
|
|
626
|
-
* 4. DROP tables, DROP ENUMs
|
|
627
|
-
* 5. CREATE ENUMs (must exist before tables that use them)
|
|
628
|
-
* 6. CREATE tables
|
|
629
|
-
* 7. ADD columns
|
|
630
|
-
* 8. ALTER columns (type, nullable, default)
|
|
631
|
-
* 9. ADD primary keys / column UNIQUE constraints
|
|
632
|
-
* 10. ADD FK constraints (must add after referenced tables exist)
|
|
633
|
-
* 11. ALTER FK (drop + re-add)
|
|
634
|
-
* 12. CREATE indexes
|
|
635
|
-
* 13. ADD CHECK constraints
|
|
636
|
-
* 14. ALTER ENUM ADD VALUE (must be last — has transaction visibility caveats in PG)
|
|
637
|
-
* 15. COMMENT ON TABLE / COLUMN (very last)
|
|
801
|
+
* Introspection additionally chooses WHICH TABLES to read. It is a read-only
|
|
802
|
+
* path, so narrowing it is safe — that is why the table filters live here and
|
|
803
|
+
* nowhere else.
|
|
638
804
|
*/
|
|
639
|
-
|
|
805
|
+
interface IntrospectionOptions extends SchemaScopeOptions {
|
|
806
|
+
/** Tables to exclude (glob patterns: * matches any chars) */
|
|
807
|
+
readonly exclude?: readonly string[];
|
|
808
|
+
/** Tables to include (default: all). Applied before exclude. */
|
|
809
|
+
readonly include?: readonly string[];
|
|
810
|
+
}
|
|
811
|
+
/** Hierarchy pattern detected during introspection */
|
|
640
812
|
/**
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
* phases run in descending order (11, 10, 9, ..., 0).
|
|
645
|
-
*
|
|
646
|
-
* Irreversible changes (drops that lose data) produce SQL WARNING comments.
|
|
813
|
+
* Hierarchy pattern detected during introspection.
|
|
814
|
+
* Alias of {@link HierarchyIR} from \@dbsp/types — kept here for
|
|
815
|
+
* public-API backwards compatibility (re-exported from \@dbsp/adapter-pgsql).
|
|
647
816
|
*/
|
|
648
|
-
|
|
649
|
-
|
|
817
|
+
type DetectedHierarchy = HierarchyIR;
|
|
818
|
+
/** Extended ModelIR with hierarchy metadata */
|
|
819
|
+
interface IntrospectedModelIR extends ModelIR {
|
|
820
|
+
readonly hierarchies: readonly DetectedHierarchy[];
|
|
821
|
+
readonly introspectedAt: Date;
|
|
822
|
+
readonly warnings: readonly string[];
|
|
823
|
+
}
|
|
650
824
|
/**
|
|
651
|
-
*
|
|
825
|
+
* Introspect a database through a pool.
|
|
652
826
|
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
*
|
|
827
|
+
* This does NOT accept a checked-out `PoolClient`, and that is deliberate. A
|
|
828
|
+
* client may be sitting inside a transaction that belongs to its owner, and a
|
|
829
|
+
* catalog query that fails there aborts *their* transaction. Protecting that
|
|
830
|
+
* needs a savepoint, and knowing whether to take one needs the caller to say
|
|
831
|
+
* whose transaction it is — which is what `PgsqlAdapter`'s `borrowedClient`
|
|
832
|
+
* declaration is for. Guessing it from the object's shape is the exact defect
|
|
833
|
+
* this adapter was rewritten to remove.
|
|
658
834
|
*
|
|
659
|
-
*
|
|
835
|
+
* Saying so in a comment is not enough: `CatalogQueryExecutor` is structural, so
|
|
836
|
+
* a `PoolClient` — which has a `query()` — satisfies it, and the prose would have
|
|
837
|
+
* been the only thing standing in the way. It is branded instead, and only the
|
|
838
|
+
* adapter's own protected executor carries the brand. A client cannot be passed
|
|
839
|
+
* here at all.
|
|
660
840
|
*
|
|
661
|
-
*
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* Result of parsing a migration file's UP/DOWN sections.
|
|
666
|
-
*/
|
|
667
|
-
interface ParsedMigrationFile {
|
|
668
|
-
readonly upStatements: readonly string[];
|
|
669
|
-
readonly downStatements: readonly string[];
|
|
670
|
-
readonly hasDown: boolean;
|
|
671
|
-
readonly destructive?: boolean | undefined;
|
|
672
|
-
}
|
|
673
|
-
/**
|
|
674
|
-
* Generate a migration file content with UP and DOWN sections.
|
|
675
|
-
*/
|
|
676
|
-
declare function generateMigrationFile(diff: SchemaDiff, options?: MigrationSQLOptions & {
|
|
677
|
-
name?: string;
|
|
678
|
-
}): string;
|
|
679
|
-
/**
|
|
680
|
-
* Parse a migration file into UP and DOWN sections.
|
|
681
|
-
* Separator: `^\s*-- DOWN\s*$` (strict regex, own line only — SC-25)
|
|
682
|
-
*/
|
|
683
|
-
declare function parseMigrationFile(content: string): ParsedMigrationFile;
|
|
684
|
-
/**
|
|
685
|
-
* Check if SQL statements contain destructive operations.
|
|
686
|
-
* Destructive: DROP TABLE, DROP COLUMN, lossy ALTER COLUMN TYPE
|
|
841
|
+
* So: hold a client, use `new PgsqlAdapter(client, { borrowedClient: true })`
|
|
842
|
+
* and call `.introspect()` on it.
|
|
687
843
|
*/
|
|
688
|
-
declare function
|
|
844
|
+
declare function introspect(pool: Pool, options?: IntrospectionOptions): Promise<IntrospectedModelIR>;
|
|
689
845
|
|
|
690
846
|
/**
|
|
691
|
-
*
|
|
847
|
+
* PgsqlAdapter - Implements the Adapter interface for PostgreSQL using native pg driver.
|
|
692
848
|
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
849
|
+
* This adapter wraps a pg Pool instance and provides the unified
|
|
850
|
+
* adapter interface for the db-semantic-planner ORM.
|
|
851
|
+
*
|
|
852
|
+
* @module pgsql-adapter
|
|
695
853
|
*/
|
|
696
854
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
855
|
+
declare class PgsqlRawSqlTransactionControlError extends Error {
|
|
856
|
+
readonly dbspRawSqlTransactionControl = true;
|
|
857
|
+
constructor(cause: unknown);
|
|
858
|
+
}
|
|
859
|
+
declare class PgsqlTransactionAbortedCommitError extends Error {
|
|
860
|
+
readonly dbspTransactionAbortedCommit = true;
|
|
861
|
+
constructor(cause: unknown);
|
|
862
|
+
}
|
|
863
|
+
declare class PgsqlTransactionAbortedError extends Error {
|
|
864
|
+
readonly dbspTransactionAborted = true;
|
|
865
|
+
constructor(cause: unknown);
|
|
708
866
|
}
|
|
709
867
|
/**
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
* @deprecated Use {@link withMigrationLock} instead — pool.query may release
|
|
713
|
-
* the connection (and the lock) before the migration completes.
|
|
868
|
+
* Options for PgsqlAdapter.
|
|
714
869
|
*/
|
|
715
|
-
|
|
870
|
+
interface PgsqlAdapterOptions {
|
|
871
|
+
/** Schema name for multi-tenant queries */
|
|
872
|
+
readonly schemaName?: string;
|
|
873
|
+
/**
|
|
874
|
+
* DB column casing convention (intuitive semantics).
|
|
875
|
+
* - `'snake_case'`: DB columns are snake_case → transform to camelCase for JS
|
|
876
|
+
* - `'camelCase'`: DB columns are camelCase → no transformation
|
|
877
|
+
* - `'preserve'`: No transformation
|
|
878
|
+
*/
|
|
879
|
+
readonly dbCasing?: DbCasing;
|
|
880
|
+
/** Optional model for WHERE compilation */
|
|
881
|
+
readonly model?: ModelIR;
|
|
882
|
+
/** Optional logger for debug/error messages */
|
|
883
|
+
readonly logger?: AdapterLogger;
|
|
884
|
+
/** Default primary key column name for convention fallbacks (default: 'id') */
|
|
885
|
+
readonly defaultPkColumnName?: string;
|
|
886
|
+
/** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
|
|
887
|
+
readonly deriveFkColumnName?: FkColumnDerivation;
|
|
888
|
+
}
|
|
889
|
+
interface PgsqlPoolAdapterOptions extends PgsqlAdapterOptions {
|
|
890
|
+
readonly borrowedClient?: false;
|
|
891
|
+
}
|
|
892
|
+
interface PgsqlBorrowedClientAdapterOptions extends PgsqlAdapterOptions {
|
|
893
|
+
/** This connection belongs to the caller. dbsp never releases it. */
|
|
894
|
+
readonly borrowedClient: true;
|
|
895
|
+
/**
|
|
896
|
+
* Let dbsp run transactions on your connection, through a savepoint.
|
|
897
|
+
*
|
|
898
|
+
* When your connection is already inside a transaction, dbsp creates a
|
|
899
|
+
* savepoint and rolls back dbsp's changes after that savepoint if the callback
|
|
900
|
+
* fails. `RELEASE SAVEPOINT` does not commit; it merges the work into your
|
|
901
|
+
* surrounding transaction, so a callback that succeeded is still undone if you
|
|
902
|
+
* later roll back. Deferred constraints or triggers can still make your outer
|
|
903
|
+
* `COMMIT` fail after dbsp has returned. `SET LOCAL` changes inside the callback
|
|
904
|
+
* remain in effect for the rest of your transaction after the savepoint is
|
|
905
|
+
* released. `ON COMMIT DROP` and `ON COMMIT DELETE ROWS` fire at your transaction
|
|
906
|
+
* boundary, not at the savepoint. Sequences are not transactional:
|
|
907
|
+
* `nextval`/`setval` are not reclaimed by a savepoint rollback. Session-level
|
|
908
|
+
* advisory locks ignore rollback; transaction-level advisory locks taken by a
|
|
909
|
+
* successful callback last until your transaction ends.
|
|
910
|
+
*
|
|
911
|
+
* Transaction control through raw SQL inside a scope dbsp is managing is
|
|
912
|
+
* unsupported. `COMMIT`, `ROLLBACK`, and `PREPARE TRANSACTION` end the
|
|
913
|
+
* transaction dbsp is working inside; dbsp detects that and fails loudly, but
|
|
914
|
+
* the data is already whatever your statement made it. Raw savepoint control
|
|
915
|
+
* (`SAVEPOINT`, `RELEASE SAVEPOINT`, `ROLLBACK TO SAVEPOINT`) can alter the
|
|
916
|
+
* savepoint stack before dbsp sees the command tag; dbsp poisons the scope, but
|
|
917
|
+
* it cannot make that command un-run. Manage your transaction outside dbsp's
|
|
918
|
+
* calls.
|
|
919
|
+
*/
|
|
920
|
+
readonly managedTransactions?: true;
|
|
921
|
+
}
|
|
716
922
|
/**
|
|
717
|
-
*
|
|
923
|
+
* Adapter implementation for PostgreSQL using native pg driver.
|
|
718
924
|
*
|
|
719
|
-
* @
|
|
720
|
-
*/
|
|
721
|
-
declare function releaseMigrationLock(pool: Pool): Promise<void>;
|
|
722
|
-
/**
|
|
723
|
-
* Execute a callback under an advisory lock using a dedicated client.
|
|
724
|
-
* The lock is held for the duration of the callback.
|
|
725
|
-
* The client is released (and lock freed) after the callback completes.
|
|
726
|
-
*/
|
|
727
|
-
declare function withMigrationLock<T>(pool: Pool, fn: (client: PoolClient) => Promise<T>): Promise<T>;
|
|
728
|
-
/**
|
|
729
|
-
* Ensure the migrations tracking table exists.
|
|
730
|
-
* Auto-migrates existing tables that lack `schema_version`/`destructive` columns,
|
|
731
|
-
* and backfills `schema_version` by `applied_at` order for rows still at 0.
|
|
732
|
-
*/
|
|
733
|
-
declare function ensureMigrationsTable(pool: Pool): Promise<void>;
|
|
734
|
-
/**
|
|
735
|
-
* Get all applied migrations, ordered by name.
|
|
736
|
-
*/
|
|
737
|
-
declare function getAppliedMigrations(pool: Pool): Promise<readonly MigrationRecord[]>;
|
|
738
|
-
/**
|
|
739
|
-
* Record a migration as applied.
|
|
740
|
-
*/
|
|
741
|
-
declare function recordMigration(pool: Pool, name: string, checksum: string, schemaVersion: number, destructive: boolean): Promise<void>;
|
|
742
|
-
/**
|
|
743
|
-
* Check if a specific migration has been applied.
|
|
744
|
-
*/
|
|
745
|
-
declare function isMigrationApplied(pool: Pool, name: string): Promise<boolean>;
|
|
746
|
-
/**
|
|
747
|
-
* Get the next schema version number (max + 1, or 1 if no migrations).
|
|
748
|
-
*/
|
|
749
|
-
declare function getNextSchemaVersion(pool: Pool): Promise<number>;
|
|
750
|
-
/**
|
|
751
|
-
* Remove a migration record (for rollback).
|
|
752
|
-
*/
|
|
753
|
-
declare function removeMigrationRecord(pool: Pool, name: string): Promise<void>;
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Type Mapping - Maps ModelIR ColumnType to PostgreSQL data types
|
|
925
|
+
* @typeParam DB - Database schema type
|
|
757
926
|
*
|
|
758
|
-
*
|
|
759
|
-
*
|
|
927
|
+
* @example
|
|
928
|
+
* ```typescript
|
|
929
|
+
* import { Pool } from 'pg';
|
|
930
|
+
* import { createPgsqlAdapter } from '@dbsp/adapter-pgsql';
|
|
760
931
|
*
|
|
761
|
-
*
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
/**
|
|
765
|
-
* Map ColumnType to PostgreSQL data type string.
|
|
766
|
-
*
|
|
767
|
-
* Uses originalDbType if available (from introspection), otherwise
|
|
768
|
-
* falls back to reasonable PostgreSQL defaults.
|
|
769
|
-
*
|
|
770
|
-
* @param col - Column definition from ModelIR
|
|
771
|
-
* @returns PostgreSQL type string (e.g., 'VARCHAR(255)', 'SERIAL', 'JSONB')
|
|
772
|
-
*/
|
|
773
|
-
declare function mapColumnType(col: ColumnIR): string;
|
|
774
|
-
/**
|
|
775
|
-
* Map OnDeleteAction to PostgreSQL syntax.
|
|
776
|
-
*/
|
|
777
|
-
declare function mapOnDeleteAction(action?: string): string;
|
|
778
|
-
|
|
779
|
-
/**
|
|
780
|
-
* EXPLAIN Statement Compiler
|
|
781
|
-
*
|
|
782
|
-
* Generates PostgreSQL EXPLAIN statements with various options.
|
|
783
|
-
* Supports:
|
|
784
|
-
* - ANALYZE (execute and show actual run times)
|
|
785
|
-
* - FORMAT (text, json, xml, yaml)
|
|
786
|
-
* - VERBOSE, COSTS, BUFFERS, TIMING, SETTINGS
|
|
787
|
-
*/
|
|
788
|
-
|
|
789
|
-
/**
|
|
790
|
-
* Output format for EXPLAIN results.
|
|
791
|
-
*/
|
|
792
|
-
type ExplainFormat = 'text' | 'json' | 'xml' | 'yaml';
|
|
793
|
-
/**
|
|
794
|
-
* Options for EXPLAIN statement.
|
|
795
|
-
*/
|
|
796
|
-
interface ExplainOptions {
|
|
797
|
-
/** Execute the query and show actual run times */
|
|
798
|
-
analyze?: boolean;
|
|
799
|
-
/** Show more detailed output */
|
|
800
|
-
verbose?: boolean;
|
|
801
|
-
/** Show cost estimates (default: true) */
|
|
802
|
-
costs?: boolean;
|
|
803
|
-
/** Show buffer usage (requires analyze) */
|
|
804
|
-
buffers?: boolean;
|
|
805
|
-
/** Show actual timing (requires analyze) */
|
|
806
|
-
timing?: boolean;
|
|
807
|
-
/** Show non-default settings */
|
|
808
|
-
settings?: boolean;
|
|
809
|
-
/** Output format */
|
|
810
|
-
format?: ExplainFormat;
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Build an EXPLAIN statement wrapping a query.
|
|
814
|
-
*
|
|
815
|
-
* @param query - The query to explain (SelectStmt, InsertStmt, etc.)
|
|
816
|
-
* @param options - EXPLAIN options
|
|
817
|
-
* @returns ExplainStmt AST node
|
|
818
|
-
*
|
|
819
|
-
* @example
|
|
820
|
-
* ```typescript
|
|
821
|
-
* const selectAst = { SelectStmt: { ... } };
|
|
822
|
-
* const explainAst = buildExplain(selectAst, { analyze: true, format: 'json' });
|
|
823
|
-
* // Produces: EXPLAIN (ANALYZE, FORMAT JSON) SELECT ...
|
|
932
|
+
* const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
933
|
+
* const adapter = createPgsqlAdapter(pool);
|
|
934
|
+
* const orm = createOrm({ model, adapter });
|
|
824
935
|
* ```
|
|
825
936
|
*/
|
|
826
|
-
declare
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
* Build verbose EXPLAIN with costs and buffers.
|
|
843
|
-
*
|
|
844
|
-
* @param query - The query to explain
|
|
845
|
-
* @returns ExplainStmt with verbose options
|
|
846
|
-
*/
|
|
847
|
-
declare function buildExplainVerbose(query: Node): Node;
|
|
848
|
-
/**
|
|
849
|
-
* Parse EXPLAIN JSON output to get execution statistics.
|
|
850
|
-
*
|
|
851
|
-
* @param jsonOutput - The JSON string from EXPLAIN (ANALYZE, FORMAT JSON)
|
|
852
|
-
* @returns Parsed plan with execution statistics
|
|
853
|
-
*/
|
|
854
|
-
declare function parseExplainJson(jsonOutput: string): ExplainPlan[];
|
|
855
|
-
/**
|
|
856
|
-
* Parsed EXPLAIN plan structure (simplified).
|
|
857
|
-
*/
|
|
858
|
-
interface ExplainPlan {
|
|
859
|
-
Plan: {
|
|
860
|
-
'Node Type': string;
|
|
861
|
-
'Relation Name'?: string;
|
|
862
|
-
Alias?: string;
|
|
863
|
-
'Startup Cost'?: number;
|
|
864
|
-
'Total Cost'?: number;
|
|
865
|
-
'Plan Rows'?: number;
|
|
866
|
-
'Plan Width'?: number;
|
|
867
|
-
'Actual Startup Time'?: number;
|
|
868
|
-
'Actual Total Time'?: number;
|
|
869
|
-
'Actual Rows'?: number;
|
|
870
|
-
'Actual Loops'?: number;
|
|
871
|
-
Plans?: ExplainPlan['Plan'][];
|
|
872
|
-
};
|
|
873
|
-
'Planning Time'?: number;
|
|
874
|
-
'Execution Time'?: number;
|
|
875
|
-
Triggers?: unknown[];
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Extract total execution time from EXPLAIN ANALYZE JSON output.
|
|
879
|
-
*
|
|
880
|
-
* @param plans - Parsed EXPLAIN plans
|
|
881
|
-
* @returns Total execution time in milliseconds
|
|
882
|
-
*/
|
|
883
|
-
declare function getTotalExecutionTime(plans: ExplainPlan[]): number;
|
|
884
|
-
/**
|
|
885
|
-
* Extract row counts from EXPLAIN ANALYZE JSON output.
|
|
886
|
-
*
|
|
887
|
-
* @param plans - Parsed EXPLAIN plans
|
|
888
|
-
* @returns Object with estimated and actual row counts
|
|
889
|
-
*/
|
|
890
|
-
declare function getRowEstimates(plans: ExplainPlan[]): {
|
|
891
|
-
estimated: number;
|
|
892
|
-
actual: number;
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
/**
|
|
896
|
-
* ParadeDB Extension Wrappers
|
|
897
|
-
*
|
|
898
|
-
* Type-safe query builders for ParadeDB BM25 full-text search.
|
|
899
|
-
* All functions return ExpressionRef instances that can be used in:
|
|
900
|
-
* - SELECT: .column(score('id').as('score'))
|
|
901
|
-
* - WHERE: .where(bm25Search('symbols', query, { name: 3.0, doc: 1.0 }))
|
|
902
|
-
* - ORDER BY: .orderBy(score('id'), 'desc')
|
|
903
|
-
*
|
|
904
|
-
* @remarks
|
|
905
|
-
* ParadeDB functions accept both named and positional arguments.
|
|
906
|
-
* This module uses named args via namedArg() for parse(), which produces:
|
|
907
|
-
* paradedb.parse(field => 'field_name', query_string => $1)
|
|
908
|
-
* Named parameter syntax is supported via the NamedArgExpressionIntent (EXT-NAMED-PARAMS).
|
|
909
|
-
*/
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* BM25 relevance score for a row.
|
|
913
|
-
*
|
|
914
|
-
* Use in SELECT and ORDER BY to retrieve and sort by full-text relevance.
|
|
915
|
-
* Requires a BM25 index on the table.
|
|
916
|
-
*
|
|
917
|
-
* @param keyField - The key field of the BM25 index (typically the primary key, e.g. 'id')
|
|
918
|
-
* @returns ExpressionRef that compiles to: paradedb.score("keyField")
|
|
919
|
-
*
|
|
920
|
-
* @example
|
|
921
|
-
* orm.select('symbols').column(score('id').as('score')).orderBy(score('id'), 'desc')
|
|
922
|
-
* // → paradedb.score("id") AS "score"
|
|
923
|
-
*/
|
|
924
|
-
declare function score(keyField: string): ExpressionRef;
|
|
925
|
-
/**
|
|
926
|
-
* Parse a single-field BM25 query expression.
|
|
927
|
-
*
|
|
928
|
-
* Compiles to: paradedb.parse(field => 'field_name', query_string => $N)
|
|
929
|
-
*
|
|
930
|
-
* @param field - Column name to search in (must be indexed in the BM25 index)
|
|
931
|
-
* @param query - Query string value (will be bound as a parameter)
|
|
932
|
-
* @returns ExpressionRef for use with boost() or booleanSearch()
|
|
933
|
-
*
|
|
934
|
-
* @example
|
|
935
|
-
* parse('name', 'hello world')
|
|
936
|
-
* // → paradedb.parse(field => 'name', query_string => $1)
|
|
937
|
-
*/
|
|
938
|
-
declare function parse(field: string, query: ExpressionRef | unknown): ExpressionRef;
|
|
939
|
-
/**
|
|
940
|
-
* Apply a boost multiplier to a BM25 sub-expression.
|
|
941
|
-
*
|
|
942
|
-
* Compiles to: paradedb.boost(factor, expr)
|
|
943
|
-
*
|
|
944
|
-
* @param factor - Boost multiplier (e.g. 3.0 for 3x weight)
|
|
945
|
-
* @param expr - Expression to boost (typically a parse() call)
|
|
946
|
-
* @returns ExpressionRef for use with booleanSearch()
|
|
947
|
-
*
|
|
948
|
-
* @example
|
|
949
|
-
* boost(3.0, parse('name', 'hello'))
|
|
950
|
-
* // → paradedb.boost(3.0, paradedb.parse('name', $1))
|
|
951
|
-
*/
|
|
952
|
-
declare function boost(factor: number, expr: ExpressionRef): ExpressionRef;
|
|
953
|
-
/**
|
|
954
|
-
* Combine multiple BM25 sub-expressions with boolean OR logic.
|
|
955
|
-
*
|
|
956
|
-
* Compiles to: paradedb.boolean(expr1, expr2, ...)
|
|
957
|
-
*
|
|
958
|
-
* @param exprs - One or more sub-expressions (typically boost() calls)
|
|
959
|
-
* @returns ExpressionRef for use on the right side of the @@@ operator
|
|
960
|
-
*
|
|
961
|
-
* @example
|
|
962
|
-
* booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
|
|
963
|
-
* // → paradedb.boolean(paradedb.boost(3.0, ...), paradedb.boost(1.0, ...))
|
|
964
|
-
*/
|
|
965
|
-
/**
|
|
966
|
-
* Combine multiple BM25 sub-expressions with boolean OR logic.
|
|
967
|
-
*
|
|
968
|
-
* Compiles to: paradedb.boolean(should => ARRAY[expr1, expr2, ...])
|
|
969
|
-
*
|
|
970
|
-
* @param exprs - One or more sub-expressions (typically boost() calls)
|
|
971
|
-
* @returns ExpressionRef for use on the right side of the @@@ operator
|
|
972
|
-
*
|
|
973
|
-
* @example
|
|
974
|
-
* booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
|
|
975
|
-
* // → paradedb.boolean(should => ARRAY[paradedb.boost(3.0, ...), paradedb.boost(1.0, ...)])
|
|
976
|
-
*/
|
|
977
|
-
declare function booleanSearch(exprs: ExpressionRef[]): ExpressionRef;
|
|
978
|
-
/**
|
|
979
|
-
* Full BM25 multi-field search with per-field boost weights.
|
|
980
|
-
*
|
|
981
|
-
* Produces: table @@@ paradedb.boolean(boost1, boost2, ...)
|
|
982
|
-
*
|
|
983
|
-
* Each field in `fieldBoosts` generates a `paradedb.boost(weight, paradedb.parse(field, $N))`
|
|
984
|
-
* sub-expression. The same query string is used for all fields (single parameter binding).
|
|
985
|
-
*
|
|
986
|
-
* @param table - Table alias for the left side of the @@@ operator
|
|
987
|
-
* @param query - Query string (bound as a single $N parameter, shared across all fields)
|
|
988
|
-
* @param fieldBoosts - Map of column name → boost weight
|
|
989
|
-
* @returns ExpressionRef for use in .where()
|
|
990
|
-
*
|
|
991
|
-
* @example
|
|
992
|
-
* bm25Search('s', searchTerm, {
|
|
993
|
-
* name_searchable: 3.0,
|
|
994
|
-
* name: 1.0,
|
|
995
|
-
* signature: 1.5,
|
|
996
|
-
* doc_searchable: 1.0,
|
|
997
|
-
* })
|
|
998
|
-
* // → s @@@ paradedb.boolean(
|
|
999
|
-
* // paradedb.boost(3.0, paradedb.parse('name_searchable', $1)),
|
|
1000
|
-
* // paradedb.boost(1.0, paradedb.parse('name', $1)),
|
|
1001
|
-
* // paradedb.boost(1.5, paradedb.parse('signature', $1)),
|
|
1002
|
-
* // paradedb.boost(1.0, paradedb.parse('doc_searchable', $1))
|
|
1003
|
-
* // )
|
|
1004
|
-
*
|
|
1005
|
-
* @remarks
|
|
1006
|
-
* The query parameter is shared: all parse() calls reference the same $N slot.
|
|
1007
|
-
* If you need different query strings per field, compose parse()/boost()/booleanSearch() manually.
|
|
1008
|
-
*
|
|
1009
|
-
* @remarks
|
|
1010
|
-
* ParadeDB's boolean() function accepts both positional args and the named
|
|
1011
|
-
* `should => ARRAY[...]` syntax. This wrapper uses positional args.
|
|
1012
|
-
* Named parameter syntax is deferred to EXT-NAMED-PARAMS.
|
|
1013
|
-
*/
|
|
1014
|
-
declare function bm25Search(table: string, query: unknown, fieldBoosts: Record<string, number>): ExpressionRef;
|
|
1015
|
-
|
|
1016
|
-
/**
|
|
1017
|
-
* PostgreSQL built-in function helpers.
|
|
1018
|
-
*
|
|
1019
|
-
* Thin wrappers around core expression primitives for common PostgreSQL functions.
|
|
1020
|
-
* Same pattern as pgvector.ts and paradedb.ts.
|
|
1021
|
-
*/
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
* Generate a series of values: generate_series(start, stop[, step])
|
|
1025
|
-
*
|
|
1026
|
-
* Returns a set of values from start to stop (inclusive), with an optional step.
|
|
1027
|
-
* Commonly used with CTE for batch operations.
|
|
1028
|
-
*
|
|
1029
|
-
* @example generateSeries(1, 100) → generate_series(1, 100)
|
|
1030
|
-
* @example generateSeries(0, 50, 5) → generate_series(0, 50, 5)
|
|
1031
|
-
*/
|
|
1032
|
-
declare function generateSeries(start: number, stop: number, step?: number): ExpressionRef;
|
|
1033
|
-
/**
|
|
1034
|
-
* Get next value from a sequence: nextval('sequence_name')
|
|
1035
|
-
*
|
|
1036
|
-
* @example nextval('order_id_seq') → nextval('order_id_seq')
|
|
1037
|
-
*/
|
|
1038
|
-
declare function nextval(sequenceName: string): ExpressionRef;
|
|
1039
|
-
|
|
1040
|
-
/**
|
|
1041
|
-
* pgvector Extension Wrappers
|
|
1042
|
-
*
|
|
1043
|
-
* Type-safe query builders for pgvector distance operators.
|
|
1044
|
-
* All functions return ExpressionRef instances that can be used in:
|
|
1045
|
-
* - SELECT: .column(cosineDistance('vector', qv).as('score'))
|
|
1046
|
-
* - WHERE: .where(cosineDistance('vector', qv).gte(0.5))
|
|
1047
|
-
* - ORDER BY: .orderBy(rawDistance('vector', qv), 'asc')
|
|
1048
|
-
*/
|
|
1049
|
-
|
|
1050
|
-
/**
|
|
1051
|
-
* Cosine similarity: 1 - (col <=> vector)
|
|
1052
|
-
*
|
|
1053
|
-
* Score in [0, 1], higher = more similar.
|
|
1054
|
-
* Use in SELECT to get a similarity score.
|
|
1055
|
-
*
|
|
1056
|
-
* @example
|
|
1057
|
-
* orm.select('embeddings').column(cosineDistance('vector', qv).as('score'))
|
|
1058
|
-
*/
|
|
1059
|
-
declare function cosineDistance(column: string, vector: number[]): ExpressionRef;
|
|
1060
|
-
/**
|
|
1061
|
-
* Raw cosine distance: col <=> vector
|
|
1062
|
-
*
|
|
1063
|
-
* Lower = closer. Index-friendly — use in ORDER BY for ANN search.
|
|
1064
|
-
* Do NOT use in SELECT as a similarity score (lower = closer is counterintuitive).
|
|
1065
|
-
*
|
|
1066
|
-
* @example
|
|
1067
|
-
* orm.select('embeddings').orderBy(rawDistance('vector', qv), 'asc')
|
|
1068
|
-
*/
|
|
1069
|
-
declare function rawDistance(column: string, vector: number[]): ExpressionRef;
|
|
1070
|
-
/**
|
|
1071
|
-
* L2 (Euclidean) distance: col <-> vector
|
|
1072
|
-
*
|
|
1073
|
-
* @example
|
|
1074
|
-
* orm.select('embeddings').orderBy(l2Distance('vector', qv), 'asc')
|
|
1075
|
-
*/
|
|
1076
|
-
declare function l2Distance(column: string, vector: number[]): ExpressionRef;
|
|
1077
|
-
/**
|
|
1078
|
-
* Inner product distance: col <#> vector (negative inner product)
|
|
1079
|
-
*
|
|
1080
|
-
* For maximum inner product search: ORDER BY innerProduct('vector', qv) ASC.
|
|
1081
|
-
*
|
|
1082
|
-
* @example
|
|
1083
|
-
* orm.select('embeddings').orderBy(innerProduct('vector', qv), 'asc')
|
|
1084
|
-
*/
|
|
1085
|
-
declare function innerProduct(column: string, vector: number[]): ExpressionRef;
|
|
1086
|
-
/**
|
|
1087
|
-
* Get the number of dimensions of a vector column: vector_dims(col)
|
|
1088
|
-
*
|
|
1089
|
-
* Returns an integer — the dimension count of the stored vector.
|
|
1090
|
-
* Useful for sanity-checking that embeddings match the expected model dimension.
|
|
1091
|
-
*
|
|
1092
|
-
* @example
|
|
1093
|
-
* orm.from(embeddings).columns([vectorDims('vector').as('dim')]).first()
|
|
1094
|
-
* // → SELECT vector_dims("t0"."vector") AS "dim" FROM "embeddings" AS "t0"
|
|
1095
|
-
*/
|
|
1096
|
-
declare function vectorDims(column: string): ExpressionRef;
|
|
1097
|
-
|
|
1098
|
-
/**
|
|
1099
|
-
* Immutable context passed to all handlers during compilation.
|
|
1100
|
-
*/
|
|
1101
|
-
interface CompilerContext {
|
|
1102
|
-
/** Naming convention transformer */
|
|
1103
|
-
readonly naming: NamingPlugin;
|
|
1104
|
-
/** Schema name for table qualification (optional) */
|
|
1105
|
-
readonly schema?: string;
|
|
1106
|
-
/** Dialect capabilities for adapter-layer SQL surface gates */
|
|
1107
|
-
readonly dialectCapabilities?: DialectCapabilities;
|
|
1108
|
-
/** Root table name for the query */
|
|
1109
|
-
readonly rootTable: string;
|
|
1110
|
-
/** Current table alias (for JOINs) */
|
|
1111
|
-
readonly currentAlias?: string;
|
|
1112
|
-
/** Final relation path/name → SQL join alias map for relation-aware expression contexts */
|
|
1113
|
-
readonly aliases?: ReadonlyMap<string, string>;
|
|
1114
|
-
/** Maximum recursive depth (default: 100) */
|
|
1115
|
-
readonly maxRecursiveDepth: number;
|
|
1116
|
-
/** Optional callback for raw SQL audit trail */
|
|
1117
|
-
readonly onRawSQL?: (sql: string) => void;
|
|
1118
|
-
/** Default primary key column name for convention fallbacks (default: 'id') */
|
|
1119
|
-
readonly defaultPkColumnName?: string;
|
|
1120
|
-
/** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
|
|
1121
|
-
readonly deriveFkColumnName?: FkColumnDerivation;
|
|
1122
|
-
/** Alias of the outer (parent) query — used for FieldRef scope:'outer' resolution in EXISTS subqueries */
|
|
1123
|
-
readonly outerAlias?: string;
|
|
1124
|
-
/** Query-local CTE/binding names that must not be schema-qualified. */
|
|
1125
|
-
readonly bindingNames?: BindingNameRegistry;
|
|
937
|
+
declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
938
|
+
private readonly pool;
|
|
939
|
+
private readonly client;
|
|
940
|
+
private readonly borrowedClient;
|
|
941
|
+
private readonly managedTransactions;
|
|
942
|
+
private readonly adapterManagedTransaction;
|
|
943
|
+
private readonly scopeToken;
|
|
944
|
+
private readonly scopeState;
|
|
945
|
+
private readonly schemaName;
|
|
946
|
+
private readonly _dbCasing;
|
|
947
|
+
private readonly naming;
|
|
948
|
+
private readonly model;
|
|
949
|
+
private readonly logger;
|
|
950
|
+
private readonly _capabilities;
|
|
951
|
+
private readonly defaultPk;
|
|
952
|
+
private readonly deriveFk;
|
|
1126
953
|
/**
|
|
1127
|
-
*
|
|
1128
|
-
* Set by PlanCompiler when compiling selectCustomExpression — enables SubqueryExpressionIntent
|
|
1129
|
-
* to embed a fully compiled sub-SELECT into the parent SELECT column list.
|
|
954
|
+
* Create a new PgsqlAdapter.
|
|
1130
955
|
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
956
|
+
* Ownership of the connection is **declared**, never inferred. Handing over a
|
|
957
|
+
* `PoolClient` means nothing on its own — it says the object has a `release()`
|
|
958
|
+
* method, not that a transaction is open or that the caller owns the lifecycle.
|
|
959
|
+
* Pass `borrowedClient: true` to say so.
|
|
960
|
+
*
|
|
961
|
+
* @param pool - a pg.Pool, a caller-owned pg.PoolClient (with `borrowedClient: true`),
|
|
962
|
+
* or nothing at all for compile-only mode
|
|
963
|
+
* @param options - configuration; declares connection ownership
|
|
1134
964
|
*/
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
965
|
+
constructor(pool?: Pool | undefined, options?: PgsqlPoolAdapterOptions);
|
|
966
|
+
constructor(pool: Pool, options?: PgsqlPoolAdapterOptions);
|
|
967
|
+
constructor(client: PoolClient, options: PgsqlBorrowedClientAdapterOptions);
|
|
968
|
+
constructor(pool: undefined, options?: PgsqlAdapterOptions);
|
|
1139
969
|
/**
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
* (price + :a) * :b.
|
|
970
|
+
* Shared compilation dependencies — built lazily from adapter fields.
|
|
971
|
+
* Passed to compiler sub-modules instead of `this`.
|
|
1143
972
|
*/
|
|
1144
|
-
readonly compileNqlSelectExpression?: (value: unknown, ctx: CompilerContext, state: CompilerState) => Node;
|
|
1145
973
|
/**
|
|
1146
|
-
*
|
|
1147
|
-
*
|
|
1148
|
-
*
|
|
974
|
+
* Return a new PgsqlAdapterOptions that merges current config with overrides.
|
|
975
|
+
* Ensures that all configuration fields (logger, defaultPkColumnName,
|
|
976
|
+
* deriveFkColumnName, etc.) are propagated to scoped/transactional adapters.
|
|
1149
977
|
*/
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
parameters: unknown[];
|
|
1158
|
-
/** Current parameter index (1-based for PostgreSQL) */
|
|
1159
|
-
paramIndex: number;
|
|
1160
|
-
/** Registered CTEs for the query */
|
|
1161
|
-
ctes: Map<string, Node>;
|
|
1162
|
-
/** Table aliases in use */
|
|
1163
|
-
aliases: Map<string, string>;
|
|
1164
|
-
/** JOIN clauses accumulated */
|
|
1165
|
-
joins: Node[];
|
|
1166
|
-
}
|
|
1167
|
-
/**
|
|
1168
|
-
* Base decision interface matching core's PlanDecision structure.
|
|
1169
|
-
*/
|
|
1170
|
-
interface Decision {
|
|
1171
|
-
readonly type: string;
|
|
1172
|
-
readonly table?: string;
|
|
1173
|
-
readonly column?: string;
|
|
1174
|
-
readonly alias?: string;
|
|
1175
|
-
readonly operator?: string;
|
|
1176
|
-
readonly value?: unknown;
|
|
1177
|
-
readonly paramIndex?: number;
|
|
1178
|
-
readonly dataType?: string;
|
|
1179
|
-
readonly direction?: 'ASC' | 'DESC';
|
|
1180
|
-
readonly nulls?: 'FIRST' | 'LAST';
|
|
1181
|
-
readonly joinType?: 'inner' | 'left';
|
|
1182
|
-
readonly sourceColumn?: ColumnListInput;
|
|
1183
|
-
readonly targetColumn?: ColumnListInput;
|
|
1184
|
-
readonly targetTable?: string;
|
|
1185
|
-
readonly function?: string;
|
|
1186
|
-
/** Apply DISTINCT to a SELECT-list aggregate (e.g. COUNT(DISTINCT col)). */
|
|
1187
|
-
readonly distinct?: boolean;
|
|
1188
|
-
readonly args?: readonly unknown[];
|
|
1189
|
-
readonly conditions?: readonly Decision[];
|
|
1190
|
-
readonly columns?: readonly string[];
|
|
1191
|
-
readonly values?: readonly unknown[];
|
|
1192
|
-
readonly set?: readonly {
|
|
1193
|
-
column: string;
|
|
1194
|
-
value: unknown;
|
|
1195
|
-
}[];
|
|
1196
|
-
readonly limit?: number | ParamIntent | {
|
|
1197
|
-
paramIndex: number;
|
|
1198
|
-
};
|
|
1199
|
-
readonly offset?: number | ParamIntent | {
|
|
1200
|
-
paramIndex: number;
|
|
1201
|
-
};
|
|
1202
|
-
readonly strategy?: 'join' | 'lateral' | 'json_agg' | 'cte';
|
|
1203
|
-
readonly relation?: string;
|
|
1204
|
-
readonly relationName?: string;
|
|
1205
|
-
readonly relationPath?: string;
|
|
1206
|
-
readonly hydrationPrefix?: string;
|
|
1207
|
-
readonly include?: readonly Decision[];
|
|
1208
|
-
readonly relationType?: 'belongsTo' | 'hasMany' | 'hasOne';
|
|
1209
|
-
readonly foreignKey?: ColumnListInput;
|
|
1210
|
-
readonly parentKey?: ColumnListInput;
|
|
1211
|
-
readonly orderByFallback?: boolean;
|
|
1212
|
-
readonly children?: readonly Decision[];
|
|
1213
|
-
readonly partition?: readonly string[];
|
|
1214
|
-
readonly orderBy?: readonly {
|
|
1215
|
-
column: string;
|
|
1216
|
-
direction?: 'ASC' | 'DESC';
|
|
1217
|
-
}[] | readonly JsonAggOrderByEntry[];
|
|
1218
|
-
readonly frame?: string;
|
|
1219
|
-
readonly maxDepth?: number;
|
|
1220
|
-
readonly pathColumn?: string;
|
|
1221
|
-
readonly cycleDetection?: boolean;
|
|
1222
|
-
readonly selectColumn?: string;
|
|
1223
|
-
readonly aggregate?: string;
|
|
978
|
+
private cloneOptions;
|
|
979
|
+
private buildCompileDeps;
|
|
980
|
+
private requireNqlCompileModel;
|
|
981
|
+
private assertNqlBindingNamesDisjointFromTables;
|
|
982
|
+
private compileNqlMutation;
|
|
983
|
+
private compileNqlBundleLeaf;
|
|
984
|
+
private compileNqlBundle;
|
|
1224
985
|
/**
|
|
1225
|
-
*
|
|
1226
|
-
* Deliberately NOT named `distinct` — `assertNoDroppedDecisionModifiers`
|
|
1227
|
-
* (subquery-emission.ts) treats a top-level `distinct === true` on ANY
|
|
1228
|
-
* subquery decision as an unsupported query-level DISTINCT modifier and
|
|
1229
|
-
* throws. This field is scoped to the aggregate projection only, so it
|
|
1230
|
-
* must not collide with that generic guard.
|
|
986
|
+
* Returns the pool/client executor, or throws if in compile-only mode.
|
|
1231
987
|
*/
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
targetColumn?: string;
|
|
1238
|
-
}[];
|
|
1239
|
-
readonly isRecursive?: boolean;
|
|
1240
|
-
readonly fkColumn?: string;
|
|
1241
|
-
readonly pkColumn?: string;
|
|
1242
|
-
readonly expandRelation?: string;
|
|
1243
|
-
readonly relationColumns?: readonly string[];
|
|
1244
|
-
readonly columnAliases?: Readonly<Record<string, string>>;
|
|
1245
|
-
readonly jsonPath?: readonly unknown[];
|
|
1246
|
-
readonly jsonMode?: 'json' | 'text';
|
|
1247
|
-
readonly _compiledFilterWhere?: _pgsql_types.Node;
|
|
1248
|
-
readonly filterWhere?: _pgsql_types.Node;
|
|
1249
|
-
readonly expressionIntent?: unknown;
|
|
1250
|
-
readonly escape?: string;
|
|
988
|
+
private requireConnection;
|
|
989
|
+
/** Adapter capabilities for feature detection */
|
|
990
|
+
get capabilities(): AdapterCapabilities;
|
|
991
|
+
/** PostgreSQL dialect capabilities for planner strategy selection */
|
|
992
|
+
get dialectCapabilities(): DialectCapabilities;
|
|
1251
993
|
/**
|
|
1252
|
-
*
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
*
|
|
994
|
+
* DB column casing convention used by this adapter.
|
|
995
|
+
*/
|
|
996
|
+
get dbCasing(): DbCasing;
|
|
997
|
+
/**
|
|
998
|
+
* Get the underlying pg Pool or borrowed PoolClient instance.
|
|
999
|
+
*/
|
|
1000
|
+
getPoolInstance(): Pool | PoolClient;
|
|
1001
|
+
/**
|
|
1002
|
+
* Compile a plan to executable SQL.
|
|
1257
1003
|
*
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1004
|
+
* When passed a direct `CompiledNqlQuery`, the adapter trusts that the bundle
|
|
1005
|
+
* has already been semantically validated by the NQL compiler. This method
|
|
1006
|
+
* still performs adapter-owned SQL safety checks for emitted binding names
|
|
1007
|
+
* before CTE emission.
|
|
1260
1008
|
*/
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Handler for WHERE clause conditions.
|
|
1265
|
-
* Transforms condition decisions into PostgreSQL AST expressions.
|
|
1266
|
-
*/
|
|
1267
|
-
interface WhereHandler {
|
|
1268
|
-
/** Operator(s) this handler supports */
|
|
1269
|
-
readonly operators: readonly string[];
|
|
1009
|
+
compile<T = unknown>(plan: PlanReport | CompiledNqlQuery, options?: CompileOptions): CompiledQuery<T>;
|
|
1270
1010
|
/**
|
|
1271
|
-
* Compile a
|
|
1272
|
-
* @param decision The condition decision
|
|
1273
|
-
* @param ctx Immutable compiler context
|
|
1274
|
-
* @param state Mutable compiler state
|
|
1275
|
-
* @param dispatch Callback to compile nested conditions
|
|
1276
|
-
* @returns PostgreSQL AST node for the condition
|
|
1011
|
+
* Compile a plan with includes, returning subquery include metadata (DX-033).
|
|
1277
1012
|
*/
|
|
1278
|
-
|
|
1279
|
-
}
|
|
1280
|
-
/**
|
|
1281
|
-
* Dispatcher for recursive WHERE compilation.
|
|
1282
|
-
*/
|
|
1283
|
-
type WhereDispatcher = (decision: Decision, ctx: CompilerContext, state: CompilerState) => Node;
|
|
1284
|
-
/**
|
|
1285
|
-
* Handler for SELECT expressions.
|
|
1286
|
-
* Transforms expression decisions into PostgreSQL AST nodes.
|
|
1287
|
-
*/
|
|
1288
|
-
interface ExpressionHandler {
|
|
1289
|
-
/** Expression type(s) this handler supports */
|
|
1290
|
-
readonly types: readonly string[];
|
|
1013
|
+
compileWithIncludes<T = unknown>(plan: PlanReport, options?: CompileOptions): CompileResultWithIncludes<T>;
|
|
1291
1014
|
/**
|
|
1292
|
-
*
|
|
1015
|
+
* Compile a subquery include query for given parent IDs (DX-033).
|
|
1016
|
+
* Generates: SELECT * FROM targetTable WHERE foreignKey IN ($1, $2, ...)
|
|
1293
1017
|
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1018
|
+
* @param info - Subquery include metadata
|
|
1019
|
+
* @param parentIds - Parent record IDs to fetch related records for
|
|
1020
|
+
* @param options - Compile options
|
|
1021
|
+
* @returns Compiled query for fetching related records
|
|
1296
1022
|
*/
|
|
1297
|
-
readonly
|
|
1023
|
+
compileSubqueryInclude(info: SubqueryIncludeInfo, parentIds: readonly unknown[], options?: CompileOptions): CompiledQuery;
|
|
1298
1024
|
/**
|
|
1299
|
-
* Compile
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1025
|
+
* Compile a FROM-less SELECT expression to SQL.
|
|
1026
|
+
*
|
|
1027
|
+
* Produces: SELECT <expr>
|
|
1028
|
+
* Example: SELECT nextval('my_seq')
|
|
1029
|
+
*
|
|
1030
|
+
* @param expr - ExpressionIntent to evaluate
|
|
1031
|
+
* @returns Compiled SQL and parameters
|
|
1304
1032
|
*/
|
|
1305
|
-
|
|
1306
|
-
}
|
|
1307
|
-
/**
|
|
1308
|
-
* Handler for include/relation strategies.
|
|
1309
|
-
* Transforms include decisions into PostgreSQL constructs (JOIN, LATERAL, json_agg, CTE).
|
|
1310
|
-
*/
|
|
1311
|
-
interface IncludeHandler {
|
|
1312
|
-
/** Strategy this handler implements */
|
|
1313
|
-
readonly strategy: 'join' | 'lateral' | 'json_agg' | 'cte';
|
|
1033
|
+
compileSelectExpression(expr: ExpressionIntent): CompiledQuery;
|
|
1314
1034
|
/**
|
|
1315
|
-
* Compile an
|
|
1316
|
-
*
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1035
|
+
* Compile an insert intent to executable SQL.
|
|
1036
|
+
*
|
|
1037
|
+
* Strategy switch (per CompileOptions):
|
|
1038
|
+
* - rows <= batchThreshold (default 50): VALUES ($1,$2),($3,$4),...
|
|
1039
|
+
* - rows > batchThreshold OR batchThreshold === 0: SELECT unnest($1::type[]),...
|
|
1320
1040
|
*/
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Result of include compilation.
|
|
1325
|
-
*/
|
|
1326
|
-
interface IncludeResult {
|
|
1327
|
-
/** Additional target list items (SELECT columns) */
|
|
1328
|
-
targets?: Node[];
|
|
1329
|
-
/** JOIN to add to FROM clause */
|
|
1330
|
-
join?: Node;
|
|
1331
|
-
/** Additional JOINs for cascaded includes (e.g., flat deep nesting) */
|
|
1332
|
-
additionalJoins?: Node[];
|
|
1333
|
-
/** CTE to add to WITH clause */
|
|
1334
|
-
cte?: Node;
|
|
1335
|
-
/** Subquery for LATERAL */
|
|
1336
|
-
lateral?: Node;
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
* PostgreSQL Schema Introspection (ADAPTER-006)
|
|
1341
|
-
*
|
|
1342
|
-
* Queries information_schema/pg_catalog to build ModelIR
|
|
1343
|
-
* from an existing database. Supports:
|
|
1344
|
-
* - Table/column/PK discovery
|
|
1345
|
-
* - FK → bidirectional relation inference
|
|
1346
|
-
* - Hierarchy detection (adjacency + edge-table)
|
|
1347
|
-
* - Include/exclude filtering
|
|
1348
|
-
*
|
|
1349
|
-
* @module introspection
|
|
1350
|
-
*/
|
|
1351
|
-
|
|
1352
|
-
/** Options for database introspection */
|
|
1353
|
-
interface IntrospectionOptions {
|
|
1354
|
-
/** Tables to exclude (glob patterns: * matches any chars) */
|
|
1355
|
-
readonly exclude?: readonly string[];
|
|
1356
|
-
/** Tables to include (default: all). Applied before exclude. */
|
|
1357
|
-
readonly include?: readonly string[];
|
|
1358
|
-
/** Schema name to introspect (default: 'public') */
|
|
1359
|
-
readonly schema?: string;
|
|
1360
|
-
}
|
|
1361
|
-
/** Hierarchy pattern detected during introspection */
|
|
1362
|
-
/**
|
|
1363
|
-
* Hierarchy pattern detected during introspection.
|
|
1364
|
-
* Alias of {@link HierarchyIR} from \@dbsp/types — kept here for
|
|
1365
|
-
* public-API backwards compatibility (re-exported from \@dbsp/adapter-pgsql).
|
|
1366
|
-
*/
|
|
1367
|
-
type DetectedHierarchy = HierarchyIR;
|
|
1368
|
-
/** Extended ModelIR with hierarchy metadata */
|
|
1369
|
-
interface IntrospectedModelIR extends ModelIR {
|
|
1370
|
-
readonly hierarchies: readonly DetectedHierarchy[];
|
|
1371
|
-
readonly introspectedAt: Date;
|
|
1372
|
-
readonly warnings: readonly string[];
|
|
1373
|
-
}
|
|
1374
|
-
declare function introspect(pool: Pool, options?: IntrospectionOptions): Promise<IntrospectedModelIR>;
|
|
1375
|
-
|
|
1376
|
-
/**
|
|
1377
|
-
* Mutation Compiler
|
|
1378
|
-
*
|
|
1379
|
-
* Compiles INSERT, UPDATE, and DELETE statements from plan decisions.
|
|
1380
|
-
* Supports:
|
|
1381
|
-
* - INSERT with values/from subquery
|
|
1382
|
-
* - INSERT with RETURNING
|
|
1383
|
-
* - UPDATE with SET and WHERE
|
|
1384
|
-
* - DELETE with WHERE
|
|
1385
|
-
* - RETURNING clause for all mutations
|
|
1386
|
-
*/
|
|
1387
|
-
|
|
1388
|
-
/**
|
|
1389
|
-
* Configuration for INSERT compilation
|
|
1390
|
-
*/
|
|
1391
|
-
interface InsertConfig {
|
|
1392
|
-
/** Table to insert into */
|
|
1393
|
-
table: string;
|
|
1394
|
-
/** Columns to insert */
|
|
1395
|
-
columns: string[];
|
|
1396
|
-
/** Values for each column (array of rows) */
|
|
1397
|
-
values: unknown[][];
|
|
1398
|
-
/** Columns to return (RETURNING clause) */
|
|
1399
|
-
returning?: string[];
|
|
1400
|
-
/** Alias-aware RETURNING projection items */
|
|
1401
|
-
returningItems?: readonly MutationReturningItem[];
|
|
1402
|
-
/** Subquery for INSERT ... SELECT */
|
|
1403
|
-
selectQuery?: Node;
|
|
1404
|
-
/** Column database types for type-cast emission (e.g. range types) */
|
|
1405
|
-
columnTypes?: Record<string, string>;
|
|
1406
|
-
}
|
|
1407
|
-
/**
|
|
1408
|
-
* Configuration for UPDATE compilation
|
|
1409
|
-
*/
|
|
1410
|
-
interface UpdateConfig {
|
|
1411
|
-
/** Table to update */
|
|
1412
|
-
table: string;
|
|
1413
|
-
/** Column-value pairs to set */
|
|
1414
|
-
set: {
|
|
1415
|
-
column: string;
|
|
1416
|
-
value: unknown;
|
|
1417
|
-
}[];
|
|
1418
|
-
/** WHERE conditions */
|
|
1419
|
-
where?: Decision[];
|
|
1420
|
-
/** Columns to return (RETURNING clause) */
|
|
1421
|
-
returning?: string[];
|
|
1422
|
-
/** Alias-aware RETURNING projection items */
|
|
1423
|
-
returningItems?: readonly MutationReturningItem[];
|
|
1424
|
-
/** Column database types for type-cast emission (e.g. range types) */
|
|
1425
|
-
columnTypes?: Record<string, string>;
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* Configuration for DELETE compilation
|
|
1429
|
-
*/
|
|
1430
|
-
interface DeleteConfig {
|
|
1431
|
-
/** Table to delete from */
|
|
1432
|
-
table: string;
|
|
1433
|
-
/** WHERE conditions */
|
|
1434
|
-
where?: Decision[];
|
|
1435
|
-
/** Columns to return (RETURNING clause) */
|
|
1436
|
-
returning?: string[];
|
|
1437
|
-
/** Alias-aware RETURNING projection items */
|
|
1438
|
-
returningItems?: readonly MutationReturningItem[];
|
|
1439
|
-
}
|
|
1440
|
-
/**
|
|
1441
|
-
* Compile an INSERT statement from configuration.
|
|
1442
|
-
*/
|
|
1443
|
-
declare function compileInsert(config: InsertConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
1444
|
-
/**
|
|
1445
|
-
* Compile an UPDATE statement from configuration.
|
|
1446
|
-
*/
|
|
1447
|
-
declare function compileUpdate(config: UpdateConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
1448
|
-
declare function compileDelete(config: DeleteConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
1449
|
-
/**
|
|
1450
|
-
* Compile a mutation decision to AST.
|
|
1451
|
-
* Determines mutation type from decision.type and delegates.
|
|
1452
|
-
*/
|
|
1453
|
-
declare function compileMutation(decision: Decision, ctx: CompilerContext, state: CompilerState): Node;
|
|
1454
|
-
|
|
1455
|
-
/**
|
|
1456
|
-
* Upsert (INSERT ... ON CONFLICT) Compiler
|
|
1457
|
-
*
|
|
1458
|
-
* Compiles UPSERT statements with ON CONFLICT handling.
|
|
1459
|
-
* Supports:
|
|
1460
|
-
* - ON CONFLICT DO NOTHING
|
|
1461
|
-
* - ON CONFLICT DO UPDATE SET ...
|
|
1462
|
-
* - Conflict target (columns or constraint name)
|
|
1463
|
-
* - WHERE clause for conflict resolution
|
|
1464
|
-
*/
|
|
1465
|
-
|
|
1466
|
-
/**
|
|
1467
|
-
* Conflict resolution strategy
|
|
1468
|
-
*/
|
|
1469
|
-
type ConflictAction = 'nothing' | 'update';
|
|
1470
|
-
/**
|
|
1471
|
-
* Conflict target specification
|
|
1472
|
-
*/
|
|
1473
|
-
interface ConflictTarget {
|
|
1474
|
-
/** Column names that form the unique constraint */
|
|
1475
|
-
columns?: string[];
|
|
1476
|
-
/** Named constraint */
|
|
1477
|
-
constraint?: string;
|
|
1478
|
-
/** WHERE clause for partial index */
|
|
1479
|
-
where?: Decision[];
|
|
1480
|
-
}
|
|
1481
|
-
/**
|
|
1482
|
-
* Configuration for UPSERT compilation
|
|
1483
|
-
*/
|
|
1484
|
-
interface UpsertConfig {
|
|
1485
|
-
/** Table to upsert into */
|
|
1486
|
-
table: string;
|
|
1487
|
-
/** Columns to insert */
|
|
1488
|
-
columns: string[];
|
|
1489
|
-
/** Values for each column (array of rows) */
|
|
1490
|
-
values: unknown[][];
|
|
1491
|
-
/** Conflict target (unique columns or constraint) */
|
|
1492
|
-
conflictTarget: ConflictTarget;
|
|
1493
|
-
/** What to do on conflict */
|
|
1494
|
-
conflictAction: ConflictAction;
|
|
1495
|
-
/** Columns to update on conflict (for 'update' action) */
|
|
1496
|
-
updateColumns?: string[];
|
|
1497
|
-
/** Optional WHERE clause for ON CONFLICT DO UPDATE */
|
|
1498
|
-
actionWhere?: Decision[];
|
|
1499
|
-
/** Optional direct WHERE intent for ON CONFLICT DO UPDATE */
|
|
1500
|
-
actionWhereIntent?: WhereIntent;
|
|
1501
|
-
/** Compile the direct action WHERE intent using the caller's WHERE compiler */
|
|
1502
|
-
compileActionWhere?: (where: WhereIntent, state: CompilerState) => Node;
|
|
1503
|
-
/** Use EXCLUDED.column for update values (default: true) */
|
|
1504
|
-
useExcluded?: boolean;
|
|
1505
|
-
/** Columns to return (RETURNING clause) */
|
|
1506
|
-
returning?: string[];
|
|
1507
|
-
/** Alias-aware RETURNING projection items */
|
|
1508
|
-
returningItems?: readonly MutationReturningItem[];
|
|
1509
|
-
/** Optional column type hints for unnest casting (schema-driven) */
|
|
1510
|
-
columnTypes?: Record<string, string>;
|
|
1041
|
+
compileInsert(intent: InsertIntent, options?: CompileOptions): CompiledQuery;
|
|
1511
1042
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1514
|
-
* Keys are logical column names (before naming plugin), values are raw SQL fragments.
|
|
1515
|
-
*
|
|
1516
|
-
* @warning SECURITY: fragments are inserted without parameterization.
|
|
1517
|
-
* Only use with hardcoded expressions. Never with user input.
|
|
1518
|
-
*
|
|
1519
|
-
* @example { last_parsed: 'now()', count: 'excluded.count + 1' }
|
|
1043
|
+
* Compile an insert-from intent to executable SQL (NQL-ALIGN).
|
|
1044
|
+
* INSERT INTO target (cols) SELECT cols FROM source WHERE ... LIMIT ... RETURNING ...
|
|
1520
1045
|
*/
|
|
1521
|
-
|
|
1522
|
-
}
|
|
1523
|
-
/**
|
|
1524
|
-
* Build ON CONFLICT clause for INSERT statement.
|
|
1525
|
-
*/
|
|
1526
|
-
declare function buildOnConflictClause(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): OnConflictClause;
|
|
1527
|
-
/**
|
|
1528
|
-
* Compile a complete UPSERT statement.
|
|
1529
|
-
*/
|
|
1530
|
-
declare function compileUpsert(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
1531
|
-
/**
|
|
1532
|
-
* Build EXCLUDED.column reference.
|
|
1533
|
-
* EXCLUDED is a special table alias in ON CONFLICT ... DO UPDATE
|
|
1534
|
-
* that refers to the row that would have been inserted.
|
|
1535
|
-
*/
|
|
1536
|
-
declare function excludedRef(column: string, naming: {
|
|
1537
|
-
toDatabase: (s: string) => string;
|
|
1538
|
-
}): Node;
|
|
1539
|
-
/**
|
|
1540
|
-
* Build conditional update using COALESCE.
|
|
1541
|
-
*
|
|
1542
|
-
* Produces: COALESCE(EXCLUDED.col, table.col)
|
|
1543
|
-
* This keeps existing value if new value is NULL.
|
|
1544
|
-
*/
|
|
1545
|
-
declare function conditionalUpdate(column: string, table: string, ctx: CompilerContext): Node;
|
|
1546
|
-
|
|
1547
|
-
/**
|
|
1548
|
-
* @module naming
|
|
1549
|
-
* Utilities for resolving database names to logical model names.
|
|
1550
|
-
*
|
|
1551
|
-
* The ModelIR.getTable() method expects logical (camelCase) names,
|
|
1552
|
-
* but the adapter often works with database (snake_case) names.
|
|
1553
|
-
* This module bridges that gap.
|
|
1554
|
-
*/
|
|
1555
|
-
|
|
1556
|
-
/**
|
|
1557
|
-
* Resolve a database table name to the corresponding logical model name.
|
|
1558
|
-
*
|
|
1559
|
-
* Converts the DB name using the naming convention, then looks it up in the model.
|
|
1560
|
-
* Falls back to exact match if conversion doesn't find a match.
|
|
1561
|
-
*
|
|
1562
|
-
* @param model - The model IR to search in
|
|
1563
|
-
* @param dbName - Database table name (e.g. "post_comments")
|
|
1564
|
-
* @param convention - Naming convention used by the adapter
|
|
1565
|
-
* @returns The logical table name if found, undefined otherwise
|
|
1566
|
-
*
|
|
1567
|
-
* @example
|
|
1568
|
-
* ```typescript
|
|
1569
|
-
* // With camelCase convention:
|
|
1570
|
-
* resolveLogicalName(model, "post_comments", "camelCase") // → "postComments"
|
|
1571
|
-
* resolveLogicalName(model, "posts", "camelCase") // → "posts"
|
|
1572
|
-
* resolveLogicalName(model, "unknown", "camelCase") // → undefined
|
|
1573
|
-
* ```
|
|
1574
|
-
*/
|
|
1575
|
-
declare function resolveLogicalName(model: ModelIR, dbName: string, casing: DbCasing): string | undefined;
|
|
1576
|
-
|
|
1577
|
-
/**
|
|
1578
|
-
* ParamRef validation and helpers for PostgreSQL AST
|
|
1579
|
-
*
|
|
1580
|
-
* ParamRef nodes represent parameterized query placeholders ($1, $2, etc.)
|
|
1581
|
-
* This module provides validation and creation helpers for safe AST construction.
|
|
1582
|
-
*/
|
|
1583
|
-
|
|
1584
|
-
/**
|
|
1585
|
-
* Validation result for ParamRef nodes
|
|
1586
|
-
*/
|
|
1587
|
-
interface ParamRefValidationResult {
|
|
1588
|
-
valid: boolean;
|
|
1589
|
-
errors: string[];
|
|
1590
|
-
}
|
|
1591
|
-
/**
|
|
1592
|
-
* Validates a ParamRef node
|
|
1593
|
-
*
|
|
1594
|
-
* Rules:
|
|
1595
|
-
* - `number` must be a positive integer (1-based indexing)
|
|
1596
|
-
* - `number` must not exceed reasonable bounds (e.g., 65535)
|
|
1597
|
-
*/
|
|
1598
|
-
declare function validateParamRef(paramRef: ParamRef): ParamRefValidationResult;
|
|
1599
|
-
/**
|
|
1600
|
-
* Creates a validated ParamRef node
|
|
1601
|
-
* @throws Error if validation fails
|
|
1602
|
-
*/
|
|
1603
|
-
declare function createParamRef(number: number, location?: number): Node;
|
|
1604
|
-
/**
|
|
1605
|
-
* Creates a TypeCast node wrapping a ParamRef
|
|
1606
|
-
* Example: $1::integer, $2::text[]
|
|
1607
|
-
*/
|
|
1608
|
-
declare function createTypeCastParamRef(paramNumber: number, typeName: string, isArray?: boolean, location?: number): Node;
|
|
1609
|
-
/**
|
|
1610
|
-
* Creates an A_Expr node for equality comparison with ParamRef
|
|
1611
|
-
* Example: col = $1
|
|
1612
|
-
*/
|
|
1613
|
-
declare function createEqualityExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
|
|
1614
|
-
/**
|
|
1615
|
-
* Creates a FuncCall node for ANY() with ParamRef
|
|
1616
|
-
* Example: col = ANY($1) for array parameter matching
|
|
1617
|
-
*/
|
|
1618
|
-
declare function createAnyExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
|
|
1619
|
-
/**
|
|
1620
|
-
* Collects all ParamRef nodes from an AST, validating each
|
|
1621
|
-
* Returns validation results for all found ParamRefs
|
|
1622
|
-
*/
|
|
1623
|
-
declare function collectAndValidateParamRefs(node: unknown): {
|
|
1624
|
-
paramRefs: Array<{
|
|
1625
|
-
paramRef: ParamRef;
|
|
1626
|
-
path: string;
|
|
1627
|
-
}>;
|
|
1628
|
-
validationResults: ParamRefValidationResult[];
|
|
1629
|
-
allValid: boolean;
|
|
1630
|
-
};
|
|
1631
|
-
|
|
1632
|
-
/**
|
|
1633
|
-
* PgsqlAdapter - Implements the Adapter interface for PostgreSQL using native pg driver.
|
|
1634
|
-
*
|
|
1635
|
-
* This adapter wraps a pg Pool instance and provides the unified
|
|
1636
|
-
* adapter interface for the db-semantic-planner ORM.
|
|
1637
|
-
*
|
|
1638
|
-
* @module pgsql-adapter
|
|
1639
|
-
*/
|
|
1640
|
-
|
|
1641
|
-
/**
|
|
1642
|
-
* Options for PgsqlAdapter.
|
|
1643
|
-
*/
|
|
1644
|
-
interface PgsqlAdapterOptions {
|
|
1645
|
-
/** Schema name for multi-tenant queries */
|
|
1646
|
-
readonly schemaName?: string;
|
|
1046
|
+
compileInsertFrom(intent: InsertFromIntent, options?: CompileOptions): CompiledQuery;
|
|
1647
1047
|
/**
|
|
1648
|
-
*
|
|
1649
|
-
* - `'snake_case'`: DB columns are snake_case → transform to camelCase for JS
|
|
1650
|
-
* - `'camelCase'`: DB columns are camelCase → no transformation
|
|
1651
|
-
* - `'preserve'`: No transformation
|
|
1048
|
+
* Compile an update intent to executable SQL.
|
|
1652
1049
|
*/
|
|
1653
|
-
|
|
1654
|
-
/** Optional model for WHERE compilation */
|
|
1655
|
-
readonly model?: ModelIR;
|
|
1656
|
-
/** Optional logger for debug/error messages */
|
|
1657
|
-
readonly logger?: AdapterLogger;
|
|
1658
|
-
/** Default primary key column name for convention fallbacks (default: 'id') */
|
|
1659
|
-
readonly defaultPkColumnName?: string;
|
|
1660
|
-
/** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
|
|
1661
|
-
readonly deriveFkColumnName?: FkColumnDerivation;
|
|
1662
|
-
}
|
|
1663
|
-
/**
|
|
1664
|
-
* Adapter implementation for PostgreSQL using native pg driver.
|
|
1665
|
-
*
|
|
1666
|
-
* @typeParam DB - Database schema type
|
|
1667
|
-
*
|
|
1668
|
-
* @example
|
|
1669
|
-
* ```typescript
|
|
1670
|
-
* import { Pool } from 'pg';
|
|
1671
|
-
* import { createPgsqlAdapter } from '@dbsp/adapter-pgsql';
|
|
1672
|
-
*
|
|
1673
|
-
* const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
1674
|
-
* const adapter = createPgsqlAdapter(pool);
|
|
1675
|
-
* const orm = createOrm({ model, adapter });
|
|
1676
|
-
* ```
|
|
1677
|
-
*/
|
|
1678
|
-
declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
1679
|
-
private readonly pool;
|
|
1680
|
-
private readonly client;
|
|
1681
|
-
private readonly schemaName;
|
|
1682
|
-
private readonly _dbCasing;
|
|
1683
|
-
private readonly naming;
|
|
1684
|
-
private readonly model;
|
|
1685
|
-
private readonly logger;
|
|
1686
|
-
private readonly _capabilities;
|
|
1687
|
-
private readonly defaultPk;
|
|
1688
|
-
private readonly deriveFk;
|
|
1050
|
+
compileUpdate(intent: UpdateIntent, options?: CompileOptions): CompiledQuery;
|
|
1689
1051
|
/**
|
|
1690
|
-
*
|
|
1052
|
+
* Compile a batch update intent to executable SQL using unnest FROM strategy (BATCH-001).
|
|
1691
1053
|
*
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
* Shared compilation dependencies — built lazily from adapter fields.
|
|
1698
|
-
* Passed to compiler sub-modules instead of `this`.
|
|
1054
|
+
* Generates:
|
|
1055
|
+
* UPDATE "table" SET "update_col" = t."update_col" [, "scalar_col" = $N]
|
|
1056
|
+
* FROM unnest(CAST($1 AS type[]), CAST($2 AS type[])) AS t("match_col", "update_col")
|
|
1057
|
+
* WHERE "table"."match_col" = t."match_col"
|
|
1058
|
+
* [RETURNING ...]
|
|
1699
1059
|
*/
|
|
1060
|
+
compileBatchUpdate(intent: BatchUpdateIntent, options?: CompileOptions): CompiledQuery;
|
|
1700
1061
|
/**
|
|
1701
|
-
*
|
|
1702
|
-
* Ensures that all configuration fields (logger, defaultPkColumnName,
|
|
1703
|
-
* deriveFkColumnName, etc.) are propagated to scoped/transactional adapters.
|
|
1062
|
+
* Compile a delete intent to executable SQL.
|
|
1704
1063
|
*/
|
|
1705
|
-
|
|
1706
|
-
private buildCompileDeps;
|
|
1707
|
-
private requireNqlCompileModel;
|
|
1708
|
-
private assertNqlBindingNamesDisjointFromTables;
|
|
1709
|
-
private compileNqlMutation;
|
|
1710
|
-
private compileNqlBundleLeaf;
|
|
1711
|
-
private compileNqlBundle;
|
|
1064
|
+
compileDelete(intent: DeleteIntent, options?: CompileOptions): CompiledQuery;
|
|
1712
1065
|
/**
|
|
1713
|
-
*
|
|
1066
|
+
* Compile an upsert intent to executable SQL (DX-026).
|
|
1714
1067
|
*/
|
|
1715
|
-
|
|
1716
|
-
/** Adapter capabilities for feature detection */
|
|
1717
|
-
get capabilities(): AdapterCapabilities;
|
|
1718
|
-
/** PostgreSQL dialect capabilities for planner strategy selection */
|
|
1719
|
-
get dialectCapabilities(): DialectCapabilities;
|
|
1068
|
+
compileUpsert(intent: UpsertIntent, options?: CompileOptions): CompiledQuery;
|
|
1720
1069
|
/**
|
|
1721
|
-
*
|
|
1070
|
+
* Compile an upsert-from intent to executable SQL (NQL-BIND).
|
|
1071
|
+
* INSERT INTO target SELECT ... FROM source ON CONFLICT (cols) DO UPDATE SET ...
|
|
1722
1072
|
*/
|
|
1723
|
-
|
|
1073
|
+
compileUpsertFrom(intent: UpsertFromIntent, options?: CompileOptions): CompiledQuery;
|
|
1724
1074
|
/**
|
|
1725
|
-
*
|
|
1075
|
+
* Compile a recursive CTE plan to executable SQL.
|
|
1076
|
+
* Supports adjacency-list and edge-table traversal modes.
|
|
1726
1077
|
*/
|
|
1727
|
-
|
|
1078
|
+
compileRecursive(report: RecursivePlanReport, model: ModelIR, options?: CompileOptions): CompiledQuery;
|
|
1728
1079
|
/**
|
|
1729
|
-
* Compile a
|
|
1080
|
+
* Compile a CTE query backed by unnest() arrays (BATCH-001 Block 5).
|
|
1730
1081
|
*
|
|
1731
|
-
*
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
* before CTE emission.
|
|
1082
|
+
* Strategy: compile CTE nodes to SQL fragments, compile outer query
|
|
1083
|
+
* independently (parameters starting at $1), then renumber outer params
|
|
1084
|
+
* to start after CTE params and prepend WITH clause.
|
|
1735
1085
|
*/
|
|
1736
|
-
|
|
1086
|
+
compileCteQuery(intent: CteQueryIntent, options?: CompileOptions): CompiledQuery;
|
|
1737
1087
|
/**
|
|
1738
|
-
* Compile a
|
|
1088
|
+
* Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL.
|
|
1739
1089
|
*/
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
* Compile a subquery include query for given parent IDs (DX-033).
|
|
1743
|
-
* Generates: SELECT * FROM targetTable WHERE foreignKey IN ($1, $2, ...)
|
|
1744
|
-
*
|
|
1745
|
-
* @param info - Subquery include metadata
|
|
1746
|
-
* @param parentIds - Parent record IDs to fetch related records for
|
|
1747
|
-
* @param options - Compile options
|
|
1748
|
-
* @returns Compiled query for fetching related records
|
|
1749
|
-
*/
|
|
1750
|
-
compileSubqueryInclude(info: SubqueryIncludeInfo, parentIds: readonly unknown[], options?: CompileOptions): CompiledQuery;
|
|
1751
|
-
/**
|
|
1752
|
-
* Compile a FROM-less SELECT expression to SQL.
|
|
1753
|
-
*
|
|
1754
|
-
* Produces: SELECT <expr>
|
|
1755
|
-
* Example: SELECT nextval('my_seq')
|
|
1756
|
-
*
|
|
1757
|
-
* @param expr - ExpressionIntent to evaluate
|
|
1758
|
-
* @returns Compiled SQL and parameters
|
|
1759
|
-
*/
|
|
1760
|
-
compileSelectExpression(expr: ExpressionIntent): CompiledQuery;
|
|
1761
|
-
/**
|
|
1762
|
-
* Compile an insert intent to executable SQL.
|
|
1763
|
-
*
|
|
1764
|
-
* Strategy switch (per CompileOptions):
|
|
1765
|
-
* - rows <= batchThreshold (default 50): VALUES ($1,$2),($3,$4),...
|
|
1766
|
-
* - rows > batchThreshold OR batchThreshold === 0: SELECT unnest($1::type[]),...
|
|
1767
|
-
*/
|
|
1768
|
-
compileInsert(intent: InsertIntent, options?: CompileOptions): CompiledQuery;
|
|
1769
|
-
/**
|
|
1770
|
-
* Compile an insert-from intent to executable SQL (NQL-ALIGN).
|
|
1771
|
-
* INSERT INTO target (cols) SELECT cols FROM source WHERE ... LIMIT ... RETURNING ...
|
|
1772
|
-
*/
|
|
1773
|
-
compileInsertFrom(intent: InsertFromIntent, options?: CompileOptions): CompiledQuery;
|
|
1774
|
-
/**
|
|
1775
|
-
* Compile an update intent to executable SQL.
|
|
1776
|
-
*/
|
|
1777
|
-
compileUpdate(intent: UpdateIntent, options?: CompileOptions): CompiledQuery;
|
|
1778
|
-
/**
|
|
1779
|
-
* Compile a batch update intent to executable SQL using unnest FROM strategy (BATCH-001).
|
|
1780
|
-
*
|
|
1781
|
-
* Generates:
|
|
1782
|
-
* UPDATE "table" SET "update_col" = t."update_col" [, "scalar_col" = $N]
|
|
1783
|
-
* FROM unnest(CAST($1 AS type[]), CAST($2 AS type[])) AS t("match_col", "update_col")
|
|
1784
|
-
* WHERE "table"."match_col" = t."match_col"
|
|
1785
|
-
* [RETURNING ...]
|
|
1786
|
-
*/
|
|
1787
|
-
compileBatchUpdate(intent: BatchUpdateIntent, options?: CompileOptions): CompiledQuery;
|
|
1788
|
-
/**
|
|
1789
|
-
* Compile a delete intent to executable SQL.
|
|
1790
|
-
*/
|
|
1791
|
-
compileDelete(intent: DeleteIntent, options?: CompileOptions): CompiledQuery;
|
|
1792
|
-
/**
|
|
1793
|
-
* Compile an upsert intent to executable SQL (DX-026).
|
|
1794
|
-
*/
|
|
1795
|
-
compileUpsert(intent: UpsertIntent, options?: CompileOptions): CompiledQuery;
|
|
1796
|
-
/**
|
|
1797
|
-
* Compile an upsert-from intent to executable SQL (NQL-BIND).
|
|
1798
|
-
* INSERT INTO target SELECT ... FROM source ON CONFLICT (cols) DO UPDATE SET ...
|
|
1799
|
-
*/
|
|
1800
|
-
compileUpsertFrom(intent: UpsertFromIntent, options?: CompileOptions): CompiledQuery;
|
|
1801
|
-
/**
|
|
1802
|
-
* Compile a recursive CTE plan to executable SQL.
|
|
1803
|
-
* Supports adjacency-list and edge-table traversal modes.
|
|
1804
|
-
*/
|
|
1805
|
-
compileRecursive(report: RecursivePlanReport, model: ModelIR, options?: CompileOptions): CompiledQuery;
|
|
1806
|
-
/**
|
|
1807
|
-
* Compile a CTE query backed by unnest() arrays (BATCH-001 Block 5).
|
|
1808
|
-
*
|
|
1809
|
-
* Strategy: compile CTE nodes to SQL fragments, compile outer query
|
|
1810
|
-
* independently (parameters starting at $1), then renumber outer params
|
|
1811
|
-
* to start after CTE params and prepend WITH clause.
|
|
1812
|
-
*/
|
|
1813
|
-
compileCteQuery(intent: CteQueryIntent, options?: CompileOptions): CompiledQuery;
|
|
1814
|
-
/**
|
|
1815
|
-
* Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL.
|
|
1816
|
-
*/
|
|
1817
|
-
compileSetOperation(intent: SetOperationIntent, model: ModelIR, options?: CompileOptions): CompiledQuery;
|
|
1818
|
-
private compileSetOperationWithBindings;
|
|
1090
|
+
compileSetOperation(intent: SetOperationIntent, model: ModelIR, options?: CompileOptions): CompiledQuery;
|
|
1091
|
+
private compileSetOperationWithBindings;
|
|
1819
1092
|
/**
|
|
1820
1093
|
* Create a dump for observability.
|
|
1821
1094
|
*/
|
|
@@ -1854,6 +1127,9 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
|
1854
1127
|
* Internal: Stream with an existing client using cursors.
|
|
1855
1128
|
*/
|
|
1856
1129
|
private streamWithClient;
|
|
1130
|
+
private streamWithManagedClient;
|
|
1131
|
+
private streamWithManagedClientSavepointScope;
|
|
1132
|
+
private streamWithClientTransaction;
|
|
1857
1133
|
/**
|
|
1858
1134
|
* Introspect the database schema and return a ModelIR.
|
|
1859
1135
|
*
|
|
@@ -1870,8 +1146,83 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
|
1870
1146
|
introspect(options?: IntrospectionOptions): Promise<IntrospectedModelIR>;
|
|
1871
1147
|
/**
|
|
1872
1148
|
* Execute a callback within a database transaction.
|
|
1149
|
+
*
|
|
1150
|
+
* ## What this guarantees
|
|
1151
|
+
*
|
|
1152
|
+
* The callback's work commits together or not at all; a statement issued inside
|
|
1153
|
+
* the transaction never executes after its boundary, even if you forget to
|
|
1154
|
+
* `await` it; a nested `transaction()` is a real savepoint; and the connection
|
|
1155
|
+
* never goes back to the pool with a transaction still open on it.
|
|
1156
|
+
*
|
|
1157
|
+
* ## What it cannot guarantee, and you should know before you reach for raw SQL
|
|
1158
|
+
*
|
|
1159
|
+
* **Raw SQL that ends the transaction ends it.** `COMMIT`, `ROLLBACK` and
|
|
1160
|
+
* `PREPARE TRANSACTION` issued through `executeRaw` — or through several commands
|
|
1161
|
+
* in one call — reach PostgreSQL and take effect *before* dbsp is told what they
|
|
1162
|
+
* were: the command tag arrives after the statement has run. dbsp detects it, kills
|
|
1163
|
+
* the scope so nothing else escapes, and throws — but **it cannot un-run what your
|
|
1164
|
+
* statement already did**, and `transaction()` rejecting does not mean nothing was
|
|
1165
|
+
* committed.
|
|
1166
|
+
*
|
|
1167
|
+
* The same holds for session state raw SQL creates: a sequence that advanced stays
|
|
1168
|
+
* advanced, an advisory lock stays held, a `PREPARE` or a `SET` you issued survives
|
|
1169
|
+
* on a pooled connection. dbsp cleans up only what dbsp created.
|
|
1170
|
+
*
|
|
1171
|
+
* This is the contract of an escape hatch, not an oversight — see #327. If you need
|
|
1172
|
+
* transaction control, own the transaction: take a client, `BEGIN` on it yourself,
|
|
1173
|
+
* and hand dbsp a `borrowedClient` **without** `managedTransactions`. dbsp will then
|
|
1174
|
+
* contain its own statements inside *your* transaction instead of the other way round.
|
|
1873
1175
|
*/
|
|
1874
1176
|
transaction<T>(fn: (adapter: Adapter<DB>) => Promise<T>): Promise<T>;
|
|
1177
|
+
/**
|
|
1178
|
+
* Execute scratch PostgreSQL work in a scope that always rolls back on success.
|
|
1179
|
+
*
|
|
1180
|
+
* This is intentionally PostgreSQL-adapter-specific. It is used for catalog
|
|
1181
|
+
* shaped scratch DDL such as CHECK expression canonicalisation, where the
|
|
1182
|
+
* caller needs PostgreSQL's rendering but must not keep the scratch objects.
|
|
1183
|
+
* Rollback here is cleanup of dbsp-created work, not a sandbox for arbitrary
|
|
1184
|
+
* session effects.
|
|
1185
|
+
*/
|
|
1186
|
+
withScratchScope<T>(fn: (adapter: PgsqlAdapter<DB>) => Promise<T>): Promise<T>;
|
|
1187
|
+
private createManagedClientAdapter;
|
|
1188
|
+
private createChildTransactionObserver;
|
|
1189
|
+
private observeChildTransaction;
|
|
1190
|
+
private markChildTransactionObserved;
|
|
1191
|
+
private refreshScopeChildrenFailure;
|
|
1192
|
+
private transactionWithManagedClient;
|
|
1193
|
+
private transactionWithManagedClientSavepointScope;
|
|
1194
|
+
private transactionWithClientTransaction;
|
|
1195
|
+
private releaseClient;
|
|
1196
|
+
private rollbackAndReleaseSavepoint;
|
|
1197
|
+
private rollbackSavepoint;
|
|
1198
|
+
private releaseSavepoint;
|
|
1199
|
+
private rollbackTransactionIfOpen;
|
|
1200
|
+
private classifyTransactionStateError;
|
|
1201
|
+
private probeTransactionState;
|
|
1202
|
+
private classifySavepointReleaseFailure;
|
|
1203
|
+
private rollbackSavepointAfterReleaseFailure;
|
|
1204
|
+
private enterTransactionScope;
|
|
1205
|
+
private enterSavepointScope;
|
|
1206
|
+
private pushClientScope;
|
|
1207
|
+
private currentClientScope;
|
|
1208
|
+
private assertCanUseClient;
|
|
1209
|
+
private assertUsableScopeAncestors;
|
|
1210
|
+
private findClientScope;
|
|
1211
|
+
private assertScopeNotPoisoned;
|
|
1212
|
+
private throwIfScopePoisoned;
|
|
1213
|
+
private scopePoisonOutranksError;
|
|
1214
|
+
private poisonScopeState;
|
|
1215
|
+
private poisonClientScope;
|
|
1216
|
+
private poisonClientScopeStack;
|
|
1217
|
+
private runWithScopeStatementLock;
|
|
1218
|
+
private closeScope;
|
|
1219
|
+
private closeScopeAndAssertChildren;
|
|
1220
|
+
private drainScopeStatements;
|
|
1221
|
+
private drainScopeChildren;
|
|
1222
|
+
private assertScopeChildrenSettled;
|
|
1223
|
+
private drainScopeWork;
|
|
1224
|
+
private executeScopeBoundaryStatement;
|
|
1225
|
+
private assertCommitSucceeded;
|
|
1875
1226
|
/**
|
|
1876
1227
|
* Create a schema-scoped adapter for multi-tenant queries.
|
|
1877
1228
|
*/
|
|
@@ -1880,6 +1231,15 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
|
1880
1231
|
* Execute raw SQL directly.
|
|
1881
1232
|
*
|
|
1882
1233
|
* ⚠️ WARNING: Use parameter placeholders ($1, $2, etc.) for all values.
|
|
1234
|
+
*
|
|
1235
|
+
* Transaction control through raw SQL inside a scope dbsp is managing is
|
|
1236
|
+
* unsupported. `COMMIT`, `ROLLBACK`, and `PREPARE TRANSACTION` end the
|
|
1237
|
+
* transaction dbsp is working inside; dbsp detects that and fails loudly, but
|
|
1238
|
+
* the data is already whatever your statement made it. Raw savepoint control
|
|
1239
|
+
* (`SAVEPOINT`, `RELEASE SAVEPOINT`, `ROLLBACK TO SAVEPOINT`) can alter the
|
|
1240
|
+
* savepoint stack before dbsp sees the command tag; dbsp poisons the scope, but
|
|
1241
|
+
* it cannot make that command un-run. Manage your transaction outside dbsp's
|
|
1242
|
+
* calls.
|
|
1883
1243
|
*/
|
|
1884
1244
|
executeRaw<T = unknown>(sql: string, parameters?: readonly unknown[]): Promise<T[]>;
|
|
1885
1245
|
/**
|
|
@@ -1901,17 +1261,35 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
|
1901
1261
|
*/
|
|
1902
1262
|
executeDDL(sql: string): Promise<void>;
|
|
1903
1263
|
/**
|
|
1904
|
-
* Whether
|
|
1905
|
-
*
|
|
1264
|
+
* Whether a transaction is open on this adapter's connection.
|
|
1265
|
+
* This is true for dbsp-managed scopes and for borrowed pg clients whose
|
|
1266
|
+
* ReadyForQuery status says the caller has an open transaction.
|
|
1906
1267
|
*
|
|
1907
1268
|
* @since DDL-TABLE-001
|
|
1908
1269
|
*/
|
|
1909
1270
|
get inTransaction(): boolean;
|
|
1271
|
+
private adapterManagedScopeIsLive;
|
|
1272
|
+
private executeQueryProtectingOpenTransaction;
|
|
1273
|
+
private executeConnectionStatement;
|
|
1274
|
+
private executeConnectionStatementUnlocked;
|
|
1275
|
+
private executeConnectionStatementInSavepoint;
|
|
1276
|
+
private issueConnectionQuery;
|
|
1277
|
+
private assertNoMultiCommandRawCall;
|
|
1278
|
+
private assertNoTransactionControlCommand;
|
|
1279
|
+
private assertPrepareDidNotEndTransaction;
|
|
1280
|
+
/**
|
|
1281
|
+
* Resolve the explicit schema for a catalog read: an explicit argument, else
|
|
1282
|
+
* the adapter's configured schema, else `undefined` (resolve in-query). NOT a
|
|
1283
|
+
* hard-coded 'public' — an unresolved schema is handled by the SQL, which
|
|
1284
|
+
* finds the table's schema search_path-aware, in the SAME session, so a
|
|
1285
|
+
* non-public search_path and a pooled connection both stay correct.
|
|
1286
|
+
*/
|
|
1287
|
+
private explicitSchema;
|
|
1910
1288
|
/**
|
|
1911
1289
|
* List all indexes on a table by querying pg_indexes.
|
|
1912
1290
|
*
|
|
1913
1291
|
* @param table - Table name
|
|
1914
|
-
* @param schema - Schema name (defaults to
|
|
1292
|
+
* @param schema - Schema name (defaults to the search_path-resolved schema)
|
|
1915
1293
|
*/
|
|
1916
1294
|
listIndexes(table: string, schema?: string, options?: {
|
|
1917
1295
|
namePattern?: string;
|
|
@@ -1921,93 +1299,1047 @@ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
|
|
|
1921
1299
|
*
|
|
1922
1300
|
* @param name - Index name
|
|
1923
1301
|
* @param table - Table name
|
|
1924
|
-
* @param schema - Schema name (defaults to
|
|
1302
|
+
* @param schema - Schema name (defaults to the search_path-resolved schema)
|
|
1925
1303
|
*/
|
|
1926
1304
|
indexExists(name: string, table: string, schema?: string): Promise<boolean>;
|
|
1927
1305
|
/**
|
|
1928
|
-
* Return the total storage size of a table in bytes.
|
|
1306
|
+
* Return the total storage size of a table in bytes (includes indexes and TOAST).
|
|
1307
|
+
*
|
|
1308
|
+
* The table name is a SQL identifier — it is double-quoted, not parameterized,
|
|
1309
|
+
* because PostgreSQL does not allow parameterized table names in FROM clauses.
|
|
1310
|
+
* With no known schema the table is left unqualified so ::regclass resolves it
|
|
1311
|
+
* through search_path (the same table an unqualified reference would hit).
|
|
1929
1312
|
*
|
|
1930
1313
|
* @param table - Table name
|
|
1931
|
-
* @param schema - Schema name (defaults to
|
|
1314
|
+
* @param schema - Schema name (defaults to the search_path-resolved schema)
|
|
1315
|
+
*/
|
|
1316
|
+
storageSize(table: string, schema?: string): Promise<number>;
|
|
1317
|
+
/**
|
|
1318
|
+
* Generate SQL for TRUNCATE TABLE.
|
|
1319
|
+
* Implements TableDDLGeneratorAdapter.generateTruncate.
|
|
1320
|
+
*/
|
|
1321
|
+
generateTruncate(table: string, schema?: string, options?: TruncateOptions): string;
|
|
1322
|
+
/**
|
|
1323
|
+
* Generate SQL for VACUUM.
|
|
1324
|
+
* Implements TableDDLGeneratorAdapter.generateVacuum.
|
|
1325
|
+
*/
|
|
1326
|
+
generateVacuum(table: string, schema?: string, options?: VacuumOptions): string;
|
|
1327
|
+
/**
|
|
1328
|
+
* Generate SQL for ALTER TABLE ... ALTER COLUMN.
|
|
1329
|
+
* Implements TableDDLGeneratorAdapter.generateAlterColumn.
|
|
1330
|
+
*/
|
|
1331
|
+
generateAlterColumn(table: string, column: string, options: AlterColumnOptions, schema?: string): string;
|
|
1332
|
+
/**
|
|
1333
|
+
* Generate SQL for CREATE INDEX.
|
|
1334
|
+
* Implements TableDDLGeneratorAdapter.generateCreateIndex.
|
|
1335
|
+
*/
|
|
1336
|
+
generateCreateIndex(table: string, options: CreateIndexOptions, schema?: string): string;
|
|
1337
|
+
/**
|
|
1338
|
+
* Generate SQL for DROP INDEX.
|
|
1339
|
+
* Implements TableDDLGeneratorAdapter.generateDropIndex.
|
|
1340
|
+
*/
|
|
1341
|
+
generateDropIndex(name: string, options?: DropIndexOptions): string;
|
|
1342
|
+
/**
|
|
1343
|
+
* Validate an identifier (table name, column name, schema name).
|
|
1344
|
+
*/
|
|
1345
|
+
validateIdentifier(value: string, type: string): void;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Create a PgsqlAdapter from a pg Pool instance.
|
|
1349
|
+
*
|
|
1350
|
+
* @param pool - pg Pool instance
|
|
1351
|
+
* @param options - Optional configuration
|
|
1352
|
+
* @returns A new PgsqlAdapter instance
|
|
1353
|
+
*
|
|
1354
|
+
* @example
|
|
1355
|
+
* ```typescript
|
|
1356
|
+
* import { Pool } from 'pg';
|
|
1357
|
+
* import { createPgsqlAdapter } from '@dbsp/adapter-pgsql';
|
|
1358
|
+
*
|
|
1359
|
+
* const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
1360
|
+
* const adapter = createPgsqlAdapter(pool);
|
|
1361
|
+
*
|
|
1362
|
+
* // With naming convention
|
|
1363
|
+
* const adapter = createPgsqlAdapter(pool, { dbCasing: 'snake_case' });
|
|
1364
|
+
* ```
|
|
1365
|
+
*/
|
|
1366
|
+
declare function createPgsqlAdapter<DB = unknown>(pool: Pool, options?: PgsqlPoolAdapterOptions): PgsqlAdapter<DB>;
|
|
1367
|
+
declare function createPgsqlAdapter<DB = unknown>(client: PoolClient, options: PgsqlBorrowedClientAdapterOptions): PgsqlAdapter<DB>;
|
|
1368
|
+
/**
|
|
1369
|
+
* Creates a compile-only PgsqlAdapter for SQL generation without a database connection.
|
|
1370
|
+
*
|
|
1371
|
+
* All compilation methods (compile, compileInsert, etc.), createDump(), and generateDDL()
|
|
1372
|
+
* work normally. Execution methods (execute, stream, transaction, etc.) throw an error.
|
|
1373
|
+
*
|
|
1374
|
+
* @example
|
|
1375
|
+
* ```typescript
|
|
1376
|
+
* import { createPgsqlCompileOnlyAdapter } from '@dbsp/adapter-pgsql';
|
|
1377
|
+
* import { createOrm } from '@dbsp/core';
|
|
1378
|
+
*
|
|
1379
|
+
* const adapter = createPgsqlCompileOnlyAdapter();
|
|
1380
|
+
* const orm = createOrm({ model, adapter });
|
|
1381
|
+
* const dump = await orm.select('users').dump();
|
|
1382
|
+
* console.log(dump.sql);
|
|
1383
|
+
* ```
|
|
1384
|
+
*/
|
|
1385
|
+
declare function createPgsqlCompileOnlyAdapter<DB = unknown>(options?: PgsqlAdapterOptions): CompileOnlyAdapter;
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Schema Comparison Engine (DDL-PROV Block 1)
|
|
1389
|
+
*
|
|
1390
|
+
* Compares two ModelIRs (schema definition vs database state)
|
|
1391
|
+
* and produces a structured diff of changes needed.
|
|
1392
|
+
*
|
|
1393
|
+
* @module schema-diff
|
|
1394
|
+
*/
|
|
1395
|
+
|
|
1396
|
+
type ChangeKind = 'create_table' | 'drop_table' | 'add_column' | 'drop_column' | 'alter_column_type' | 'alter_column_nullable' | 'alter_column_default' | 'alter_column_unique' | 'add_primary_key' | 'drop_primary_key' | 'add_foreign_key' | 'drop_foreign_key' | 'alter_foreign_key' | 'validate_constraint' | 'create_index' | 'drop_index' | 'add_check_constraint' | 'drop_check_constraint' | 'create_enum' | 'alter_enum_add_value' | 'drop_enum' | 'alter_column_collation' | 'alter_column_identity' | 'add_comment' | 'drop_comment' | 'create_extension' | 'drop_extension' | 'create_sequence' | 'alter_sequence' | 'drop_sequence' | 'enable_rls' | 'disable_rls' | 'create_policy' | 'drop_policy';
|
|
1397
|
+
interface SchemaChange {
|
|
1398
|
+
readonly kind: ChangeKind;
|
|
1399
|
+
readonly table: string;
|
|
1400
|
+
readonly column?: string;
|
|
1401
|
+
readonly destructive: boolean;
|
|
1402
|
+
readonly details: string;
|
|
1403
|
+
/** Additional metadata for SQL generation */
|
|
1404
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
1405
|
+
}
|
|
1406
|
+
interface DiffSummary {
|
|
1407
|
+
readonly tables: {
|
|
1408
|
+
readonly added: number;
|
|
1409
|
+
readonly dropped: number;
|
|
1410
|
+
};
|
|
1411
|
+
readonly columns: {
|
|
1412
|
+
readonly added: number;
|
|
1413
|
+
readonly dropped: number;
|
|
1414
|
+
readonly altered: number;
|
|
1415
|
+
};
|
|
1416
|
+
readonly indexes: {
|
|
1417
|
+
readonly added: number;
|
|
1418
|
+
readonly dropped: number;
|
|
1419
|
+
};
|
|
1420
|
+
readonly constraints: {
|
|
1421
|
+
readonly added: number;
|
|
1422
|
+
readonly dropped: number;
|
|
1423
|
+
readonly altered: number;
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
interface SchemaDiff {
|
|
1427
|
+
readonly changes: readonly SchemaChange[];
|
|
1428
|
+
readonly hasDestructive: boolean;
|
|
1429
|
+
readonly summary: DiffSummary;
|
|
1430
|
+
}
|
|
1431
|
+
interface CompareSchemataOptions {
|
|
1432
|
+
/**
|
|
1433
|
+
* Database naming convention.
|
|
1434
|
+
* When set, schema model names (camelCase) are converted to DB format
|
|
1435
|
+
* (e.g. snake_case) before comparison with the introspected model.
|
|
1436
|
+
*/
|
|
1437
|
+
dbCasing?: DbCasing;
|
|
1438
|
+
/** Dialect capabilities — comparisons for unsupported features will be skipped */
|
|
1439
|
+
readonly dialectCapabilities?: DialectCapabilities;
|
|
1440
|
+
/**
|
|
1441
|
+
* When `true`, extensions present in the live DB but absent from the model
|
|
1442
|
+
* schema are silently ignored — no `drop_extension` change is emitted for them.
|
|
1443
|
+
* Only extensions explicitly declared in the model are managed (created if missing).
|
|
1444
|
+
*
|
|
1445
|
+
* Use this when the database image pre-installs extensions that the application
|
|
1446
|
+
* schema does not own (e.g. pgvector, pg_search bundled in a custom Postgres image).
|
|
1447
|
+
* Default: `false` (full-sync behaviour — unmanaged DB extensions produce a
|
|
1448
|
+
* `drop_extension` entry).
|
|
1449
|
+
*/
|
|
1450
|
+
readonly ignoreUnmanagedExtensions?: boolean;
|
|
1451
|
+
/**
|
|
1452
|
+
* Strict compile-only mode for callers that require convergence guarantees.
|
|
1453
|
+
*
|
|
1454
|
+
* `compareSchemata()` is intentionally pure and cannot ask PostgreSQL to
|
|
1455
|
+
* canonicalise raw-SQL expression surfaces. By default it keeps the historic
|
|
1456
|
+
* best-effort raw string comparison for CHECK expressions, partial-index
|
|
1457
|
+
* predicates, and index expressions. Set this flag to throw when either model
|
|
1458
|
+
* contains one of those surfaces so a caller cannot accidentally rely on a
|
|
1459
|
+
* compile-only diff for a convergence-sensitive check.
|
|
1460
|
+
*
|
|
1461
|
+
* Live PostgreSQL callers should use `comparePgsqlDatabaseSchema()`, which
|
|
1462
|
+
* canonicalises CHECK constraint expressions before calling this function.
|
|
1463
|
+
* Partial-index predicates and index expressions are not canonicalised by the
|
|
1464
|
+
* live helper and are rejected there when this strict flag is set.
|
|
1465
|
+
*/
|
|
1466
|
+
readonly requireExpressionCanonicalization?: boolean;
|
|
1467
|
+
}
|
|
1468
|
+
declare class ExpressionCanonicalizationUnavailableError extends Error {
|
|
1469
|
+
readonly surfaces: readonly string[];
|
|
1470
|
+
constructor(surfaces: readonly string[]);
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* Compare two ModelIRs and produce a structured diff.
|
|
1474
|
+
*
|
|
1475
|
+
* @param schema - The desired schema (from definition)
|
|
1476
|
+
* @param db - The current database state (from introspection)
|
|
1477
|
+
* @param options - Optional comparison settings (e.g. dbCasing)
|
|
1478
|
+
* @returns SchemaDiff with all changes needed to bring DB in sync with schema
|
|
1479
|
+
*/
|
|
1480
|
+
declare function compareSchemata(schema: ModelIR, db: ModelIR, options?: CompareSchemataOptions): SchemaDiff;
|
|
1481
|
+
|
|
1482
|
+
interface ComparePgsqlDatabaseSchemaOptions extends CompareSchemataOptions, SchemaScopeOptions {
|
|
1483
|
+
/**
|
|
1484
|
+
* Whether to canonicalise PostgreSQL CHECK constraint expressions before
|
|
1485
|
+
* comparing. Defaults to `true`. Set to `false` only for compatibility with
|
|
1486
|
+
* legacy raw-string live diffs.
|
|
1487
|
+
*
|
|
1488
|
+
* Live canonicalisation creates temporary scratch tables and missing desired
|
|
1489
|
+
* enum types inside an adapter scratch scope whose successful cleanup is
|
|
1490
|
+
* rollback. The database role needs permission to create temporary tables,
|
|
1491
|
+
* and enum-dependent checks may need permission to create the pending enum
|
|
1492
|
+
* type. If PostgreSQL refuses that scratch DDL, non-strict mode warns and
|
|
1493
|
+
* falls back to best-effort raw string comparison for the affected CHECK
|
|
1494
|
+
* constraints.
|
|
1495
|
+
*/
|
|
1496
|
+
readonly canonicalizeExpressions?: boolean;
|
|
1497
|
+
/**
|
|
1498
|
+
* Receives live CHECK canonicalisation warnings. Defaults to console.warn.
|
|
1932
1499
|
*/
|
|
1500
|
+
readonly onWarning?: (message: string) => void;
|
|
1501
|
+
/**
|
|
1502
|
+
* Diff that the caller just applied before this live re-diff. Used only when
|
|
1503
|
+
* CHECK expressions are compared by raw text to fail loudly if the exact same
|
|
1504
|
+
* expression-surface drift appears again after re-introspection.
|
|
1505
|
+
*/
|
|
1506
|
+
readonly previouslyAppliedDiff?: SchemaDiff;
|
|
1507
|
+
}
|
|
1508
|
+
declare class NonConvergentSchemaDiffError extends Error {
|
|
1509
|
+
readonly table: string;
|
|
1510
|
+
readonly constraint: string;
|
|
1511
|
+
readonly desiredExpression: string;
|
|
1512
|
+
readonly databaseExpression: string;
|
|
1513
|
+
constructor(table: string, constraint: string, desiredExpression: string, databaseExpression: string);
|
|
1514
|
+
}
|
|
1515
|
+
/** An enum value this diff adds, reported as a candidate cause — never asserted. */
|
|
1516
|
+
interface AddedEnumValue {
|
|
1517
|
+
readonly enumName: string;
|
|
1518
|
+
readonly value: string;
|
|
1519
|
+
}
|
|
1520
|
+
declare class CheckConstraintNewEnumValueError extends Error {
|
|
1521
|
+
readonly table: string;
|
|
1522
|
+
readonly constraint: string;
|
|
1523
|
+
readonly addedEnumValues: readonly AddedEnumValue[];
|
|
1524
|
+
constructor(table: string, constraint: string, addedEnumValues: readonly AddedEnumValue[]);
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Live PostgreSQL schema diff: introspect, canonicalise desired CHECK
|
|
1528
|
+
* constraint expressions through PostgreSQL, then call the pure synchronous
|
|
1529
|
+
* schema comparator.
|
|
1530
|
+
*
|
|
1531
|
+
* If CHECK canonicalisation falls back while the same diff adds a plausibly
|
|
1532
|
+
* referenced enum value, the diff is refused. dbsp currently applies each
|
|
1533
|
+
* migration in one transaction, and PostgreSQL forbids using a newly added enum
|
|
1534
|
+
* value in that same transaction; emitting the CHECK would produce a migration
|
|
1535
|
+
* that cannot run. Apply the enum addition by itself first, then add or update
|
|
1536
|
+
* the CHECK constraint in a later migration.
|
|
1537
|
+
*
|
|
1538
|
+
* Partial-index predicates and index expressions are intentionally not
|
|
1539
|
+
* canonicalised here; non-strict diffs compare them by raw string, and strict
|
|
1540
|
+
* diffs reject them.
|
|
1541
|
+
*/
|
|
1542
|
+
declare function comparePgsqlDatabaseSchema(adapter: PgsqlAdapter, desired: ModelIR, options?: ComparePgsqlDatabaseSchemaOptions): Promise<SchemaDiff>;
|
|
1543
|
+
declare function assertNoRepeatedExpressionSurfaceDrift(previouslyAppliedDiff: SchemaDiff, currentDiff: SchemaDiff, rawCheckExpressionSurfaces?: ReadonlySet<string>): void;
|
|
1544
|
+
|
|
1545
|
+
/**
|
|
1546
|
+
* Migration SQL Generator (DDL-PROV Block 1)
|
|
1547
|
+
*
|
|
1548
|
+
* Generates ordered SQL statements from a SchemaDiff.
|
|
1549
|
+
* Statements are topologically sorted: DROP constraints → DROP objects → CREATE objects → ADD constraints.
|
|
1550
|
+
*
|
|
1551
|
+
* @module migration-sql
|
|
1552
|
+
*/
|
|
1553
|
+
|
|
1554
|
+
interface MigrationSQLOptions {
|
|
1555
|
+
/**
|
|
1556
|
+
* Schema namespace (default: none — unqualified).
|
|
1557
|
+
* Required when emitted migration SQL would otherwise mix non-default
|
|
1558
|
+
* target-scoped custom types/enums with unqualified table SQL.
|
|
1559
|
+
*/
|
|
1560
|
+
readonly schemaName?: string;
|
|
1561
|
+
/** Whether to include destructive changes (drops) */
|
|
1562
|
+
readonly includeDestructive?: boolean;
|
|
1563
|
+
/** Automatically create indexes on FK columns for new tables (default: true) */
|
|
1564
|
+
readonly fkAutoIndex?: boolean;
|
|
1565
|
+
/** Dialect capabilities — migration SQL for unsupported features will be filtered */
|
|
1566
|
+
readonly dialectCapabilities?: DialectCapabilities;
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Generate ordered SQL statements from a SchemaDiff.
|
|
1570
|
+
*
|
|
1571
|
+
* Topological order:
|
|
1572
|
+
* 0. DROP FK/CHECK constraints (must drop before referenced tables)
|
|
1573
|
+
* 1. DROP indexes
|
|
1574
|
+
* 2. DROP columns
|
|
1575
|
+
* 3. DROP primary keys
|
|
1576
|
+
* 4. DROP tables, DROP ENUMs
|
|
1577
|
+
* 5. CREATE ENUMs (must exist before tables that use them)
|
|
1578
|
+
* 6. CREATE tables
|
|
1579
|
+
* 7. ADD columns
|
|
1580
|
+
* 8. ALTER columns (type, nullable, default)
|
|
1581
|
+
* 9. ADD primary keys / column UNIQUE constraints
|
|
1582
|
+
* 10. ADD FK constraints (must add after referenced tables exist)
|
|
1583
|
+
* 11. ALTER FK (drop + re-add)
|
|
1584
|
+
* 12. CREATE indexes
|
|
1585
|
+
* 13. ADD CHECK constraints
|
|
1586
|
+
* 14. ALTER ENUM ADD VALUE (must be last — has transaction visibility caveats in PG)
|
|
1587
|
+
* 15. COMMENT ON TABLE / COLUMN (very last)
|
|
1588
|
+
*/
|
|
1589
|
+
declare function generateMigrationSQL(diff: SchemaDiff, options?: MigrationSQLOptions): readonly string[];
|
|
1590
|
+
/**
|
|
1591
|
+
* Generate ordered DOWN SQL statements from a SchemaDiff.
|
|
1592
|
+
*
|
|
1593
|
+
* Reverses the topological order used in UP migrations:
|
|
1594
|
+
* phases run in descending order (11, 10, 9, ..., 0).
|
|
1595
|
+
*
|
|
1596
|
+
* Irreversible changes (drops that lose data) produce SQL WARNING comments.
|
|
1597
|
+
*/
|
|
1598
|
+
declare function generateDownSQL(diff: SchemaDiff, options?: MigrationSQLOptions): readonly string[];
|
|
1599
|
+
|
|
1600
|
+
/**
|
|
1601
|
+
* Migration File Format v2 — UP + DOWN sections.
|
|
1602
|
+
*
|
|
1603
|
+
* File format:
|
|
1604
|
+
* -- dbsp:destructive: true|false
|
|
1605
|
+
* <UP statements>;
|
|
1606
|
+
* -- DOWN
|
|
1607
|
+
* <DOWN statements>;
|
|
1608
|
+
*
|
|
1609
|
+
* The separator `-- DOWN` must be on its own line (SC-25).
|
|
1610
|
+
*
|
|
1611
|
+
* @module ddl/migration-file
|
|
1612
|
+
*/
|
|
1613
|
+
|
|
1614
|
+
/**
|
|
1615
|
+
* Result of parsing a migration file's UP/DOWN sections.
|
|
1616
|
+
*/
|
|
1617
|
+
interface ParsedMigrationFile {
|
|
1618
|
+
readonly upStatements: readonly string[];
|
|
1619
|
+
readonly downStatements: readonly string[];
|
|
1620
|
+
readonly hasDown: boolean;
|
|
1621
|
+
readonly destructive?: boolean | undefined;
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Generate a migration file content with UP and DOWN sections.
|
|
1625
|
+
*/
|
|
1626
|
+
declare function generateMigrationFile(diff: SchemaDiff, options?: MigrationSQLOptions & {
|
|
1627
|
+
name?: string;
|
|
1628
|
+
}): string;
|
|
1629
|
+
/**
|
|
1630
|
+
* Parse a migration file into UP and DOWN sections.
|
|
1631
|
+
* Separator: `^\s*-- DOWN\s*$` (strict regex, own line only — SC-25)
|
|
1632
|
+
*/
|
|
1633
|
+
declare function parseMigrationFile(content: string): ParsedMigrationFile;
|
|
1634
|
+
/**
|
|
1635
|
+
* Check if SQL statements contain destructive operations.
|
|
1636
|
+
* Destructive: DROP TABLE, DROP COLUMN, lossy ALTER COLUMN TYPE
|
|
1637
|
+
*/
|
|
1638
|
+
declare function isDestructiveDown(downStatements: readonly string[]): boolean;
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* Migration Tracker — `_dbsp_migrations` table CRUD.
|
|
1642
|
+
*
|
|
1643
|
+
* Manages the tracking table that records which migrations
|
|
1644
|
+
* have been applied to a database.
|
|
1645
|
+
*/
|
|
1646
|
+
|
|
1647
|
+
interface MigrationRecord {
|
|
1648
|
+
/** Migration filename (e.g., "0001_create_users.sql") */
|
|
1649
|
+
readonly name: string;
|
|
1650
|
+
/** SHA-256 checksum of the migration file content */
|
|
1651
|
+
readonly checksum: string;
|
|
1652
|
+
/** When the migration was applied */
|
|
1653
|
+
readonly appliedAt: Date;
|
|
1654
|
+
/** Schema version at time of this migration */
|
|
1655
|
+
readonly schemaVersion: number;
|
|
1656
|
+
/** Whether this migration contains destructive changes */
|
|
1657
|
+
readonly destructive: boolean;
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Execute a callback under an advisory lock using a dedicated client.
|
|
1661
|
+
* The lock is held for the duration of the callback.
|
|
1662
|
+
* The client is released (and lock freed) after the callback completes.
|
|
1663
|
+
*/
|
|
1664
|
+
declare function withMigrationLock<T>(pool: Pool, fn: (client: PoolClient) => Promise<T>): Promise<T>;
|
|
1665
|
+
/**
|
|
1666
|
+
* Ensure the migrations tracking table exists.
|
|
1667
|
+
* Auto-migrates existing tables that lack `schema_version`/`destructive` columns,
|
|
1668
|
+
* and backfills `schema_version` by `applied_at` order for rows still at 0.
|
|
1669
|
+
*/
|
|
1670
|
+
declare function ensureMigrationsTable(pool: Pool): Promise<void>;
|
|
1671
|
+
/**
|
|
1672
|
+
* Get all applied migrations, ordered by name.
|
|
1673
|
+
*/
|
|
1674
|
+
declare function getAppliedMigrations(pool: Pool): Promise<readonly MigrationRecord[]>;
|
|
1675
|
+
/**
|
|
1676
|
+
* Record a migration as applied.
|
|
1677
|
+
*/
|
|
1678
|
+
declare function recordMigration(pool: Pool, name: string, checksum: string, schemaVersion: number, destructive: boolean): Promise<void>;
|
|
1679
|
+
/**
|
|
1680
|
+
* Check if a specific migration has been applied.
|
|
1681
|
+
*/
|
|
1682
|
+
declare function isMigrationApplied(pool: Pool, name: string): Promise<boolean>;
|
|
1683
|
+
/**
|
|
1684
|
+
* Get the next schema version number (max + 1, or 1 if no migrations).
|
|
1685
|
+
*/
|
|
1686
|
+
declare function getNextSchemaVersion(pool: Pool): Promise<number>;
|
|
1687
|
+
/**
|
|
1688
|
+
* Remove a migration record (for rollback).
|
|
1689
|
+
*/
|
|
1690
|
+
declare function removeMigrationRecord(pool: Pool, name: string): Promise<void>;
|
|
1691
|
+
|
|
1692
|
+
/**
|
|
1693
|
+
* Type Mapping - Maps ModelIR ColumnType to PostgreSQL data types
|
|
1694
|
+
*
|
|
1695
|
+
* Supports both manual schemas and introspected schemas (preserving originalDbType).
|
|
1696
|
+
* Handles auto-increment via SERIAL/BIGSERIAL types.
|
|
1697
|
+
*
|
|
1698
|
+
* @module ddl/type-mapping
|
|
1699
|
+
*/
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* Map ColumnType to PostgreSQL data type string.
|
|
1703
|
+
*
|
|
1704
|
+
* Uses originalDbType if available (from introspection), otherwise
|
|
1705
|
+
* falls back to reasonable PostgreSQL defaults.
|
|
1706
|
+
*
|
|
1707
|
+
* @param col - Column definition from ModelIR
|
|
1708
|
+
* @returns PostgreSQL type string (e.g., 'VARCHAR(255)', 'SERIAL', 'JSONB')
|
|
1709
|
+
*/
|
|
1710
|
+
declare function mapColumnType(col: ColumnIR, targetSchema?: string): string;
|
|
1711
|
+
/**
|
|
1712
|
+
* Map OnDeleteAction to PostgreSQL syntax.
|
|
1713
|
+
*/
|
|
1714
|
+
declare function mapOnDeleteAction(action?: string): string;
|
|
1715
|
+
|
|
1716
|
+
/**
|
|
1717
|
+
* EXPLAIN Statement Compiler
|
|
1718
|
+
*
|
|
1719
|
+
* Generates PostgreSQL EXPLAIN statements with various options.
|
|
1720
|
+
* Supports:
|
|
1721
|
+
* - ANALYZE (execute and show actual run times)
|
|
1722
|
+
* - FORMAT (text, json, xml, yaml)
|
|
1723
|
+
* - VERBOSE, COSTS, BUFFERS, TIMING, SETTINGS
|
|
1724
|
+
*/
|
|
1725
|
+
|
|
1726
|
+
/**
|
|
1727
|
+
* Output format for EXPLAIN results.
|
|
1728
|
+
*/
|
|
1729
|
+
type ExplainFormat = 'text' | 'json' | 'xml' | 'yaml';
|
|
1730
|
+
/**
|
|
1731
|
+
* Options for EXPLAIN statement.
|
|
1732
|
+
*/
|
|
1733
|
+
interface ExplainOptions {
|
|
1734
|
+
/** Execute the query and show actual run times */
|
|
1735
|
+
analyze?: boolean;
|
|
1736
|
+
/** Show more detailed output */
|
|
1737
|
+
verbose?: boolean;
|
|
1738
|
+
/** Show cost estimates (default: true) */
|
|
1739
|
+
costs?: boolean;
|
|
1740
|
+
/** Show buffer usage (requires analyze) */
|
|
1741
|
+
buffers?: boolean;
|
|
1742
|
+
/** Show actual timing (requires analyze) */
|
|
1743
|
+
timing?: boolean;
|
|
1744
|
+
/** Show non-default settings */
|
|
1745
|
+
settings?: boolean;
|
|
1746
|
+
/** Output format */
|
|
1747
|
+
format?: ExplainFormat;
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Build an EXPLAIN statement wrapping a query.
|
|
1751
|
+
*
|
|
1752
|
+
* @param query - The query to explain (SelectStmt, InsertStmt, etc.)
|
|
1753
|
+
* @param options - EXPLAIN options
|
|
1754
|
+
* @returns ExplainStmt AST node
|
|
1755
|
+
*
|
|
1756
|
+
* @example
|
|
1757
|
+
* ```typescript
|
|
1758
|
+
* const selectAst = { SelectStmt: { ... } };
|
|
1759
|
+
* const explainAst = buildExplain(selectAst, { analyze: true, format: 'json' });
|
|
1760
|
+
* // Produces: EXPLAIN (ANALYZE, FORMAT JSON) SELECT ...
|
|
1761
|
+
* ```
|
|
1762
|
+
*/
|
|
1763
|
+
declare function buildExplain(query: Node, options?: ExplainOptions): Node;
|
|
1764
|
+
/**
|
|
1765
|
+
* Build EXPLAIN ANALYZE with JSON format (common pattern).
|
|
1766
|
+
*
|
|
1767
|
+
* @param query - The query to explain
|
|
1768
|
+
* @returns ExplainStmt with ANALYZE and JSON format
|
|
1769
|
+
*/
|
|
1770
|
+
declare function buildExplainAnalyzeJson(query: Node): Node;
|
|
1771
|
+
/**
|
|
1772
|
+
* Build simple EXPLAIN (plan only, no execution).
|
|
1773
|
+
*
|
|
1774
|
+
* @param query - The query to explain
|
|
1775
|
+
* @returns ExplainStmt with default options
|
|
1776
|
+
*/
|
|
1777
|
+
declare function buildExplainPlan(query: Node): Node;
|
|
1778
|
+
/**
|
|
1779
|
+
* Build verbose EXPLAIN with costs and buffers.
|
|
1780
|
+
*
|
|
1781
|
+
* @param query - The query to explain
|
|
1782
|
+
* @returns ExplainStmt with verbose options
|
|
1783
|
+
*/
|
|
1784
|
+
declare function buildExplainVerbose(query: Node): Node;
|
|
1785
|
+
/**
|
|
1786
|
+
* Parse EXPLAIN JSON output to get execution statistics.
|
|
1787
|
+
*
|
|
1788
|
+
* @param jsonOutput - The JSON string from EXPLAIN (ANALYZE, FORMAT JSON)
|
|
1789
|
+
* @returns Parsed plan with execution statistics
|
|
1790
|
+
*/
|
|
1791
|
+
declare function parseExplainJson(jsonOutput: string): ExplainPlan[];
|
|
1792
|
+
/**
|
|
1793
|
+
* Parsed EXPLAIN plan structure (simplified).
|
|
1794
|
+
*/
|
|
1795
|
+
interface ExplainPlan {
|
|
1796
|
+
Plan: {
|
|
1797
|
+
'Node Type': string;
|
|
1798
|
+
'Relation Name'?: string;
|
|
1799
|
+
Alias?: string;
|
|
1800
|
+
'Startup Cost'?: number;
|
|
1801
|
+
'Total Cost'?: number;
|
|
1802
|
+
'Plan Rows'?: number;
|
|
1803
|
+
'Plan Width'?: number;
|
|
1804
|
+
'Actual Startup Time'?: number;
|
|
1805
|
+
'Actual Total Time'?: number;
|
|
1806
|
+
'Actual Rows'?: number;
|
|
1807
|
+
'Actual Loops'?: number;
|
|
1808
|
+
Plans?: ExplainPlan['Plan'][];
|
|
1809
|
+
};
|
|
1810
|
+
'Planning Time'?: number;
|
|
1811
|
+
'Execution Time'?: number;
|
|
1812
|
+
Triggers?: unknown[];
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Extract total execution time from EXPLAIN ANALYZE JSON output.
|
|
1816
|
+
*
|
|
1817
|
+
* @param plans - Parsed EXPLAIN plans
|
|
1818
|
+
* @returns Total execution time in milliseconds
|
|
1819
|
+
*/
|
|
1820
|
+
declare function getTotalExecutionTime(plans: ExplainPlan[]): number;
|
|
1821
|
+
/**
|
|
1822
|
+
* Extract row counts from EXPLAIN ANALYZE JSON output.
|
|
1823
|
+
*
|
|
1824
|
+
* @param plans - Parsed EXPLAIN plans
|
|
1825
|
+
* @returns Object with estimated and actual row counts
|
|
1826
|
+
*/
|
|
1827
|
+
declare function getRowEstimates(plans: ExplainPlan[]): {
|
|
1828
|
+
estimated: number;
|
|
1829
|
+
actual: number;
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
interface CheckConstraintCanonicalizationWarning {
|
|
1833
|
+
readonly table: string;
|
|
1834
|
+
readonly constraint: string;
|
|
1835
|
+
readonly message: string;
|
|
1836
|
+
readonly cause: unknown;
|
|
1837
|
+
}
|
|
1838
|
+
interface CanonicalizeCheckConstraintsOptions {
|
|
1839
|
+
/** Database schema that owns the target tables and target-scoped enum types. */
|
|
1840
|
+
readonly schemaName?: string;
|
|
1841
|
+
/** Naming convention used when matching desired table names to DB table names. */
|
|
1842
|
+
readonly dbCasing?: DbCasing;
|
|
1843
|
+
/** Called when PostgreSQL CHECK canonicalisation fails and raw comparison is used. */
|
|
1844
|
+
readonly onWarning?: (warning: CheckConstraintCanonicalizationWarning) => void;
|
|
1845
|
+
/** Throw instead of falling back to raw comparison when canonicalisation fails. */
|
|
1846
|
+
readonly requireCanonicalization?: boolean;
|
|
1847
|
+
}
|
|
1848
|
+
type PgsqlCanonicalizationScope = Pick<Adapter, 'executeRaw' | 'transaction'>;
|
|
1849
|
+
declare class CheckConstraintCanonicalizationError extends Error {
|
|
1850
|
+
readonly table: string;
|
|
1851
|
+
readonly constraints: readonly string[];
|
|
1852
|
+
readonly cause: unknown;
|
|
1853
|
+
constructor(table: string, constraints: readonly string[], cause: unknown);
|
|
1854
|
+
}
|
|
1855
|
+
/**
|
|
1856
|
+
* Canonicalise PostgreSQL CHECK constraint expressions in a desired model.
|
|
1857
|
+
*
|
|
1858
|
+
* CHECK constraints are canonicalised by creating a transaction-local temp table
|
|
1859
|
+
* with the desired table's column definitions (borrowing live database type
|
|
1860
|
+
* detail for existing columns when the desired model omits it), adding the
|
|
1861
|
+
* authored CHECK constraints to that temp table, and reading PostgreSQL's
|
|
1862
|
+
* `pg_get_constraintdef()` rendering. The caller must provide a rollback-only
|
|
1863
|
+
* scratch scope; that rollback is cleanup for dbsp-created scratch objects, not
|
|
1864
|
+
* a sandbox for arbitrary session effects.
|
|
1865
|
+
* Missing desired enum types are also created inside that scratch scope before
|
|
1866
|
+
* scratch tables.
|
|
1867
|
+
* Scratch columns include only names and types; defaults, identity, uniqueness,
|
|
1868
|
+
* nullability, and other table-shape clauses are deliberately omitted.
|
|
1869
|
+
*
|
|
1870
|
+
* The returned expression is the full `CHECK (...)` clause. Bare authored
|
|
1871
|
+
* predicates are accepted and become full CHECK clauses.
|
|
1872
|
+
*
|
|
1873
|
+
* PostgreSQL does not allow an enum value added by `ALTER TYPE ... ADD VALUE`
|
|
1874
|
+
* to be used in the same transaction that added it. Because dbsp currently
|
|
1875
|
+
* emits and applies each migration in one transaction, the live diff layer
|
|
1876
|
+
* deliberately refuses CHECK constraints that fall back while the same diff adds
|
|
1877
|
+
* a plausibly referenced enum value. Splitting that into multiple transaction
|
|
1878
|
+
* phases is a separate migration-runner feature.
|
|
1879
|
+
*
|
|
1880
|
+
* This does not canonicalise partial-index predicates or index expressions, so
|
|
1881
|
+
* those surfaces may still compare by raw text in non-strict diffs.
|
|
1882
|
+
*/
|
|
1883
|
+
declare function canonicalizeCheckConstraints(adapter: PgsqlCanonicalizationScope, desired: ModelIR, dbModel: ModelIR, options?: CanonicalizeCheckConstraintsOptions): Promise<ModelIR>;
|
|
1884
|
+
|
|
1885
|
+
/**
|
|
1886
|
+
* ParadeDB Extension Wrappers
|
|
1887
|
+
*
|
|
1888
|
+
* Type-safe query builders for ParadeDB BM25 full-text search.
|
|
1889
|
+
* All functions return ExpressionRef instances that can be used in:
|
|
1890
|
+
* - SELECT: .column(score('id').as('score'))
|
|
1891
|
+
* - WHERE: .where(bm25Search('symbols', query, { name: 3.0, doc: 1.0 }))
|
|
1892
|
+
* - ORDER BY: .orderBy(score('id'), 'desc')
|
|
1893
|
+
*
|
|
1894
|
+
* @remarks
|
|
1895
|
+
* ParadeDB functions accept both named and positional arguments.
|
|
1896
|
+
* This module uses named args via namedArg() for parse(), which produces:
|
|
1897
|
+
* paradedb.parse(field => 'field_name', query_string => $1)
|
|
1898
|
+
* Named parameter syntax is supported via the NamedArgExpressionIntent (EXT-NAMED-PARAMS).
|
|
1899
|
+
*/
|
|
1900
|
+
|
|
1901
|
+
/**
|
|
1902
|
+
* BM25 relevance score for a row.
|
|
1903
|
+
*
|
|
1904
|
+
* Use in SELECT and ORDER BY to retrieve and sort by full-text relevance.
|
|
1905
|
+
* Requires a BM25 index on the table.
|
|
1906
|
+
*
|
|
1907
|
+
* @param keyField - The key field of the BM25 index (typically the primary key, e.g. 'id')
|
|
1908
|
+
* @returns ExpressionRef that compiles to: paradedb.score("keyField")
|
|
1909
|
+
*
|
|
1910
|
+
* @example
|
|
1911
|
+
* orm.select('symbols').column(score('id').as('score')).orderBy(score('id'), 'desc')
|
|
1912
|
+
* // → paradedb.score("id") AS "score"
|
|
1913
|
+
*/
|
|
1914
|
+
declare function score(keyField: string): ExpressionRef;
|
|
1915
|
+
/**
|
|
1916
|
+
* Parse a single-field BM25 query expression.
|
|
1917
|
+
*
|
|
1918
|
+
* Compiles to: paradedb.parse(field => 'field_name', query_string => $N)
|
|
1919
|
+
*
|
|
1920
|
+
* @param field - Column name to search in (must be indexed in the BM25 index)
|
|
1921
|
+
* @param query - Query string value (will be bound as a parameter)
|
|
1922
|
+
* @returns ExpressionRef for use with boost() or booleanSearch()
|
|
1923
|
+
*
|
|
1924
|
+
* @example
|
|
1925
|
+
* parse('name', 'hello world')
|
|
1926
|
+
* // → paradedb.parse(field => 'name', query_string => $1)
|
|
1927
|
+
*/
|
|
1928
|
+
declare function parse(field: string, query: ExpressionRef | unknown): ExpressionRef;
|
|
1929
|
+
/**
|
|
1930
|
+
* Apply a boost multiplier to a BM25 sub-expression.
|
|
1931
|
+
*
|
|
1932
|
+
* Compiles to: paradedb.boost(factor, expr)
|
|
1933
|
+
*
|
|
1934
|
+
* @param factor - Boost multiplier (e.g. 3.0 for 3x weight)
|
|
1935
|
+
* @param expr - Expression to boost (typically a parse() call)
|
|
1936
|
+
* @returns ExpressionRef for use with booleanSearch()
|
|
1937
|
+
*
|
|
1938
|
+
* @example
|
|
1939
|
+
* boost(3.0, parse('name', 'hello'))
|
|
1940
|
+
* // → paradedb.boost(3.0, paradedb.parse('name', $1))
|
|
1941
|
+
*/
|
|
1942
|
+
declare function boost(factor: number, expr: ExpressionRef): ExpressionRef;
|
|
1943
|
+
/**
|
|
1944
|
+
* Combine multiple BM25 sub-expressions with boolean OR logic.
|
|
1945
|
+
*
|
|
1946
|
+
* Compiles to: paradedb.boolean(expr1, expr2, ...)
|
|
1947
|
+
*
|
|
1948
|
+
* @param exprs - One or more sub-expressions (typically boost() calls)
|
|
1949
|
+
* @returns ExpressionRef for use on the right side of the @@@ operator
|
|
1950
|
+
*
|
|
1951
|
+
* @example
|
|
1952
|
+
* booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
|
|
1953
|
+
* // → paradedb.boolean(paradedb.boost(3.0, ...), paradedb.boost(1.0, ...))
|
|
1954
|
+
*/
|
|
1955
|
+
/**
|
|
1956
|
+
* Combine multiple BM25 sub-expressions with boolean OR logic.
|
|
1957
|
+
*
|
|
1958
|
+
* Compiles to: paradedb.boolean(should => ARRAY[expr1, expr2, ...])
|
|
1959
|
+
*
|
|
1960
|
+
* @param exprs - One or more sub-expressions (typically boost() calls)
|
|
1961
|
+
* @returns ExpressionRef for use on the right side of the @@@ operator
|
|
1962
|
+
*
|
|
1963
|
+
* @example
|
|
1964
|
+
* booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
|
|
1965
|
+
* // → paradedb.boolean(should => ARRAY[paradedb.boost(3.0, ...), paradedb.boost(1.0, ...)])
|
|
1966
|
+
*/
|
|
1967
|
+
declare function booleanSearch(exprs: ExpressionRef[]): ExpressionRef;
|
|
1968
|
+
/**
|
|
1969
|
+
* Full BM25 multi-field search with per-field boost weights.
|
|
1970
|
+
*
|
|
1971
|
+
* Produces: table @@@ paradedb.boolean(boost1, boost2, ...)
|
|
1972
|
+
*
|
|
1973
|
+
* Each field in `fieldBoosts` generates a `paradedb.boost(weight, paradedb.parse(field, $N))`
|
|
1974
|
+
* sub-expression. The same query string is used for all fields (single parameter binding).
|
|
1975
|
+
*
|
|
1976
|
+
* @param table - Table alias for the left side of the @@@ operator
|
|
1977
|
+
* @param query - Query string (bound as a single $N parameter, shared across all fields)
|
|
1978
|
+
* @param fieldBoosts - Map of column name → boost weight
|
|
1979
|
+
* @returns ExpressionRef for use in .where()
|
|
1980
|
+
*
|
|
1981
|
+
* @example
|
|
1982
|
+
* bm25Search('s', searchTerm, {
|
|
1983
|
+
* name_searchable: 3.0,
|
|
1984
|
+
* name: 1.0,
|
|
1985
|
+
* signature: 1.5,
|
|
1986
|
+
* doc_searchable: 1.0,
|
|
1987
|
+
* })
|
|
1988
|
+
* // → s @@@ paradedb.boolean(
|
|
1989
|
+
* // paradedb.boost(3.0, paradedb.parse('name_searchable', $1)),
|
|
1990
|
+
* // paradedb.boost(1.0, paradedb.parse('name', $1)),
|
|
1991
|
+
* // paradedb.boost(1.5, paradedb.parse('signature', $1)),
|
|
1992
|
+
* // paradedb.boost(1.0, paradedb.parse('doc_searchable', $1))
|
|
1993
|
+
* // )
|
|
1994
|
+
*
|
|
1995
|
+
* @remarks
|
|
1996
|
+
* The query parameter is shared: all parse() calls reference the same $N slot.
|
|
1997
|
+
* If you need different query strings per field, compose parse()/boost()/booleanSearch() manually.
|
|
1998
|
+
*
|
|
1999
|
+
* @remarks
|
|
2000
|
+
* ParadeDB's boolean() function accepts both positional args and the named
|
|
2001
|
+
* `should => ARRAY[...]` syntax. This wrapper uses positional args.
|
|
2002
|
+
* Named parameter syntax is deferred to EXT-NAMED-PARAMS.
|
|
2003
|
+
*/
|
|
2004
|
+
declare function bm25Search(table: string, query: unknown, fieldBoosts: Record<string, number>): ExpressionRef;
|
|
2005
|
+
|
|
2006
|
+
/**
|
|
2007
|
+
* PostgreSQL built-in function helpers.
|
|
2008
|
+
*
|
|
2009
|
+
* Thin wrappers around core expression primitives for common PostgreSQL functions.
|
|
2010
|
+
* Same pattern as pgvector.ts and paradedb.ts.
|
|
2011
|
+
*/
|
|
2012
|
+
|
|
2013
|
+
/**
|
|
2014
|
+
* Generate a series of values: generate_series(start, stop[, step])
|
|
2015
|
+
*
|
|
2016
|
+
* Returns a set of values from start to stop (inclusive), with an optional step.
|
|
2017
|
+
* Commonly used with CTE for batch operations.
|
|
2018
|
+
*
|
|
2019
|
+
* @example generateSeries(1, 100) → generate_series(1, 100)
|
|
2020
|
+
* @example generateSeries(0, 50, 5) → generate_series(0, 50, 5)
|
|
2021
|
+
*/
|
|
2022
|
+
declare function generateSeries(start: number, stop: number, step?: number): ExpressionRef;
|
|
2023
|
+
/**
|
|
2024
|
+
* Get next value from a sequence: nextval('sequence_name')
|
|
2025
|
+
*
|
|
2026
|
+
* @example nextval('order_id_seq') → nextval('order_id_seq')
|
|
2027
|
+
*/
|
|
2028
|
+
declare function nextval(sequenceName: string): ExpressionRef;
|
|
2029
|
+
|
|
2030
|
+
/**
|
|
2031
|
+
* pgvector Extension Wrappers
|
|
2032
|
+
*
|
|
2033
|
+
* Type-safe query builders for pgvector distance operators.
|
|
2034
|
+
* All functions return ExpressionRef instances that can be used in:
|
|
2035
|
+
* - SELECT: .column(cosineDistance('vector', qv).as('score'))
|
|
2036
|
+
* - WHERE: .where(cosineDistance('vector', qv).gte(0.5))
|
|
2037
|
+
* - ORDER BY: .orderBy(rawDistance('vector', qv), 'asc')
|
|
2038
|
+
*/
|
|
2039
|
+
|
|
2040
|
+
/**
|
|
2041
|
+
* Cosine similarity: 1 - (col <=> vector)
|
|
2042
|
+
*
|
|
2043
|
+
* Score in [0, 1], higher = more similar.
|
|
2044
|
+
* Use in SELECT to get a similarity score.
|
|
2045
|
+
*
|
|
2046
|
+
* @example
|
|
2047
|
+
* orm.select('embeddings').column(cosineDistance('vector', qv).as('score'))
|
|
2048
|
+
*/
|
|
2049
|
+
declare function cosineDistance(column: string, vector: number[]): ExpressionRef;
|
|
2050
|
+
/**
|
|
2051
|
+
* Raw cosine distance: col <=> vector
|
|
2052
|
+
*
|
|
2053
|
+
* Lower = closer. Index-friendly — use in ORDER BY for ANN search.
|
|
2054
|
+
* Do NOT use in SELECT as a similarity score (lower = closer is counterintuitive).
|
|
2055
|
+
*
|
|
2056
|
+
* @example
|
|
2057
|
+
* orm.select('embeddings').orderBy(rawDistance('vector', qv), 'asc')
|
|
2058
|
+
*/
|
|
2059
|
+
declare function rawDistance(column: string, vector: number[]): ExpressionRef;
|
|
2060
|
+
/**
|
|
2061
|
+
* L2 (Euclidean) distance: col <-> vector
|
|
2062
|
+
*
|
|
2063
|
+
* @example
|
|
2064
|
+
* orm.select('embeddings').orderBy(l2Distance('vector', qv), 'asc')
|
|
2065
|
+
*/
|
|
2066
|
+
declare function l2Distance(column: string, vector: number[]): ExpressionRef;
|
|
2067
|
+
/**
|
|
2068
|
+
* Inner product distance: col <#> vector (negative inner product)
|
|
2069
|
+
*
|
|
2070
|
+
* For maximum inner product search: ORDER BY innerProduct('vector', qv) ASC.
|
|
2071
|
+
*
|
|
2072
|
+
* @example
|
|
2073
|
+
* orm.select('embeddings').orderBy(innerProduct('vector', qv), 'asc')
|
|
2074
|
+
*/
|
|
2075
|
+
declare function innerProduct(column: string, vector: number[]): ExpressionRef;
|
|
2076
|
+
/**
|
|
2077
|
+
* Get the number of dimensions of a vector column: vector_dims(col)
|
|
2078
|
+
*
|
|
2079
|
+
* Returns an integer — the dimension count of the stored vector.
|
|
2080
|
+
* Useful for sanity-checking that embeddings match the expected model dimension.
|
|
2081
|
+
*
|
|
2082
|
+
* @example
|
|
2083
|
+
* orm.from(embeddings).columns([vectorDims('vector').as('dim')]).first()
|
|
2084
|
+
* // → SELECT vector_dims("t0"."vector") AS "dim" FROM "embeddings" AS "t0"
|
|
2085
|
+
*/
|
|
2086
|
+
declare function vectorDims(column: string): ExpressionRef;
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Mutation Compiler
|
|
2090
|
+
*
|
|
2091
|
+
* Compiles INSERT, UPDATE, and DELETE statements from plan decisions.
|
|
2092
|
+
* Supports:
|
|
2093
|
+
* - INSERT with values/from subquery
|
|
2094
|
+
* - INSERT with RETURNING
|
|
2095
|
+
* - UPDATE with SET and WHERE
|
|
2096
|
+
* - DELETE with WHERE
|
|
2097
|
+
* - RETURNING clause for all mutations
|
|
2098
|
+
*/
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* Configuration for INSERT compilation
|
|
2102
|
+
*/
|
|
2103
|
+
interface InsertConfig {
|
|
2104
|
+
/** Table to insert into */
|
|
2105
|
+
table: string;
|
|
2106
|
+
/** Columns to insert */
|
|
2107
|
+
columns: string[];
|
|
2108
|
+
/** Values for each column (array of rows) */
|
|
2109
|
+
values: unknown[][];
|
|
2110
|
+
/** Columns to return (RETURNING clause) */
|
|
2111
|
+
returning?: string[];
|
|
2112
|
+
/** Alias-aware RETURNING projection items */
|
|
2113
|
+
returningItems?: readonly MutationReturningItem[];
|
|
2114
|
+
/** Subquery for INSERT ... SELECT */
|
|
2115
|
+
selectQuery?: Node;
|
|
2116
|
+
/** Column database types for type-cast emission (e.g. range types) */
|
|
2117
|
+
columnTypes?: Record<string, string>;
|
|
2118
|
+
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Configuration for UPDATE compilation
|
|
2121
|
+
*/
|
|
2122
|
+
interface UpdateConfig {
|
|
2123
|
+
/** Table to update */
|
|
2124
|
+
table: string;
|
|
2125
|
+
/** Column-value pairs to set */
|
|
2126
|
+
set: {
|
|
2127
|
+
column: string;
|
|
2128
|
+
value: unknown;
|
|
2129
|
+
}[];
|
|
2130
|
+
/** WHERE conditions */
|
|
2131
|
+
where?: Decision[];
|
|
2132
|
+
/** Columns to return (RETURNING clause) */
|
|
2133
|
+
returning?: string[];
|
|
2134
|
+
/** Alias-aware RETURNING projection items */
|
|
2135
|
+
returningItems?: readonly MutationReturningItem[];
|
|
2136
|
+
/** Column database types for type-cast emission (e.g. range types) */
|
|
2137
|
+
columnTypes?: Record<string, string>;
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Configuration for DELETE compilation
|
|
2141
|
+
*/
|
|
2142
|
+
interface DeleteConfig {
|
|
2143
|
+
/** Table to delete from */
|
|
2144
|
+
table: string;
|
|
2145
|
+
/** WHERE conditions */
|
|
2146
|
+
where?: Decision[];
|
|
2147
|
+
/** Columns to return (RETURNING clause) */
|
|
2148
|
+
returning?: string[];
|
|
2149
|
+
/** Alias-aware RETURNING projection items */
|
|
2150
|
+
returningItems?: readonly MutationReturningItem[];
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2153
|
+
* Compile an INSERT statement from configuration.
|
|
2154
|
+
*/
|
|
2155
|
+
declare function compileInsert(config: InsertConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
2156
|
+
/**
|
|
2157
|
+
* Compile an UPDATE statement from configuration.
|
|
2158
|
+
*/
|
|
2159
|
+
declare function compileUpdate(config: UpdateConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
2160
|
+
declare function compileDelete(config: DeleteConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
2161
|
+
/**
|
|
2162
|
+
* Compile a mutation decision to AST.
|
|
2163
|
+
* Determines mutation type from decision.type and delegates.
|
|
2164
|
+
*/
|
|
2165
|
+
declare function compileMutation(decision: Decision, ctx: CompilerContext, state: CompilerState): Node;
|
|
2166
|
+
|
|
2167
|
+
/**
|
|
2168
|
+
* Upsert (INSERT ... ON CONFLICT) Compiler
|
|
2169
|
+
*
|
|
2170
|
+
* Compiles UPSERT statements with ON CONFLICT handling.
|
|
2171
|
+
* Supports:
|
|
2172
|
+
* - ON CONFLICT DO NOTHING
|
|
2173
|
+
* - ON CONFLICT DO UPDATE SET ...
|
|
2174
|
+
* - Conflict target (columns or constraint name)
|
|
2175
|
+
* - WHERE clause for conflict resolution
|
|
2176
|
+
*/
|
|
2177
|
+
|
|
2178
|
+
/**
|
|
2179
|
+
* Conflict resolution strategy
|
|
2180
|
+
*/
|
|
2181
|
+
type ConflictAction = 'nothing' | 'update';
|
|
2182
|
+
/**
|
|
2183
|
+
* Conflict target specification
|
|
2184
|
+
*/
|
|
2185
|
+
interface ConflictTarget {
|
|
2186
|
+
/** Column names that form the unique constraint */
|
|
2187
|
+
columns?: string[];
|
|
2188
|
+
/** Named constraint */
|
|
2189
|
+
constraint?: string;
|
|
2190
|
+
/** WHERE clause for partial index */
|
|
2191
|
+
where?: Decision[];
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Configuration for UPSERT compilation
|
|
2195
|
+
*/
|
|
2196
|
+
interface UpsertConfig {
|
|
2197
|
+
/** Table to upsert into */
|
|
2198
|
+
table: string;
|
|
2199
|
+
/** Columns to insert */
|
|
2200
|
+
columns: string[];
|
|
2201
|
+
/** Values for each column (array of rows) */
|
|
2202
|
+
values: unknown[][];
|
|
2203
|
+
/** Conflict target (unique columns or constraint) */
|
|
2204
|
+
conflictTarget: ConflictTarget;
|
|
2205
|
+
/** What to do on conflict */
|
|
2206
|
+
conflictAction: ConflictAction;
|
|
2207
|
+
/** Columns to update on conflict (for 'update' action) */
|
|
2208
|
+
updateColumns?: string[];
|
|
2209
|
+
/** Optional WHERE clause for ON CONFLICT DO UPDATE */
|
|
2210
|
+
actionWhere?: Decision[];
|
|
2211
|
+
/** Optional direct WHERE intent for ON CONFLICT DO UPDATE */
|
|
2212
|
+
actionWhereIntent?: WhereIntent;
|
|
2213
|
+
/** Compile the direct action WHERE intent using the caller's WHERE compiler */
|
|
2214
|
+
compileActionWhere?: (where: WhereIntent, state: CompilerState) => Node;
|
|
2215
|
+
/** Use EXCLUDED.column for update values (default: true) */
|
|
2216
|
+
useExcluded?: boolean;
|
|
2217
|
+
/** Columns to return (RETURNING clause) */
|
|
2218
|
+
returning?: string[];
|
|
2219
|
+
/** Alias-aware RETURNING projection items */
|
|
2220
|
+
returningItems?: readonly MutationReturningItem[];
|
|
2221
|
+
/** Optional column type hints for unnest casting (schema-driven) */
|
|
2222
|
+
columnTypes?: Record<string, string>;
|
|
1933
2223
|
/**
|
|
1934
|
-
*
|
|
2224
|
+
* Raw SQL expressions for specific update columns.
|
|
2225
|
+
* These are injected verbatim into the ON CONFLICT DO UPDATE SET clause.
|
|
2226
|
+
* Keys are logical column names (before naming plugin), values are raw SQL fragments.
|
|
1935
2227
|
*
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
2228
|
+
* @warning SECURITY: fragments are inserted without parameterization.
|
|
2229
|
+
* Only use with hardcoded expressions. Never with user input.
|
|
1938
2230
|
*
|
|
1939
|
-
* @
|
|
1940
|
-
* @param schema - Schema name (defaults to adapter schema or 'public')
|
|
1941
|
-
*/
|
|
1942
|
-
storageSize(table: string, schema?: string): Promise<number>;
|
|
1943
|
-
/**
|
|
1944
|
-
* Generate SQL for TRUNCATE TABLE.
|
|
1945
|
-
* Implements TableDDLGeneratorAdapter.generateTruncate.
|
|
1946
|
-
*/
|
|
1947
|
-
generateTruncate(table: string, schema?: string, options?: TruncateOptions): string;
|
|
1948
|
-
/**
|
|
1949
|
-
* Generate SQL for VACUUM.
|
|
1950
|
-
* Implements TableDDLGeneratorAdapter.generateVacuum.
|
|
1951
|
-
*/
|
|
1952
|
-
generateVacuum(table: string, schema?: string, options?: VacuumOptions): string;
|
|
1953
|
-
/**
|
|
1954
|
-
* Generate SQL for ALTER TABLE ... ALTER COLUMN.
|
|
1955
|
-
* Implements TableDDLGeneratorAdapter.generateAlterColumn.
|
|
1956
|
-
*/
|
|
1957
|
-
generateAlterColumn(table: string, column: string, options: AlterColumnOptions, schema?: string): string;
|
|
1958
|
-
/**
|
|
1959
|
-
* Generate SQL for CREATE INDEX.
|
|
1960
|
-
* Implements TableDDLGeneratorAdapter.generateCreateIndex.
|
|
1961
|
-
*/
|
|
1962
|
-
generateCreateIndex(table: string, options: CreateIndexOptions, schema?: string): string;
|
|
1963
|
-
/**
|
|
1964
|
-
* Generate SQL for DROP INDEX.
|
|
1965
|
-
* Implements TableDDLGeneratorAdapter.generateDropIndex.
|
|
1966
|
-
*/
|
|
1967
|
-
generateDropIndex(name: string, options?: DropIndexOptions): string;
|
|
1968
|
-
/**
|
|
1969
|
-
* Validate an identifier (table name, column name, schema name).
|
|
2231
|
+
* @example { last_parsed: 'now()', count: 'excluded.count + 1' }
|
|
1970
2232
|
*/
|
|
1971
|
-
|
|
2233
|
+
updateExpressions?: Record<string, string>;
|
|
1972
2234
|
}
|
|
1973
2235
|
/**
|
|
1974
|
-
*
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
*
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
*
|
|
1983
|
-
*
|
|
2236
|
+
* Build ON CONFLICT clause for INSERT statement.
|
|
2237
|
+
*/
|
|
2238
|
+
declare function buildOnConflictClause(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): OnConflictClause;
|
|
2239
|
+
/**
|
|
2240
|
+
* Compile a complete UPSERT statement.
|
|
2241
|
+
*/
|
|
2242
|
+
declare function compileUpsert(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): Node;
|
|
2243
|
+
/**
|
|
2244
|
+
* Build EXCLUDED.column reference.
|
|
2245
|
+
* EXCLUDED is a special table alias in ON CONFLICT ... DO UPDATE
|
|
2246
|
+
* that refers to the row that would have been inserted.
|
|
2247
|
+
*/
|
|
2248
|
+
declare function excludedRef(column: string, naming: {
|
|
2249
|
+
toDatabase: (s: string) => string;
|
|
2250
|
+
}): Node;
|
|
2251
|
+
/**
|
|
2252
|
+
* Build conditional update using COALESCE.
|
|
1984
2253
|
*
|
|
1985
|
-
*
|
|
1986
|
-
*
|
|
2254
|
+
* Produces: COALESCE(EXCLUDED.col, table.col)
|
|
2255
|
+
* This keeps existing value if new value is NULL.
|
|
2256
|
+
*/
|
|
2257
|
+
declare function conditionalUpdate(column: string, table: string, ctx: CompilerContext): Node;
|
|
2258
|
+
|
|
2259
|
+
/**
|
|
2260
|
+
* @module naming
|
|
2261
|
+
* Utilities for resolving database names to logical model names.
|
|
1987
2262
|
*
|
|
1988
|
-
*
|
|
1989
|
-
*
|
|
1990
|
-
*
|
|
2263
|
+
* The ModelIR.getTable() method expects logical (camelCase) names,
|
|
2264
|
+
* but the adapter often works with database (snake_case) names.
|
|
2265
|
+
* This module bridges that gap.
|
|
1991
2266
|
*/
|
|
1992
|
-
|
|
2267
|
+
|
|
1993
2268
|
/**
|
|
1994
|
-
*
|
|
2269
|
+
* Resolve a database table name to the corresponding logical model name.
|
|
1995
2270
|
*
|
|
1996
|
-
*
|
|
1997
|
-
*
|
|
2271
|
+
* Converts the DB name using the naming convention, then looks it up in the model.
|
|
2272
|
+
* Falls back to exact match if conversion doesn't find a match.
|
|
2273
|
+
*
|
|
2274
|
+
* @param model - The model IR to search in
|
|
2275
|
+
* @param dbName - Database table name (e.g. "post_comments")
|
|
2276
|
+
* @param convention - Naming convention used by the adapter
|
|
2277
|
+
* @returns The logical table name if found, undefined otherwise
|
|
1998
2278
|
*
|
|
1999
2279
|
* @example
|
|
2000
2280
|
* ```typescript
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2003
|
-
*
|
|
2004
|
-
*
|
|
2005
|
-
* const orm = createOrm({ model, adapter });
|
|
2006
|
-
* const dump = await orm.select('users').dump();
|
|
2007
|
-
* console.log(dump.sql);
|
|
2281
|
+
* // With camelCase convention:
|
|
2282
|
+
* resolveLogicalName(model, "post_comments", "camelCase") // → "postComments"
|
|
2283
|
+
* resolveLogicalName(model, "posts", "camelCase") // → "posts"
|
|
2284
|
+
* resolveLogicalName(model, "unknown", "camelCase") // → undefined
|
|
2008
2285
|
* ```
|
|
2009
2286
|
*/
|
|
2010
|
-
declare function
|
|
2287
|
+
declare function resolveLogicalName(model: ModelIR, dbName: string, casing: DbCasing): string | undefined;
|
|
2288
|
+
|
|
2289
|
+
/**
|
|
2290
|
+
* ParamRef validation and helpers for PostgreSQL AST
|
|
2291
|
+
*
|
|
2292
|
+
* ParamRef nodes represent parameterized query placeholders ($1, $2, etc.)
|
|
2293
|
+
* This module provides validation and creation helpers for safe AST construction.
|
|
2294
|
+
*/
|
|
2295
|
+
|
|
2296
|
+
/**
|
|
2297
|
+
* Validation result for ParamRef nodes
|
|
2298
|
+
*/
|
|
2299
|
+
interface ParamRefValidationResult {
|
|
2300
|
+
valid: boolean;
|
|
2301
|
+
errors: string[];
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Validates a ParamRef node
|
|
2305
|
+
*
|
|
2306
|
+
* Rules:
|
|
2307
|
+
* - `number` must be a positive integer (1-based indexing)
|
|
2308
|
+
* - `number` must not exceed reasonable bounds (e.g., 65535)
|
|
2309
|
+
*/
|
|
2310
|
+
declare function validateParamRef(paramRef: ParamRef): ParamRefValidationResult;
|
|
2311
|
+
/**
|
|
2312
|
+
* Creates a validated ParamRef node
|
|
2313
|
+
* @throws Error if validation fails
|
|
2314
|
+
*/
|
|
2315
|
+
declare function createParamRef(number: number, location?: number): Node;
|
|
2316
|
+
/**
|
|
2317
|
+
* Creates a TypeCast node wrapping a ParamRef
|
|
2318
|
+
* Example: $1::integer, $2::text[]
|
|
2319
|
+
*/
|
|
2320
|
+
declare function createTypeCastParamRef(paramNumber: number, typeName: string, isArray?: boolean, location?: number): Node;
|
|
2321
|
+
/**
|
|
2322
|
+
* Creates an A_Expr node for equality comparison with ParamRef
|
|
2323
|
+
* Example: col = $1
|
|
2324
|
+
*/
|
|
2325
|
+
declare function createEqualityExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
|
|
2326
|
+
/**
|
|
2327
|
+
* Creates a FuncCall node for ANY() with ParamRef
|
|
2328
|
+
* Example: col = ANY($1) for array parameter matching
|
|
2329
|
+
*/
|
|
2330
|
+
declare function createAnyExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
|
|
2331
|
+
/**
|
|
2332
|
+
* Collects all ParamRef nodes from an AST, validating each
|
|
2333
|
+
* Returns validation results for all found ParamRefs
|
|
2334
|
+
*/
|
|
2335
|
+
declare function collectAndValidateParamRefs(node: unknown): {
|
|
2336
|
+
paramRefs: Array<{
|
|
2337
|
+
paramRef: ParamRef;
|
|
2338
|
+
path: string;
|
|
2339
|
+
}>;
|
|
2340
|
+
validationResults: ParamRefValidationResult[];
|
|
2341
|
+
allValid: boolean;
|
|
2342
|
+
};
|
|
2011
2343
|
|
|
2012
2344
|
/**
|
|
2013
2345
|
* Redact sensitive values in a query dump's `params` array before logging.
|
|
@@ -2319,5 +2651,15 @@ declare function validateIdentifiers(identifiers: Record<string, 'table' | 'colu
|
|
|
2319
2651
|
* NOT for use in SQL - use validateIdentifier + AST helpers for that.
|
|
2320
2652
|
*/
|
|
2321
2653
|
declare function sanitizeForDisplay(value: string): string;
|
|
2654
|
+
/**
|
|
2655
|
+
* Validate a raw SQL expression used in DDL contexts (defaults, policy USING/CHECK).
|
|
2656
|
+
* Rejects injection vectors: semicolons, line-comment markers, block-comment markers.
|
|
2657
|
+
*
|
|
2658
|
+
* @security Called before any ModelIR-sourced string is interpolated into DDL.
|
|
2659
|
+
* @param sql The raw SQL expression string to validate.
|
|
2660
|
+
* @param context Human-readable context label for the error message.
|
|
2661
|
+
* @throws Error if the expression contains forbidden characters.
|
|
2662
|
+
*/
|
|
2663
|
+
declare function validateSqlExpression(sql: string, context: string): void;
|
|
2322
2664
|
|
|
2323
|
-
export { type BatchValuesJoinDecision, CamelCaseNamingPlugin, type ChangeKind, type CompareSchemataOptions, type CompiledResult, type CompilerContext, type CompilerOptions, type CompilerState, type ConflictAction, type ConflictTarget, type CursorHoldOption, type CursorOptions, type CursorScrollOption, DEFAULT_PK_COLUMN, DEFAULT_REDACTION_PATTERNS, type Decision, type DeleteConfig, type DetectedHierarchy, type DiffSummary, type ExplainFormat, type ExplainOptions, type ExplainPlan, type ExpressionHandler, type FetchDirection, type FetchOptions, type FkColumnDerivation, type GenerateDDLOptions, IdentityNamingPlugin, type IncludeHandler, type IncludeResult, type InsertConfig, type IntrospectedModelIR, type IntrospectionOptions, InvalidIdentifierError, type JoinDecision, type LeafCompileFn, type MigrationRecord, type MigrationSQLOptions, type NamingPlugin, type ParamRefValidationResult, type ParsedMigrationFile, PgsqlAdapter, type PgsqlAdapterOptions, PlanCompiler, type PlanDecision, type PrecompiledJoinDecision, type RedactionConfig, type RedactionPattern, type SchemaChange, type SchemaDiff, type SetOperationResult, type SimplifiedPlanReport, type StreamConfig, type UpdateConfig, type UpsertConfig, type WhereDispatcher, type WhereHandler,
|
|
2665
|
+
export { type AddedEnumValue, type BatchValuesJoinDecision, CamelCaseNamingPlugin, type CanonicalizeCheckConstraintsOptions, type ChangeKind, CheckConstraintCanonicalizationError, type CheckConstraintCanonicalizationWarning, CheckConstraintNewEnumValueError, type ComparePgsqlDatabaseSchemaOptions, type CompareSchemataOptions, type CompiledResult, type CompilerContext, type CompilerOptions, type CompilerState, type ConflictAction, type ConflictTarget, type CursorHoldOption, type CursorOptions, type CursorScrollOption, DEFAULT_PK_COLUMN, DEFAULT_REDACTION_PATTERNS, type Decision, type DeleteConfig, type DetectedHierarchy, type DiffSummary, type ExplainFormat, type ExplainOptions, type ExplainPlan, ExpressionCanonicalizationUnavailableError, type ExpressionHandler, type FetchDirection, type FetchOptions, type FkColumnDerivation, type GenerateDDLOptions, IdentityNamingPlugin, type IncludeHandler, type IncludeResult, type InsertConfig, type IntrospectedModelIR, type IntrospectionOptions, InvalidIdentifierError, type JoinDecision, type LeafCompileFn, type MigrationRecord, type MigrationSQLOptions, type NamingPlugin, NonConvergentSchemaDiffError, type ParamRefValidationResult, type ParsedMigrationFile, PgsqlAdapter, type PgsqlAdapterOptions, type PgsqlBorrowedClientAdapterOptions, type PgsqlPoolAdapterOptions, PgsqlRawSqlTransactionControlError, PgsqlTransactionAbortedCommitError, PgsqlTransactionAbortedError, PlanCompiler, type PlanDecision, type PrecompiledJoinDecision, type RedactionConfig, type RedactionPattern, type SchemaChange, type SchemaDiff, type SchemaScopeOptions, type SetOperationResult, type SimplifiedPlanReport, type StreamConfig, type UpdateConfig, type UpsertConfig, type WhereDispatcher, type WhereHandler, assertNoRepeatedExpressionSurfaceDrift, bm25Search, booleanSearch, boost, buildCloseCursor, buildDeclareCursor, buildExplain, buildExplainAnalyzeJson, buildExplainPlan, buildExplainVerbose, buildFetch, buildFetchAll, buildFetchFirst, buildFetchForward, buildFetchNext, buildOnConflictClause, buildStreamingStatements, camelCaseNaming, canGenerateCreateIndex, canonicalizeCheckConstraints, collectAndValidateParamRefs, comparePgsqlDatabaseSchema, compareSchemata, compileDelete, compileInsert, compileMutation, compilePlan, compileSetOperation, compileUpdate, compileUpsert, conditionalUpdate, cosineDistance, createAnyExpr, createEqualityExpr, createLeafCompileFn, createParamRef, createPgsqlAdapter, createPgsqlCompileOnlyAdapter, createTypeCastParamRef, defaultFkDerivation, ensureMigrationsTable, excludedRef, generateCreateIndex, generateCursorName, generateDDL, generateDownSQL, generateMigrationFile, generateMigrationSQL, generateSeries, getAppliedMigrations, getNamingPluginForDbCasing, getNextSchemaVersion, getRowEstimates, getTotalExecutionTime, identityNaming, innerProduct, introspect, isBatchValuesJoinDecision, isDestructiveDown, isJoinDecision, isMigrationApplied, isPrecompiledJoinDecision, isReservedKeyword, l2Distance, mapColumnType, mapOnDeleteAction, nextval, parse, parseExplainJson, parseMigrationFile, rawDistance, recordMigration, redactParams, removeMigrationRecord, resolveLogicalName, sanitizeForDisplay, score, validateIdentifier, validateIdentifiers, validateParamRef, validateQualifiedIdentifier, validateSqlExpression, vectorDims, withMigrationLock };
|