@dbsp/adapter-pgsql 1.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.
@@ -0,0 +1,2154 @@
1
+ import { ExpressionRef, IndexInfo, TruncateOptions, VacuumOptions, AlterColumnOptions, CreateIndexOptions, DropIndexOptions, ModelIR as ModelIR$1 } from '@dbsp/core';
2
+ export { normalizeSQL } from '@dbsp/core';
3
+ import * as _dbsp_types from '@dbsp/types';
4
+ import { DialectCapabilities, ModelIR, DbCasing, ColumnIR, HierarchyIR, Adapter, AdapterLogger, AdapterCapabilities, PlanReport, CompileOptions, CompiledQuery, CompileResultWithIncludes, SubqueryIncludeInfo, ExpressionIntent, InsertIntent, InsertFromIntent, UpdateIntent, BatchUpdateIntent, DeleteIntent, UpsertIntent, UpsertFromIntent, RecursivePlanReport, CteQueryIntent, SetOperationIntent, DumpMeta, Dump, AdapterStreamOptions, CompileOnlyAdapter, QueryIntent } from '@dbsp/types';
5
+ import * as _pgsql_types from '@pgsql/types';
6
+ import { Node, OnConflictClause, ParamRef } from '@pgsql/types';
7
+ import { Pool, PoolClient } from 'pg';
8
+
9
+ /**
10
+ * Default primary key column name used as convention fallback
11
+ * when schema metadata doesn't provide an explicit PK.
12
+ *
13
+ * Consumers (handlers, compiler) must NOT use this directly —
14
+ * they use `requiredColumn()` to throw on missing data.
15
+ * Only convention mappers (extractors, introspection) should reference this.
16
+ */
17
+ declare const DEFAULT_PK_COLUMN = "id";
18
+ /**
19
+ * Derive a foreign key column name from a table name and the PK column it references.
20
+ *
21
+ * Convention: `${singularTableName}_${pkColumnName}`
22
+ * e.g. (authors, id) → author_id, (categories, id) → category_id
23
+ *
24
+ * Consumers should use `deriveFkColumnName` from CompilerContext or options
25
+ * for configurable behavior.
26
+ */
27
+ type FkColumnDerivation = (tableName: string, pkColumnName: string) => string;
28
+ declare const defaultFkDerivation: FkColumnDerivation;
29
+
30
+ /**
31
+ * NamingPlugin - Identifier transformation between model and database naming conventions
32
+ *
33
+ * Inspired by Kysely's CamelCasePlugin architecture.
34
+ * The plugin transforms identifiers bidirectionally:
35
+ * - toDatabase: model name (camelCase) → database name (snake_case)
36
+ * - toModel: database name (snake_case) → model name (camelCase)
37
+ */
38
+ /**
39
+ * Interface for naming convention transformation plugins
40
+ */
41
+ interface NamingPlugin {
42
+ /**
43
+ * Transform a model identifier to database format
44
+ * Example: "createdAt" → "created_at"
45
+ */
46
+ toDatabase(identifier: string): string;
47
+ /**
48
+ * Transform a database identifier to model format
49
+ * Example: "created_at" → "createdAt"
50
+ */
51
+ toModel(identifier: string): string;
52
+ }
53
+ /**
54
+ * Identity plugin - no transformation
55
+ * Use this when model and database naming conventions match
56
+ */
57
+ declare class IdentityNamingPlugin implements NamingPlugin {
58
+ toDatabase(identifier: string): string;
59
+ toModel(identifier: string): string;
60
+ }
61
+ /**
62
+ * CamelCase ↔ snake_case transformation plugin
63
+ *
64
+ * Follows the same logic as Kysely's CamelCasePlugin:
65
+ * - Handles consecutive uppercase letters (e.g., "parseJSON" → "parse_json")
66
+ * - Handles numbers (e.g., "field1Name" → "field1_name")
67
+ * - Preserves leading underscores
68
+ */
69
+ declare class CamelCaseNamingPlugin implements NamingPlugin {
70
+ /**
71
+ * camelCase → snake_case
72
+ */
73
+ toDatabase(identifier: string): string;
74
+ /**
75
+ * snake_case → camelCase
76
+ */
77
+ toModel(identifier: string): string;
78
+ }
79
+ /**
80
+ * Singleton instances for convenience
81
+ */
82
+ declare const identityNaming: IdentityNamingPlugin;
83
+ declare const camelCaseNaming: CamelCaseNamingPlugin;
84
+ /**
85
+ * Get a naming plugin by DbCasing (intuitive semantics).
86
+ * - `'snake_case'`: DB uses snake_case → CamelCaseNamingPlugin (transforms to camelCase)
87
+ * - `'camelCase'`: DB uses camelCase → IdentityNamingPlugin (no transform)
88
+ * - `'preserve'`: No transformation → IdentityNamingPlugin
89
+ */
90
+ declare function getNamingPluginForDbCasing(casing: 'snake_case' | 'camelCase' | 'preserve'): NamingPlugin;
91
+
92
+ /**
93
+ * Simplified PlanDecision for the spike
94
+ * (In production, import from @dbsp/core)
95
+ */
96
+ interface PlanDecision {
97
+ readonly type: string;
98
+ readonly table?: string;
99
+ readonly column?: string;
100
+ readonly alias?: string;
101
+ readonly field?: string;
102
+ readonly operator?: string;
103
+ readonly value?: unknown;
104
+ readonly paramIndex?: number;
105
+ readonly direction?: 'ASC' | 'DESC';
106
+ readonly nulls?: 'FIRST' | 'LAST';
107
+ readonly joinType?: 'inner' | 'left';
108
+ readonly sourceColumn?: string;
109
+ readonly targetColumn?: string;
110
+ readonly targetTable?: string;
111
+ readonly function?: string;
112
+ readonly args?: readonly unknown[];
113
+ readonly conditions?: readonly PlanDecision[];
114
+ readonly columns?: readonly string[];
115
+ readonly values?: readonly unknown[];
116
+ readonly set?: readonly {
117
+ column: string;
118
+ value: unknown;
119
+ }[];
120
+ readonly limit?: number | {
121
+ paramIndex: number;
122
+ };
123
+ readonly offset?: number | {
124
+ paramIndex: number;
125
+ };
126
+ readonly partitionBy?: readonly string[];
127
+ readonly orderBy?: readonly {
128
+ field: string;
129
+ direction?: 'asc' | 'desc';
130
+ }[];
131
+ readonly dataType?: string;
132
+ readonly sourceTable?: string;
133
+ readonly relationName?: string;
134
+ readonly relationType?: 'belongsTo' | 'hasMany' | 'hasOne';
135
+ readonly foreignKey?: string;
136
+ readonly parentKey?: string;
137
+ readonly children?: readonly PlanDecision[];
138
+ readonly intentPath?: string;
139
+ readonly choice?: string;
140
+ readonly subquery?: {
141
+ readonly from: string;
142
+ readonly select: string;
143
+ readonly where?: PlanDecision;
144
+ readonly limit?: number;
145
+ readonly orderBy?: readonly {
146
+ field: string;
147
+ direction?: string;
148
+ }[];
149
+ };
150
+ readonly expressionType?: string;
151
+ readonly relation?: string;
152
+ readonly columnAliases?: Readonly<Record<string, string>>;
153
+ readonly traversal?: string;
154
+ readonly pkColumn?: string;
155
+ readonly fkColumn?: string;
156
+ readonly maxDepth?: number;
157
+ readonly role?: string;
158
+ readonly jsonPath?: readonly string[];
159
+ readonly jsonMode?: 'json' | 'text';
160
+ readonly selectColumn?: string;
161
+ readonly aggregate?: string;
162
+ readonly subqueryOperator?: string;
163
+ readonly filterCondition?: PlanDecision;
164
+ readonly expressionIntent?: unknown;
165
+ readonly escape?: string;
166
+ readonly include?: readonly PlanDecision[];
167
+ readonly joinRarg?: Node;
168
+ readonly joinOnNode?: Node;
169
+ readonly batchValuesParams?: readonly unknown[];
170
+ }
171
+ /**
172
+ * Any decision of type 'join'.
173
+ * Narrows `type` to the literal 'join' for safe switch exhaustion.
174
+ */
175
+ interface JoinDecision extends PlanDecision {
176
+ readonly type: 'join';
177
+ }
178
+ /**
179
+ * A 'join' decision that carries pre-compiled PostgreSQL AST nodes.
180
+ * Used by both table-mode and BatchValues-mode joins when the ON condition
181
+ * has been compiled ahead of time in adapter-compiler-select.ts.
182
+ *
183
+ * The `joinRarg` is the right-hand RangeVar/RangeFunction; `joinOnNode` is
184
+ * the A_Expr tree for the ON clause.
185
+ */
186
+ interface PrecompiledJoinDecision extends JoinDecision {
187
+ readonly joinRarg: Node;
188
+ readonly joinOnNode: Node;
189
+ }
190
+ /**
191
+ * A pre-compiled 'join' decision backed by a BatchValues unnest() source.
192
+ * `batchValuesParams` must be spliced into compiler state BEFORE other query
193
+ * parameters so that $1/$2/… ParamRefs in the RangeFunction align correctly.
194
+ */
195
+ interface BatchValuesJoinDecision extends PrecompiledJoinDecision {
196
+ readonly batchValuesParams: readonly unknown[];
197
+ }
198
+ /** Narrows a PlanDecision to JoinDecision (type === 'join'). */
199
+ declare function isJoinDecision(d: PlanDecision): d is JoinDecision;
200
+ /**
201
+ * Narrows a PlanDecision to PrecompiledJoinDecision.
202
+ * True when the join carries pre-compiled `joinRarg` + `joinOnNode` AST nodes
203
+ * (table mode or BatchValues mode).
204
+ */
205
+ declare function isPrecompiledJoinDecision(d: PlanDecision): d is PrecompiledJoinDecision;
206
+ /**
207
+ * Narrows a PlanDecision to BatchValuesJoinDecision.
208
+ * True when the join is a BatchValues unnest() join and carries pre-spliced
209
+ * parameter arrays in `batchValuesParams`.
210
+ */
211
+ declare function isBatchValuesJoinDecision(d: PlanDecision): d is BatchValuesJoinDecision;
212
+ /**
213
+ * Simplified PlanReport for the spike
214
+ */
215
+ interface SimplifiedPlanReport {
216
+ readonly rootTable: string;
217
+ readonly decisions: readonly PlanDecision[];
218
+ readonly schema?: string;
219
+ /** If true, wrap result in SELECT EXISTS(SELECT 1 ...) AS "exists" */
220
+ readonly existsWrap?: boolean;
221
+ /** Row-level lock (FOR UPDATE/SHARE/etc.) */
222
+ readonly lock?: _dbsp_types.LockIntent;
223
+ /**
224
+ * When present, the FROM clause is replaced by a pre-compiled RangeFunction node
225
+ * (e.g. unnest() AS alias) instead of the root table rangeVar.
226
+ * `batchValuesFromParams` holds the parameter arrays to splice into state first.
227
+ */
228
+ readonly batchValuesFromNode?: unknown;
229
+ readonly batchValuesFromParams?: readonly unknown[];
230
+ }
231
+ /**
232
+ * Compiled query result
233
+ */
234
+ interface CompiledResult {
235
+ readonly sql: string;
236
+ readonly parameters: readonly unknown[];
237
+ readonly ast: Node;
238
+ }
239
+ interface CompilerOptions {
240
+ readonly naming?: NamingPlugin;
241
+ readonly schema?: string;
242
+ /** Default primary key column name convention (default: 'id') */
243
+ readonly defaultPkColumnName?: string;
244
+ /** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
245
+ readonly deriveFkColumnName?: FkColumnDerivation;
246
+ /** ModelIR for type-aware parameter casting in WHERE clauses */
247
+ readonly model?: _dbsp_types.ModelIR;
248
+ }
249
+ declare class PlanCompiler {
250
+ private readonly naming;
251
+ private readonly schema;
252
+ private readonly defaultPk;
253
+ private readonly deriveFk;
254
+ private readonly model;
255
+ /** Mutable state shared with extracted condition/value compilation functions */
256
+ private state;
257
+ /** Track root table for EXISTS FK correlation */
258
+ private currentRootTable;
259
+ /** Pending JOINs registered by filter/include strategies (flushed in compileSelect) */
260
+ private pendingJoins;
261
+ /** Raw JOIN AST nodes from include handlers (e.g., LATERAL) */
262
+ private rawJoins;
263
+ /** CTE nodes from include handlers (e.g., CTE strategy) */
264
+ private pendingCtes;
265
+ /**
266
+ * Maps joined targetTable → alias for multi-hop FK resolution.
267
+ * Populated as join decisions are compiled so later hops can find
268
+ * the correct source alias (e.g., 'symbols' → 'callee').
269
+ */
270
+ private joinAliasMap;
271
+ /**
272
+ * Tracks all join aliases in use for the current query.
273
+ * Ensures no two JOINs share the same alias (DOUBLE-ALIAS prevention).
274
+ */
275
+ private usedJoinAliases;
276
+ constructor(options?: CompilerOptions);
277
+ /** Build immutable context for handler-based WHERE compilation */
278
+ private handlerCtx;
279
+ /**
280
+ * Dispatch a PlanDecision through the unified WHERE handler system.
281
+ * Bridges PlanCompiler's state to handler types, calls dispatcher, syncs back.
282
+ */
283
+ private dispatchWhere;
284
+ /**
285
+ * Recursively convert a PlanDecision (potentially with nested in+subquery)
286
+ * into a HandlerDecision suitable for the WHERE dispatcher.
287
+ *
288
+ * When a PlanDecision has operator='in'/'notIn' with a subquery object,
289
+ * mapToHandlerDecision loses the subquery because HandlerDecision has no
290
+ * `subquery` field. This method detects that pattern and converts it to the
291
+ * inSubquery/notInSubquery form that buildScalarSubquery expects.
292
+ *
293
+ * Called recursively so 2+ levels of nested IN subqueries all work.
294
+ */
295
+ private mapInSubqueryCondition;
296
+ /**
297
+ * Bridge PlanDecision to handler Decision and dispatch to include handler.
298
+ * Returns targets and optional pending joins to apply.
299
+ */
300
+ private compileIncludeViaHandler;
301
+ /**
302
+ * Compile a simplified plan report to SQL
303
+ */
304
+ compile(plan: SimplifiedPlanReport): CompiledResult;
305
+ private detectQueryType;
306
+ /** Build a HandlerCompilerContext for the given plan and optional alias override. */
307
+ private createHandlerContext;
308
+ /** Build a fresh HandlerCompilerState sharing the current parameter array. */
309
+ private createHandlerState;
310
+ /**
311
+ * Compile a SELECT-list target via expression handler.
312
+ * Wraps the node in a ResTarget and pushes it onto targetList.
313
+ */
314
+ private compileSelectTarget;
315
+ /**
316
+ * Compile an includeStrategy decision and register its results.
317
+ * Pushes targets onto targetList, raw joins / CTEs onto instance collections.
318
+ */
319
+ private compileIncludeDecision;
320
+ /**
321
+ * Fold a WHERE-family decision into an existing where expression.
322
+ * Returns the updated (or new) where node.
323
+ */
324
+ private compileWhereDecision;
325
+ /**
326
+ * Flush pendingJoins and rawJoins into the FROM clause.
327
+ * Mutates the from array in-place.
328
+ */
329
+ private flushPendingJoins;
330
+ /**
331
+ * Build the initial FROM clause array and register batch-values parameters.
332
+ * For batch-values queries, the unnest RangeFunction replaces the root rangeVar.
333
+ */
334
+ private compileFromClause;
335
+ /**
336
+ * Fold WHERE conditions from a join-strategy include decision into the
337
+ * accumulated WHERE expression. The join alias is used as currentAlias so
338
+ * column refs like `project_id` resolve against the joined table, not root.
339
+ */
340
+ private compileIncludeWhereConditions;
341
+ /**
342
+ * Apply a single join decision to the FROM clause in-place.
343
+ * Chains multiple joins by wrapping from[0] as the left-arg each time.
344
+ */
345
+ private compileJoinDecision;
346
+ /**
347
+ * Compile a single orderBy decision into a SortBy AST node.
348
+ * Supports both expression-intent and plain column references.
349
+ */
350
+ /**
351
+ * Compile a single orderBy decision into a SortBy AST node.
352
+ * Supports both expression-intent and plain column references.
353
+ * Returns undefined when neither expressionIntent nor column is present.
354
+ */
355
+ private compileOrderByDecision;
356
+ /**
357
+ * Compile a single groupBy decision into a ColumnRef AST node.
358
+ * Supports dotted 'relation.column' notation for joined tables.
359
+ */
360
+ private compileGroupByDecision;
361
+ /**
362
+ * Assemble the final SelectStmt from all accumulated clause nodes.
363
+ * Also handles the default SELECT *, CTEs, and row-level locking.
364
+ */
365
+ private buildSelectStmt;
366
+ private compileSelect;
367
+ /**
368
+ * Wrap a SELECT statement in SELECT EXISTS(SELECT 1 ...) AS "exists"
369
+ *
370
+ * This transforms the inner SELECT by:
371
+ * 1. Replacing targetList with just `1` (constant)
372
+ * 2. Wrapping in SubLink with EXISTS_SUBLINK
373
+ * 3. Creating outer SELECT with EXISTS result aliased as "exists"
374
+ */
375
+ private wrapSelectInExists;
376
+ private compileCaseExpression;
377
+ /**
378
+ * Compile a CASE THEN/ELSE value based on its ExpressionIntent kind.
379
+ * Delegates to shared resolveCaseValue with nested CASE support.
380
+ */
381
+ private compileCaseValue;
382
+ private compileInsert;
383
+ private compileUpdate;
384
+ private compileDelete;
385
+ /**
386
+ * Register an INNER JOIN for a belongsTo filter-strategy decision.
387
+ * The JOIN replaces the EXISTS subquery when the planner chooses 'join'.
388
+ * The ON condition correlates FK → PK (belongsTo: source.FK = target.PK).
389
+ */
390
+ private registerJoinFilter;
391
+ private compileJoin;
392
+ }
393
+ /**
394
+ * Convenience function to compile a plan
395
+ */
396
+ declare function compilePlan(plan: SimplifiedPlanReport, options?: CompilerOptions): CompiledResult;
397
+
398
+ /**
399
+ * DDL Generator - Generates PostgreSQL DDL statements from ModelIR
400
+ *
401
+ * Generates SQL strings directly for better compatibility and control.
402
+ * Two-pass strategy handles circular FK dependencies.
403
+ *
404
+ * @module ddl/ddl-generator
405
+ */
406
+
407
+ interface GenerateDDLOptions {
408
+ /** Include DROP TABLE IF EXISTS statements before CREATE TABLE */
409
+ readonly includeDropStatements?: boolean;
410
+ /** Database schema name (e.g., 'public', 'tenant_123') */
411
+ readonly schemaName?: string;
412
+ /**
413
+ * Automatically create indexes on foreign key columns.
414
+ * FK columns are frequently used in JOINs, so indexing is a best practice.
415
+ * @default true
416
+ */
417
+ readonly fkAutoIndex?: boolean;
418
+ /** Naming plugin for identifier transformation */
419
+ readonly naming?: NamingPlugin;
420
+ /** Dialect capabilities — DDL passes for unsupported features will be skipped */
421
+ readonly dialectCapabilities?: DialectCapabilities;
422
+ }
423
+ /**
424
+ * Generate DDL statements from a ModelIR schema.
425
+ *
426
+ * Uses a two-pass approach to handle circular FK dependencies:
427
+ * 1. CREATE TABLE (without FK constraints)
428
+ * 2. ALTER TABLE ADD CONSTRAINT for foreign keys
429
+ * 3. CREATE INDEX (explicit + auto-generated for FKs)
430
+ *
431
+ * @param schema - The ModelIR schema to generate DDL from
432
+ * @param options - Optional configuration
433
+ * @returns Array of DDL statements in dependency order
434
+ */
435
+ declare function generateDDL(schema: ModelIR, options?: GenerateDDLOptions): string[];
436
+
437
+ /**
438
+ * Schema Comparison Engine (DDL-PROV Block 1)
439
+ *
440
+ * Compares two ModelIRs (schema definition vs database state)
441
+ * and produces a structured diff of changes needed.
442
+ *
443
+ * @module schema-diff
444
+ */
445
+
446
+ type ChangeKind = 'create_table' | 'drop_table' | 'add_column' | 'drop_column' | 'alter_column_type' | 'alter_column_nullable' | 'alter_column_default' | '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';
447
+ interface SchemaChange {
448
+ readonly kind: ChangeKind;
449
+ readonly table: string;
450
+ readonly column?: string;
451
+ readonly destructive: boolean;
452
+ readonly details: string;
453
+ /** Additional metadata for SQL generation */
454
+ readonly meta?: Readonly<Record<string, unknown>>;
455
+ }
456
+ interface DiffSummary {
457
+ readonly tables: {
458
+ readonly added: number;
459
+ readonly dropped: number;
460
+ };
461
+ readonly columns: {
462
+ readonly added: number;
463
+ readonly dropped: number;
464
+ readonly altered: number;
465
+ };
466
+ readonly indexes: {
467
+ readonly added: number;
468
+ readonly dropped: number;
469
+ };
470
+ readonly constraints: {
471
+ readonly added: number;
472
+ readonly dropped: number;
473
+ readonly altered: number;
474
+ };
475
+ }
476
+ interface SchemaDiff {
477
+ readonly changes: readonly SchemaChange[];
478
+ readonly hasDestructive: boolean;
479
+ readonly summary: DiffSummary;
480
+ }
481
+ interface CompareSchemataOptions {
482
+ /**
483
+ * Database naming convention.
484
+ * When set, schema model names (camelCase) are converted to DB format
485
+ * (e.g. snake_case) before comparison with the introspected model.
486
+ */
487
+ dbCasing?: DbCasing;
488
+ /** Dialect capabilities — comparisons for unsupported features will be skipped */
489
+ readonly dialectCapabilities?: DialectCapabilities;
490
+ }
491
+ /**
492
+ * Compare two ModelIRs and produce a structured diff.
493
+ *
494
+ * @param schema - The desired schema (from definition)
495
+ * @param db - The current database state (from introspection)
496
+ * @param options - Optional comparison settings (e.g. dbCasing)
497
+ * @returns SchemaDiff with all changes needed to bring DB in sync with schema
498
+ */
499
+ declare function compareSchemata(schema: ModelIR, db: ModelIR, options?: CompareSchemataOptions): SchemaDiff;
500
+
501
+ /**
502
+ * Migration SQL Generator (DDL-PROV Block 1)
503
+ *
504
+ * Generates ordered SQL statements from a SchemaDiff.
505
+ * Statements are topologically sorted: DROP constraints → DROP objects → CREATE objects → ADD constraints.
506
+ *
507
+ * @module migration-sql
508
+ */
509
+
510
+ interface MigrationSQLOptions {
511
+ /** Schema namespace (default: none — unqualified) */
512
+ readonly schemaName?: string;
513
+ /** Whether to include destructive changes (drops) */
514
+ readonly includeDestructive?: boolean;
515
+ /** Automatically create indexes on FK columns for new tables (default: true) */
516
+ readonly fkAutoIndex?: boolean;
517
+ /** Dialect capabilities — migration SQL for unsupported features will be filtered */
518
+ readonly dialectCapabilities?: DialectCapabilities;
519
+ }
520
+ /**
521
+ * Generate ordered SQL statements from a SchemaDiff.
522
+ *
523
+ * Topological order:
524
+ * 0. DROP FK/CHECK constraints (must drop before referenced tables)
525
+ * 1. DROP indexes
526
+ * 2. DROP columns
527
+ * 3. DROP primary keys
528
+ * 4. DROP tables, DROP ENUMs
529
+ * 5. CREATE ENUMs (must exist before tables that use them)
530
+ * 6. CREATE tables
531
+ * 7. ADD columns
532
+ * 8. ALTER columns (type, nullable, default)
533
+ * 9. ADD primary keys
534
+ * 10. ADD FK constraints (must add after referenced tables exist)
535
+ * 11. ALTER FK (drop + re-add)
536
+ * 12. CREATE indexes
537
+ * 13. ADD CHECK constraints
538
+ * 14. ALTER ENUM ADD VALUE (must be last — has transaction visibility caveats in PG)
539
+ * 15. COMMENT ON TABLE / COLUMN (very last)
540
+ */
541
+ declare function generateMigrationSQL(diff: SchemaDiff, options?: MigrationSQLOptions): readonly string[];
542
+ /**
543
+ * Generate ordered DOWN SQL statements from a SchemaDiff.
544
+ *
545
+ * Reverses the topological order used in UP migrations:
546
+ * phases run in descending order (11, 10, 9, ..., 0).
547
+ *
548
+ * Irreversible changes (drops that lose data) produce SQL WARNING comments.
549
+ */
550
+ declare function generateDownSQL(diff: SchemaDiff, options?: MigrationSQLOptions): readonly string[];
551
+
552
+ /**
553
+ * Migration File Format v2 — UP + DOWN sections.
554
+ *
555
+ * File format:
556
+ * <UP statements>;
557
+ * -- DOWN
558
+ * <DOWN statements>;
559
+ *
560
+ * The separator `-- DOWN` must be on its own line (SC-25).
561
+ *
562
+ * @module ddl/migration-file
563
+ */
564
+
565
+ /**
566
+ * Result of parsing a migration file's UP/DOWN sections.
567
+ */
568
+ interface ParsedMigrationFile {
569
+ readonly upStatements: readonly string[];
570
+ readonly downStatements: readonly string[];
571
+ readonly hasDown: boolean;
572
+ }
573
+ /**
574
+ * Generate a migration file content with UP and DOWN sections.
575
+ */
576
+ declare function generateMigrationFile(diff: SchemaDiff, options?: MigrationSQLOptions & {
577
+ name?: string;
578
+ }): string;
579
+ /**
580
+ * Parse a migration file into UP and DOWN sections.
581
+ * Separator: `^\s*-- DOWN\s*$` (strict regex, own line only — SC-25)
582
+ */
583
+ declare function parseMigrationFile(content: string): ParsedMigrationFile;
584
+ /**
585
+ * Check if SQL statements contain destructive operations.
586
+ * Destructive: DROP TABLE, DROP COLUMN, lossy ALTER COLUMN TYPE
587
+ */
588
+ declare function isDestructiveDown(downStatements: readonly string[]): boolean;
589
+
590
+ /**
591
+ * Migration Tracker — `_dbsp_migrations` table CRUD.
592
+ *
593
+ * Manages the tracking table that records which migrations
594
+ * have been applied to a database.
595
+ */
596
+
597
+ interface MigrationRecord {
598
+ /** Migration filename (e.g., "0001_create_users.sql") */
599
+ readonly name: string;
600
+ /** SHA-256 checksum of the migration file content */
601
+ readonly checksum: string;
602
+ /** When the migration was applied */
603
+ readonly appliedAt: Date;
604
+ /** Schema version at time of this migration */
605
+ readonly schemaVersion: number;
606
+ /** Whether this migration contains destructive changes */
607
+ readonly destructive: boolean;
608
+ }
609
+ /**
610
+ * Acquire a session-level advisory lock for migration operations.
611
+ *
612
+ * @deprecated Use {@link withMigrationLock} instead — pool.query may release
613
+ * the connection (and the lock) before the migration completes.
614
+ */
615
+ declare function acquireMigrationLock(pool: Pool): Promise<void>;
616
+ /**
617
+ * Release the session-level advisory lock for migration operations.
618
+ *
619
+ * @deprecated Use {@link withMigrationLock} instead.
620
+ */
621
+ declare function releaseMigrationLock(pool: Pool): Promise<void>;
622
+ /**
623
+ * Execute a callback under an advisory lock using a dedicated client.
624
+ * The lock is held for the duration of the callback.
625
+ * The client is released (and lock freed) after the callback completes.
626
+ */
627
+ declare function withMigrationLock<T>(pool: Pool, fn: (client: PoolClient) => Promise<T>): Promise<T>;
628
+ /**
629
+ * Ensure the migrations tracking table exists.
630
+ * Auto-migrates existing tables that lack `schema_version`/`destructive` columns,
631
+ * and backfills `schema_version` by `applied_at` order for rows still at 0.
632
+ */
633
+ declare function ensureMigrationsTable(pool: Pool): Promise<void>;
634
+ /**
635
+ * Get all applied migrations, ordered by name.
636
+ */
637
+ declare function getAppliedMigrations(pool: Pool): Promise<readonly MigrationRecord[]>;
638
+ /**
639
+ * Record a migration as applied.
640
+ */
641
+ declare function recordMigration(pool: Pool, name: string, checksum: string, schemaVersion: number, destructive: boolean): Promise<void>;
642
+ /**
643
+ * Check if a specific migration has been applied.
644
+ */
645
+ declare function isMigrationApplied(pool: Pool, name: string): Promise<boolean>;
646
+ /**
647
+ * Get the next schema version number (max + 1, or 1 if no migrations).
648
+ */
649
+ declare function getNextSchemaVersion(pool: Pool): Promise<number>;
650
+ /**
651
+ * Remove a migration record (for rollback).
652
+ */
653
+ declare function removeMigrationRecord(pool: Pool, name: string): Promise<void>;
654
+
655
+ /**
656
+ * Type Mapping - Maps ModelIR ColumnType to PostgreSQL data types
657
+ *
658
+ * Supports both manual schemas and introspected schemas (preserving originalDbType).
659
+ * Handles auto-increment via SERIAL/BIGSERIAL types.
660
+ *
661
+ * @module ddl/type-mapping
662
+ */
663
+
664
+ /**
665
+ * Map ColumnType to PostgreSQL data type string.
666
+ *
667
+ * Uses originalDbType if available (from introspection), otherwise
668
+ * falls back to reasonable PostgreSQL defaults.
669
+ *
670
+ * @param col - Column definition from ModelIR
671
+ * @returns PostgreSQL type string (e.g., 'VARCHAR(255)', 'SERIAL', 'JSONB')
672
+ */
673
+ declare function mapColumnType(col: ColumnIR): string;
674
+ /**
675
+ * Map OnDeleteAction to PostgreSQL syntax.
676
+ */
677
+ declare function mapOnDeleteAction(action?: string): string;
678
+
679
+ /**
680
+ * EXPLAIN Statement Compiler
681
+ *
682
+ * Generates PostgreSQL EXPLAIN statements with various options.
683
+ * Supports:
684
+ * - ANALYZE (execute and show actual run times)
685
+ * - FORMAT (text, json, xml, yaml)
686
+ * - VERBOSE, COSTS, BUFFERS, TIMING, SETTINGS
687
+ */
688
+
689
+ /**
690
+ * Output format for EXPLAIN results.
691
+ */
692
+ type ExplainFormat = 'text' | 'json' | 'xml' | 'yaml';
693
+ /**
694
+ * Options for EXPLAIN statement.
695
+ */
696
+ interface ExplainOptions {
697
+ /** Execute the query and show actual run times */
698
+ analyze?: boolean;
699
+ /** Show more detailed output */
700
+ verbose?: boolean;
701
+ /** Show cost estimates (default: true) */
702
+ costs?: boolean;
703
+ /** Show buffer usage (requires analyze) */
704
+ buffers?: boolean;
705
+ /** Show actual timing (requires analyze) */
706
+ timing?: boolean;
707
+ /** Show non-default settings */
708
+ settings?: boolean;
709
+ /** Output format */
710
+ format?: ExplainFormat;
711
+ }
712
+ /**
713
+ * Build an EXPLAIN statement wrapping a query.
714
+ *
715
+ * @param query - The query to explain (SelectStmt, InsertStmt, etc.)
716
+ * @param options - EXPLAIN options
717
+ * @returns ExplainStmt AST node
718
+ *
719
+ * @example
720
+ * ```typescript
721
+ * const selectAst = { SelectStmt: { ... } };
722
+ * const explainAst = buildExplain(selectAst, { analyze: true, format: 'json' });
723
+ * // Produces: EXPLAIN (ANALYZE, FORMAT JSON) SELECT ...
724
+ * ```
725
+ */
726
+ declare function buildExplain(query: Node, options?: ExplainOptions): Node;
727
+ /**
728
+ * Build EXPLAIN ANALYZE with JSON format (common pattern).
729
+ *
730
+ * @param query - The query to explain
731
+ * @returns ExplainStmt with ANALYZE and JSON format
732
+ */
733
+ declare function buildExplainAnalyzeJson(query: Node): Node;
734
+ /**
735
+ * Build simple EXPLAIN (plan only, no execution).
736
+ *
737
+ * @param query - The query to explain
738
+ * @returns ExplainStmt with default options
739
+ */
740
+ declare function buildExplainPlan(query: Node): Node;
741
+ /**
742
+ * Build verbose EXPLAIN with costs and buffers.
743
+ *
744
+ * @param query - The query to explain
745
+ * @returns ExplainStmt with verbose options
746
+ */
747
+ declare function buildExplainVerbose(query: Node): Node;
748
+ /**
749
+ * Parse EXPLAIN JSON output to get execution statistics.
750
+ *
751
+ * @param jsonOutput - The JSON string from EXPLAIN (ANALYZE, FORMAT JSON)
752
+ * @returns Parsed plan with execution statistics
753
+ */
754
+ declare function parseExplainJson(jsonOutput: string): ExplainPlan[];
755
+ /**
756
+ * Parsed EXPLAIN plan structure (simplified).
757
+ */
758
+ interface ExplainPlan {
759
+ Plan: {
760
+ 'Node Type': string;
761
+ 'Relation Name'?: string;
762
+ Alias?: string;
763
+ 'Startup Cost'?: number;
764
+ 'Total Cost'?: number;
765
+ 'Plan Rows'?: number;
766
+ 'Plan Width'?: number;
767
+ 'Actual Startup Time'?: number;
768
+ 'Actual Total Time'?: number;
769
+ 'Actual Rows'?: number;
770
+ 'Actual Loops'?: number;
771
+ Plans?: ExplainPlan['Plan'][];
772
+ };
773
+ 'Planning Time'?: number;
774
+ 'Execution Time'?: number;
775
+ Triggers?: unknown[];
776
+ }
777
+ /**
778
+ * Extract total execution time from EXPLAIN ANALYZE JSON output.
779
+ *
780
+ * @param plans - Parsed EXPLAIN plans
781
+ * @returns Total execution time in milliseconds
782
+ */
783
+ declare function getTotalExecutionTime(plans: ExplainPlan[]): number;
784
+ /**
785
+ * Extract row counts from EXPLAIN ANALYZE JSON output.
786
+ *
787
+ * @param plans - Parsed EXPLAIN plans
788
+ * @returns Object with estimated and actual row counts
789
+ */
790
+ declare function getRowEstimates(plans: ExplainPlan[]): {
791
+ estimated: number;
792
+ actual: number;
793
+ };
794
+
795
+ /**
796
+ * ParadeDB Extension Wrappers
797
+ *
798
+ * Type-safe query builders for ParadeDB BM25 full-text search.
799
+ * All functions return ExpressionRef instances that can be used in:
800
+ * - SELECT: .column(score('id').as('score'))
801
+ * - WHERE: .where(bm25Search('symbols', query, { name: 3.0, doc: 1.0 }))
802
+ * - ORDER BY: .orderBy(score('id'), 'desc')
803
+ *
804
+ * @remarks
805
+ * ParadeDB functions accept both named and positional arguments.
806
+ * This module uses named args via namedArg() for parse(), which produces:
807
+ * paradedb.parse(field => 'field_name', query_string => $1)
808
+ * Named parameter syntax is supported via the NamedArgExpressionIntent (EXT-NAMED-PARAMS).
809
+ */
810
+
811
+ /**
812
+ * BM25 relevance score for a row.
813
+ *
814
+ * Use in SELECT and ORDER BY to retrieve and sort by full-text relevance.
815
+ * Requires a BM25 index on the table.
816
+ *
817
+ * @param keyField - The key field of the BM25 index (typically the primary key, e.g. 'id')
818
+ * @returns ExpressionRef that compiles to: paradedb.score("keyField")
819
+ *
820
+ * @example
821
+ * orm.select('symbols').column(score('id').as('score')).orderBy(score('id'), 'desc')
822
+ * // → paradedb.score("id") AS "score"
823
+ */
824
+ declare function score(keyField: string): ExpressionRef;
825
+ /**
826
+ * Parse a single-field BM25 query expression.
827
+ *
828
+ * Compiles to: paradedb.parse(field => 'field_name', query_string => $N)
829
+ *
830
+ * @param field - Column name to search in (must be indexed in the BM25 index)
831
+ * @param query - Query string value (will be bound as a parameter)
832
+ * @returns ExpressionRef for use with boost() or booleanSearch()
833
+ *
834
+ * @example
835
+ * parse('name', 'hello world')
836
+ * // → paradedb.parse(field => 'name', query_string => $1)
837
+ */
838
+ declare function parse(field: string, query: ExpressionRef | unknown): ExpressionRef;
839
+ /**
840
+ * Apply a boost multiplier to a BM25 sub-expression.
841
+ *
842
+ * Compiles to: paradedb.boost(factor, expr)
843
+ *
844
+ * @param factor - Boost multiplier (e.g. 3.0 for 3x weight)
845
+ * @param expr - Expression to boost (typically a parse() call)
846
+ * @returns ExpressionRef for use with booleanSearch()
847
+ *
848
+ * @example
849
+ * boost(3.0, parse('name', 'hello'))
850
+ * // → paradedb.boost(3.0, paradedb.parse('name', $1))
851
+ */
852
+ declare function boost(factor: number, expr: ExpressionRef): ExpressionRef;
853
+ /**
854
+ * Combine multiple BM25 sub-expressions with boolean OR logic.
855
+ *
856
+ * Compiles to: paradedb.boolean(expr1, expr2, ...)
857
+ *
858
+ * @param exprs - One or more sub-expressions (typically boost() calls)
859
+ * @returns ExpressionRef for use on the right side of the @@@ operator
860
+ *
861
+ * @example
862
+ * booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
863
+ * // → paradedb.boolean(paradedb.boost(3.0, ...), paradedb.boost(1.0, ...))
864
+ */
865
+ /**
866
+ * Combine multiple BM25 sub-expressions with boolean OR logic.
867
+ *
868
+ * Compiles to: paradedb.boolean(should => ARRAY[expr1, expr2, ...])
869
+ *
870
+ * @param exprs - One or more sub-expressions (typically boost() calls)
871
+ * @returns ExpressionRef for use on the right side of the @@@ operator
872
+ *
873
+ * @example
874
+ * booleanSearch([boost(3.0, parse('name', q)), boost(1.0, parse('doc', q))])
875
+ * // → paradedb.boolean(should => ARRAY[paradedb.boost(3.0, ...), paradedb.boost(1.0, ...)])
876
+ */
877
+ declare function booleanSearch(exprs: ExpressionRef[]): ExpressionRef;
878
+ /**
879
+ * Full BM25 multi-field search with per-field boost weights.
880
+ *
881
+ * Produces: table @@@ paradedb.boolean(boost1, boost2, ...)
882
+ *
883
+ * Each field in `fieldBoosts` generates a `paradedb.boost(weight, paradedb.parse(field, $N))`
884
+ * sub-expression. The same query string is used for all fields (single parameter binding).
885
+ *
886
+ * @param table - Table alias for the left side of the @@@ operator
887
+ * @param query - Query string (bound as a single $N parameter, shared across all fields)
888
+ * @param fieldBoosts - Map of column name → boost weight
889
+ * @returns ExpressionRef for use in .where()
890
+ *
891
+ * @example
892
+ * bm25Search('s', searchTerm, {
893
+ * name_searchable: 3.0,
894
+ * name: 1.0,
895
+ * signature: 1.5,
896
+ * doc_searchable: 1.0,
897
+ * })
898
+ * // → s @@@ paradedb.boolean(
899
+ * // paradedb.boost(3.0, paradedb.parse('name_searchable', $1)),
900
+ * // paradedb.boost(1.0, paradedb.parse('name', $1)),
901
+ * // paradedb.boost(1.5, paradedb.parse('signature', $1)),
902
+ * // paradedb.boost(1.0, paradedb.parse('doc_searchable', $1))
903
+ * // )
904
+ *
905
+ * @remarks
906
+ * The query parameter is shared: all parse() calls reference the same $N slot.
907
+ * If you need different query strings per field, compose parse()/boost()/booleanSearch() manually.
908
+ *
909
+ * @remarks
910
+ * ParadeDB's boolean() function accepts both positional args and the named
911
+ * `should => ARRAY[...]` syntax. This wrapper uses positional args.
912
+ * Named parameter syntax is deferred to EXT-NAMED-PARAMS.
913
+ */
914
+ declare function bm25Search(table: string, query: unknown, fieldBoosts: Record<string, number>): ExpressionRef;
915
+
916
+ /**
917
+ * PostgreSQL built-in function helpers.
918
+ *
919
+ * Thin wrappers around core expression primitives for common PostgreSQL functions.
920
+ * Same pattern as pgvector.ts and paradedb.ts.
921
+ */
922
+
923
+ /**
924
+ * Generate a series of values: generate_series(start, stop[, step])
925
+ *
926
+ * Returns a set of values from start to stop (inclusive), with an optional step.
927
+ * Commonly used with CTE for batch operations.
928
+ *
929
+ * @example generateSeries(1, 100) → generate_series(1, 100)
930
+ * @example generateSeries(0, 50, 5) → generate_series(0, 50, 5)
931
+ */
932
+ declare function generateSeries(start: number, stop: number, step?: number): ExpressionRef;
933
+ /**
934
+ * Get next value from a sequence: nextval('sequence_name')
935
+ *
936
+ * @example nextval('order_id_seq') → nextval('order_id_seq')
937
+ */
938
+ declare function nextval(sequenceName: string): ExpressionRef;
939
+
940
+ /**
941
+ * pgvector Extension Wrappers
942
+ *
943
+ * Type-safe query builders for pgvector distance operators.
944
+ * All functions return ExpressionRef instances that can be used in:
945
+ * - SELECT: .column(cosineDistance('vector', qv).as('score'))
946
+ * - WHERE: .where(cosineDistance('vector', qv).gte(0.5))
947
+ * - ORDER BY: .orderBy(rawDistance('vector', qv), 'asc')
948
+ */
949
+
950
+ /**
951
+ * Cosine similarity: 1 - (col <=> vector)
952
+ *
953
+ * Score in [0, 1], higher = more similar.
954
+ * Use in SELECT to get a similarity score.
955
+ *
956
+ * @example
957
+ * orm.select('embeddings').column(cosineDistance('vector', qv).as('score'))
958
+ */
959
+ declare function cosineDistance(column: string, vector: number[]): ExpressionRef;
960
+ /**
961
+ * Raw cosine distance: col <=> vector
962
+ *
963
+ * Lower = closer. Index-friendly — use in ORDER BY for ANN search.
964
+ * Do NOT use in SELECT as a similarity score (lower = closer is counterintuitive).
965
+ *
966
+ * @example
967
+ * orm.select('embeddings').orderBy(rawDistance('vector', qv), 'asc')
968
+ */
969
+ declare function rawDistance(column: string, vector: number[]): ExpressionRef;
970
+ /**
971
+ * L2 (Euclidean) distance: col <-> vector
972
+ *
973
+ * @example
974
+ * orm.select('embeddings').orderBy(l2Distance('vector', qv), 'asc')
975
+ */
976
+ declare function l2Distance(column: string, vector: number[]): ExpressionRef;
977
+ /**
978
+ * Inner product distance: col <#> vector (negative inner product)
979
+ *
980
+ * For maximum inner product search: ORDER BY innerProduct('vector', qv) ASC.
981
+ *
982
+ * @example
983
+ * orm.select('embeddings').orderBy(innerProduct('vector', qv), 'asc')
984
+ */
985
+ declare function innerProduct(column: string, vector: number[]): ExpressionRef;
986
+ /**
987
+ * Get the number of dimensions of a vector column: vector_dims(col)
988
+ *
989
+ * Returns an integer — the dimension count of the stored vector.
990
+ * Useful for sanity-checking that embeddings match the expected model dimension.
991
+ *
992
+ * @example
993
+ * orm.from(embeddings).columns([vectorDims('vector').as('dim')]).first()
994
+ * // → SELECT vector_dims("t0"."vector") AS "dim" FROM "embeddings" AS "t0"
995
+ */
996
+ declare function vectorDims(column: string): ExpressionRef;
997
+
998
+ /**
999
+ * Immutable context passed to all handlers during compilation.
1000
+ */
1001
+ interface CompilerContext {
1002
+ /** Naming convention transformer */
1003
+ readonly naming: NamingPlugin;
1004
+ /** Schema name for table qualification (optional) */
1005
+ readonly schema?: string;
1006
+ /** Root table name for the query */
1007
+ readonly rootTable: string;
1008
+ /** Current table alias (for JOINs) */
1009
+ readonly currentAlias?: string;
1010
+ /** Maximum recursive depth (default: 100) */
1011
+ readonly maxRecursiveDepth: number;
1012
+ /** Optional callback for raw SQL audit trail */
1013
+ readonly onRawSQL?: (sql: string) => void;
1014
+ /** Default primary key column name for convention fallbacks (default: 'id') */
1015
+ readonly defaultPkColumnName?: string;
1016
+ /** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
1017
+ readonly deriveFkColumnName?: FkColumnDerivation;
1018
+ /** Alias of the outer (parent) query — used for FieldRef scope:'outer' resolution in EXISTS subqueries */
1019
+ readonly outerAlias?: string;
1020
+ /**
1021
+ * Optional callback to compile a QueryIntent into an AST Node (SubLink subselect).
1022
+ * Set by PlanCompiler when compiling selectCustomExpression — enables SubqueryExpressionIntent
1023
+ * to embed a fully compiled sub-SELECT into the parent SELECT column list.
1024
+ *
1025
+ * @param query - The inner QueryIntent to compile
1026
+ * @param paramOffset - Current outer paramIndex; inner $N are renumbered by this offset
1027
+ * @returns The compiled SelectStmt AST node and the inner parameters
1028
+ */
1029
+ readonly compileSubquery?: (query: _dbsp_types.QueryIntent, paramOffset: number) => {
1030
+ ast: Node;
1031
+ parameters: readonly unknown[];
1032
+ };
1033
+ /**
1034
+ * Optional ModelIR for type-aware parameter casting.
1035
+ * When provided, WHERE comparisons emit `$N::type` to eliminate
1036
+ * PostgreSQL type inference ambiguity for nullable columns.
1037
+ */
1038
+ readonly model?: ModelIR;
1039
+ }
1040
+ /**
1041
+ * Mutable state maintained during compilation.
1042
+ */
1043
+ interface CompilerState {
1044
+ /** Collected parameters in order */
1045
+ parameters: unknown[];
1046
+ /** Current parameter index (1-based for PostgreSQL) */
1047
+ paramIndex: number;
1048
+ /** Registered CTEs for the query */
1049
+ ctes: Map<string, Node>;
1050
+ /** Table aliases in use */
1051
+ aliases: Map<string, string>;
1052
+ /** JOIN clauses accumulated */
1053
+ joins: Node[];
1054
+ }
1055
+ /**
1056
+ * Base decision interface matching core's PlanDecision structure.
1057
+ */
1058
+ interface Decision {
1059
+ readonly type: string;
1060
+ readonly table?: string;
1061
+ readonly column?: string;
1062
+ readonly alias?: string;
1063
+ readonly operator?: string;
1064
+ readonly value?: unknown;
1065
+ readonly paramIndex?: number;
1066
+ readonly dataType?: string;
1067
+ readonly direction?: 'ASC' | 'DESC';
1068
+ readonly nulls?: 'FIRST' | 'LAST';
1069
+ readonly joinType?: 'inner' | 'left';
1070
+ readonly sourceColumn?: string;
1071
+ readonly targetColumn?: string;
1072
+ readonly targetTable?: string;
1073
+ readonly function?: string;
1074
+ readonly args?: readonly unknown[];
1075
+ readonly conditions?: readonly Decision[];
1076
+ readonly columns?: readonly string[];
1077
+ readonly values?: readonly unknown[];
1078
+ readonly set?: readonly {
1079
+ column: string;
1080
+ value: unknown;
1081
+ }[];
1082
+ readonly limit?: number | {
1083
+ paramIndex: number;
1084
+ };
1085
+ readonly offset?: number | {
1086
+ paramIndex: number;
1087
+ };
1088
+ readonly strategy?: 'join' | 'lateral' | 'json_agg' | 'cte';
1089
+ readonly relation?: string;
1090
+ readonly relationName?: string;
1091
+ readonly include?: readonly Decision[];
1092
+ readonly relationType?: 'belongsTo' | 'hasMany' | 'hasOne';
1093
+ readonly foreignKey?: string;
1094
+ readonly parentKey?: string;
1095
+ readonly children?: readonly Decision[];
1096
+ readonly partition?: readonly string[];
1097
+ readonly orderBy?: readonly {
1098
+ column: string;
1099
+ direction?: 'ASC' | 'DESC';
1100
+ }[];
1101
+ readonly frame?: string;
1102
+ readonly maxDepth?: number;
1103
+ readonly pathColumn?: string;
1104
+ readonly cycleDetection?: boolean;
1105
+ readonly selectColumn?: string;
1106
+ readonly aggregate?: string;
1107
+ readonly subqueryOperator?: string;
1108
+ readonly traversal?: string;
1109
+ readonly traversals?: readonly {
1110
+ traversal: string;
1111
+ targetColumn?: string;
1112
+ }[];
1113
+ readonly isRecursive?: boolean;
1114
+ readonly fkColumn?: string;
1115
+ readonly pkColumn?: string;
1116
+ readonly expandRelation?: string;
1117
+ readonly relationColumns?: readonly string[];
1118
+ readonly columnAliases?: Readonly<Record<string, string>>;
1119
+ readonly jsonPath?: readonly string[];
1120
+ readonly jsonMode?: 'json' | 'text';
1121
+ readonly _compiledFilterWhere?: _pgsql_types.Node;
1122
+ readonly filterWhere?: _pgsql_types.Node;
1123
+ readonly expressionIntent?: unknown;
1124
+ readonly escape?: string;
1125
+ }
1126
+ /**
1127
+ * Handler for WHERE clause conditions.
1128
+ * Transforms condition decisions into PostgreSQL AST expressions.
1129
+ */
1130
+ interface WhereHandler {
1131
+ /** Operator(s) this handler supports */
1132
+ readonly operators: readonly string[];
1133
+ /**
1134
+ * Compile a WHERE condition to AST.
1135
+ * @param decision The condition decision
1136
+ * @param ctx Immutable compiler context
1137
+ * @param state Mutable compiler state
1138
+ * @param dispatch Callback to compile nested conditions
1139
+ * @returns PostgreSQL AST node for the condition
1140
+ */
1141
+ compile(decision: Decision, ctx: CompilerContext, state: CompilerState, dispatch: WhereDispatcher): Node;
1142
+ }
1143
+ /**
1144
+ * Dispatcher for recursive WHERE compilation.
1145
+ */
1146
+ type WhereDispatcher = (decision: Decision, ctx: CompilerContext, state: CompilerState) => Node;
1147
+ /**
1148
+ * Handler for SELECT expressions.
1149
+ * Transforms expression decisions into PostgreSQL AST nodes.
1150
+ */
1151
+ interface ExpressionHandler {
1152
+ /** Expression type(s) this handler supports */
1153
+ readonly types: readonly string[];
1154
+ /**
1155
+ * Compile an expression to AST.
1156
+ * @param decision The expression decision
1157
+ * @param ctx Immutable compiler context
1158
+ * @param state Mutable compiler state
1159
+ * @returns PostgreSQL AST node for the expression
1160
+ */
1161
+ compile(decision: Decision, ctx: CompilerContext, state: CompilerState): Node;
1162
+ }
1163
+ /**
1164
+ * Handler for include/relation strategies.
1165
+ * Transforms include decisions into PostgreSQL constructs (JOIN, LATERAL, json_agg, CTE).
1166
+ */
1167
+ interface IncludeHandler {
1168
+ /** Strategy this handler implements */
1169
+ readonly strategy: 'join' | 'lateral' | 'json_agg' | 'cte';
1170
+ /**
1171
+ * Compile an include to AST.
1172
+ * @param decision The include decision
1173
+ * @param ctx Immutable compiler context
1174
+ * @param state Mutable compiler state
1175
+ * @returns Object with modifications to apply
1176
+ */
1177
+ compile(decision: Decision, ctx: CompilerContext, state: CompilerState): IncludeResult;
1178
+ }
1179
+ /**
1180
+ * Result of include compilation.
1181
+ */
1182
+ interface IncludeResult {
1183
+ /** Additional target list items (SELECT columns) */
1184
+ targets?: Node[];
1185
+ /** JOIN to add to FROM clause */
1186
+ join?: Node;
1187
+ /** Additional JOINs for cascaded includes (e.g., flat deep nesting) */
1188
+ additionalJoins?: Node[];
1189
+ /** CTE to add to WITH clause */
1190
+ cte?: Node;
1191
+ /** Subquery for LATERAL */
1192
+ lateral?: Node;
1193
+ }
1194
+
1195
+ /**
1196
+ * PostgreSQL Schema Introspection (ADAPTER-006)
1197
+ *
1198
+ * Queries information_schema/pg_catalog to build ModelIR
1199
+ * from an existing database. Supports:
1200
+ * - Table/column/PK discovery
1201
+ * - FK → bidirectional relation inference
1202
+ * - Hierarchy detection (adjacency + edge-table)
1203
+ * - Include/exclude filtering
1204
+ *
1205
+ * @module introspection
1206
+ */
1207
+
1208
+ /** Options for database introspection */
1209
+ interface IntrospectionOptions {
1210
+ /** Tables to exclude (glob patterns: * matches any chars) */
1211
+ readonly exclude?: readonly string[];
1212
+ /** Tables to include (default: all). Applied before exclude. */
1213
+ readonly include?: readonly string[];
1214
+ /** Schema name to introspect (default: 'public') */
1215
+ readonly schema?: string;
1216
+ }
1217
+ /** Hierarchy pattern detected during introspection */
1218
+ /**
1219
+ * Hierarchy pattern detected during introspection.
1220
+ * Alias of {@link HierarchyIR} from \@dbsp/types — kept here for
1221
+ * public-API backwards compatibility (re-exported from \@dbsp/adapter-pgsql).
1222
+ */
1223
+ type DetectedHierarchy = HierarchyIR;
1224
+ /** Extended ModelIR with hierarchy metadata */
1225
+ interface IntrospectedModelIR extends ModelIR {
1226
+ readonly hierarchies: readonly DetectedHierarchy[];
1227
+ readonly introspectedAt: Date;
1228
+ readonly warnings: readonly string[];
1229
+ }
1230
+ declare function introspect(pool: Pool, options?: IntrospectionOptions): Promise<IntrospectedModelIR>;
1231
+
1232
+ /**
1233
+ * Mutation Compiler
1234
+ *
1235
+ * Compiles INSERT, UPDATE, and DELETE statements from plan decisions.
1236
+ * Supports:
1237
+ * - INSERT with values/from subquery
1238
+ * - INSERT with RETURNING
1239
+ * - UPDATE with SET and WHERE
1240
+ * - DELETE with WHERE
1241
+ * - RETURNING clause for all mutations
1242
+ */
1243
+
1244
+ /**
1245
+ * Configuration for INSERT compilation
1246
+ */
1247
+ interface InsertConfig {
1248
+ /** Table to insert into */
1249
+ table: string;
1250
+ /** Columns to insert */
1251
+ columns: string[];
1252
+ /** Values for each column (array of rows) */
1253
+ values: unknown[][];
1254
+ /** Columns to return (RETURNING clause) */
1255
+ returning?: string[];
1256
+ /** Subquery for INSERT ... SELECT */
1257
+ selectQuery?: Node;
1258
+ /** Column database types for type-cast emission (e.g. range types) */
1259
+ columnTypes?: Record<string, string>;
1260
+ }
1261
+ /**
1262
+ * Configuration for UPDATE compilation
1263
+ */
1264
+ interface UpdateConfig {
1265
+ /** Table to update */
1266
+ table: string;
1267
+ /** Column-value pairs to set */
1268
+ set: {
1269
+ column: string;
1270
+ value: unknown;
1271
+ }[];
1272
+ /** WHERE conditions */
1273
+ where?: Decision[];
1274
+ /** Columns to return (RETURNING clause) */
1275
+ returning?: string[];
1276
+ /** Column database types for type-cast emission (e.g. range types) */
1277
+ columnTypes?: Record<string, string>;
1278
+ }
1279
+ /**
1280
+ * Configuration for DELETE compilation
1281
+ */
1282
+ interface DeleteConfig {
1283
+ /** Table to delete from */
1284
+ table: string;
1285
+ /** WHERE conditions */
1286
+ where?: Decision[];
1287
+ /** Columns to return (RETURNING clause) */
1288
+ returning?: string[];
1289
+ }
1290
+ /**
1291
+ * Compile an INSERT statement from configuration.
1292
+ */
1293
+ declare function compileInsert(config: InsertConfig, ctx: CompilerContext, state: CompilerState): Node;
1294
+ /**
1295
+ * Compile an UPDATE statement from configuration.
1296
+ */
1297
+ declare function compileUpdate(config: UpdateConfig, ctx: CompilerContext, state: CompilerState): Node;
1298
+ declare function compileDelete(config: DeleteConfig, ctx: CompilerContext, state: CompilerState): Node;
1299
+ /**
1300
+ * Compile a mutation decision to AST.
1301
+ * Determines mutation type from decision.type and delegates.
1302
+ */
1303
+ declare function compileMutation(decision: Decision, ctx: CompilerContext, state: CompilerState): Node;
1304
+
1305
+ /**
1306
+ * Upsert (INSERT ... ON CONFLICT) Compiler
1307
+ *
1308
+ * Compiles UPSERT statements with ON CONFLICT handling.
1309
+ * Supports:
1310
+ * - ON CONFLICT DO NOTHING
1311
+ * - ON CONFLICT DO UPDATE SET ...
1312
+ * - Conflict target (columns or constraint name)
1313
+ * - WHERE clause for conflict resolution
1314
+ */
1315
+
1316
+ /**
1317
+ * Conflict resolution strategy
1318
+ */
1319
+ type ConflictAction = 'nothing' | 'update';
1320
+ /**
1321
+ * Conflict target specification
1322
+ */
1323
+ interface ConflictTarget {
1324
+ /** Column names that form the unique constraint */
1325
+ columns?: string[];
1326
+ /** Named constraint */
1327
+ constraint?: string;
1328
+ /** WHERE clause for partial index */
1329
+ where?: Decision[];
1330
+ }
1331
+ /**
1332
+ * Configuration for UPSERT compilation
1333
+ */
1334
+ interface UpsertConfig {
1335
+ /** Table to upsert into */
1336
+ table: string;
1337
+ /** Columns to insert */
1338
+ columns: string[];
1339
+ /** Values for each column (array of rows) */
1340
+ values: unknown[][];
1341
+ /** Conflict target (unique columns or constraint) */
1342
+ conflictTarget: ConflictTarget;
1343
+ /** What to do on conflict */
1344
+ conflictAction: ConflictAction;
1345
+ /** Columns to update on conflict (for 'update' action) */
1346
+ updateColumns?: string[];
1347
+ /** Use EXCLUDED.column for update values (default: true) */
1348
+ useExcluded?: boolean;
1349
+ /** Columns to return (RETURNING clause) */
1350
+ returning?: string[];
1351
+ /** Optional column type hints for unnest casting (schema-driven) */
1352
+ columnTypes?: Record<string, string>;
1353
+ /**
1354
+ * Raw SQL expressions for specific update columns.
1355
+ * These are injected verbatim into the ON CONFLICT DO UPDATE SET clause.
1356
+ * Keys are logical column names (before naming plugin), values are raw SQL fragments.
1357
+ *
1358
+ * @warning SECURITY: fragments are inserted without parameterization.
1359
+ * Only use with hardcoded expressions. Never with user input.
1360
+ *
1361
+ * @example { last_parsed: 'now()', count: 'excluded.count + 1' }
1362
+ */
1363
+ updateExpressions?: Record<string, string>;
1364
+ }
1365
+ /**
1366
+ * Build ON CONFLICT clause for INSERT statement.
1367
+ */
1368
+ declare function buildOnConflictClause(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): OnConflictClause;
1369
+ /**
1370
+ * Compile a complete UPSERT statement.
1371
+ */
1372
+ declare function compileUpsert(config: UpsertConfig, ctx: CompilerContext, state: CompilerState): Node;
1373
+ /**
1374
+ * Build EXCLUDED.column reference.
1375
+ * EXCLUDED is a special table alias in ON CONFLICT ... DO UPDATE
1376
+ * that refers to the row that would have been inserted.
1377
+ */
1378
+ declare function excludedRef(column: string, naming: {
1379
+ toDatabase: (s: string) => string;
1380
+ }): Node;
1381
+ /**
1382
+ * Build conditional update using COALESCE.
1383
+ *
1384
+ * Produces: COALESCE(EXCLUDED.col, table.col)
1385
+ * This keeps existing value if new value is NULL.
1386
+ */
1387
+ declare function conditionalUpdate(column: string, table: string, ctx: CompilerContext): Node;
1388
+
1389
+ /**
1390
+ * @module naming
1391
+ * Utilities for resolving database names to logical model names.
1392
+ *
1393
+ * The ModelIR.getTable() method expects logical (camelCase) names,
1394
+ * but the adapter often works with database (snake_case) names.
1395
+ * This module bridges that gap.
1396
+ */
1397
+
1398
+ /**
1399
+ * Resolve a database table name to the corresponding logical model name.
1400
+ *
1401
+ * Converts the DB name using the naming convention, then looks it up in the model.
1402
+ * Falls back to exact match if conversion doesn't find a match.
1403
+ *
1404
+ * @param model - The model IR to search in
1405
+ * @param dbName - Database table name (e.g. "post_comments")
1406
+ * @param convention - Naming convention used by the adapter
1407
+ * @returns The logical table name if found, undefined otherwise
1408
+ *
1409
+ * @example
1410
+ * ```typescript
1411
+ * // With camelCase convention:
1412
+ * resolveLogicalName(model, "post_comments", "camelCase") // → "postComments"
1413
+ * resolveLogicalName(model, "posts", "camelCase") // → "posts"
1414
+ * resolveLogicalName(model, "unknown", "camelCase") // → undefined
1415
+ * ```
1416
+ */
1417
+ declare function resolveLogicalName(model: ModelIR, dbName: string, casing: DbCasing): string | undefined;
1418
+
1419
+ /**
1420
+ * ParamRef validation and helpers for PostgreSQL AST
1421
+ *
1422
+ * ParamRef nodes represent parameterized query placeholders ($1, $2, etc.)
1423
+ * This module provides validation and creation helpers for safe AST construction.
1424
+ */
1425
+
1426
+ /**
1427
+ * Validation result for ParamRef nodes
1428
+ */
1429
+ interface ParamRefValidationResult {
1430
+ valid: boolean;
1431
+ errors: string[];
1432
+ }
1433
+ /**
1434
+ * Validates a ParamRef node
1435
+ *
1436
+ * Rules:
1437
+ * - `number` must be a positive integer (1-based indexing)
1438
+ * - `number` must not exceed reasonable bounds (e.g., 65535)
1439
+ */
1440
+ declare function validateParamRef(paramRef: ParamRef): ParamRefValidationResult;
1441
+ /**
1442
+ * Creates a validated ParamRef node
1443
+ * @throws Error if validation fails
1444
+ */
1445
+ declare function createParamRef(number: number, location?: number): Node;
1446
+ /**
1447
+ * Creates a TypeCast node wrapping a ParamRef
1448
+ * Example: $1::integer, $2::text[]
1449
+ */
1450
+ declare function createTypeCastParamRef(paramNumber: number, typeName: string, isArray?: boolean, location?: number): Node;
1451
+ /**
1452
+ * Creates an A_Expr node for equality comparison with ParamRef
1453
+ * Example: col = $1
1454
+ */
1455
+ declare function createEqualityExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
1456
+ /**
1457
+ * Creates a FuncCall node for ANY() with ParamRef
1458
+ * Example: col = ANY($1) for array parameter matching
1459
+ */
1460
+ declare function createAnyExpr(columnName: string, paramNumber: number, tableName?: string, location?: number): Node;
1461
+ /**
1462
+ * Collects all ParamRef nodes from an AST, validating each
1463
+ * Returns validation results for all found ParamRefs
1464
+ */
1465
+ declare function collectAndValidateParamRefs(node: unknown): {
1466
+ paramRefs: Array<{
1467
+ paramRef: ParamRef;
1468
+ path: string;
1469
+ }>;
1470
+ validationResults: ParamRefValidationResult[];
1471
+ allValid: boolean;
1472
+ };
1473
+
1474
+ /**
1475
+ * PgsqlAdapter - Implements the Adapter interface for PostgreSQL using native pg driver.
1476
+ *
1477
+ * This adapter wraps a pg Pool instance and provides the unified
1478
+ * adapter interface for the db-semantic-planner ORM.
1479
+ *
1480
+ * @module pgsql-adapter
1481
+ */
1482
+
1483
+ /**
1484
+ * Options for PgsqlAdapter.
1485
+ */
1486
+ interface PgsqlAdapterOptions {
1487
+ /** Schema name for multi-tenant queries */
1488
+ readonly schemaName?: string;
1489
+ /**
1490
+ * DB column casing convention (intuitive semantics).
1491
+ * - `'snake_case'`: DB columns are snake_case → transform to camelCase for JS
1492
+ * - `'camelCase'`: DB columns are camelCase → no transformation
1493
+ * - `'preserve'`: No transformation
1494
+ */
1495
+ readonly dbCasing?: DbCasing;
1496
+ /** Optional model for WHERE compilation */
1497
+ readonly model?: ModelIR;
1498
+ /** Optional logger for debug/error messages */
1499
+ readonly logger?: AdapterLogger;
1500
+ /** Default primary key column name for convention fallbacks (default: 'id') */
1501
+ readonly defaultPkColumnName?: string;
1502
+ /** Convention for deriving FK column names: (tableName, pkName) => fkColumnName */
1503
+ readonly deriveFkColumnName?: FkColumnDerivation;
1504
+ }
1505
+ /**
1506
+ * Adapter implementation for PostgreSQL using native pg driver.
1507
+ *
1508
+ * @typeParam DB - Database schema type
1509
+ *
1510
+ * @example
1511
+ * ```typescript
1512
+ * import { Pool } from 'pg';
1513
+ * import { createPgsqlAdapter } from '@dbsp/adapter-pgsql';
1514
+ *
1515
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
1516
+ * const adapter = createPgsqlAdapter(pool);
1517
+ * const orm = createOrm({ model, adapter });
1518
+ * ```
1519
+ */
1520
+ declare class PgsqlAdapter<DB = unknown> implements Adapter<DB> {
1521
+ private readonly pool;
1522
+ private readonly client;
1523
+ private readonly schemaName;
1524
+ private readonly _dbCasing;
1525
+ private readonly naming;
1526
+ private readonly model;
1527
+ private readonly logger;
1528
+ private readonly _capabilities;
1529
+ private readonly defaultPk;
1530
+ private readonly deriveFk;
1531
+ /**
1532
+ * Create a new PgsqlAdapter.
1533
+ *
1534
+ * @param pool - pg.Pool instance, PoolClient (transactions), or undefined (compile-only mode)
1535
+ * @param options - Optional configuration
1536
+ */
1537
+ constructor(pool?: Pool | PoolClient | undefined, options?: PgsqlAdapterOptions);
1538
+ /**
1539
+ * Shared compilation dependencies — built lazily from adapter fields.
1540
+ * Passed to compiler sub-modules instead of `this`.
1541
+ */
1542
+ /**
1543
+ * Return a new PgsqlAdapterOptions that merges current config with overrides.
1544
+ * Ensures that all configuration fields (logger, defaultPkColumnName,
1545
+ * deriveFkColumnName, etc.) are propagated to scoped/transactional adapters.
1546
+ */
1547
+ private cloneOptions;
1548
+ private buildCompileDeps;
1549
+ /**
1550
+ * Returns the pool/client executor, or throws if in compile-only mode.
1551
+ */
1552
+ private requireConnection;
1553
+ /** Adapter capabilities for feature detection */
1554
+ get capabilities(): AdapterCapabilities;
1555
+ /** PostgreSQL dialect capabilities for planner strategy selection */
1556
+ get dialectCapabilities(): DialectCapabilities;
1557
+ /**
1558
+ * DB column casing convention used by this adapter.
1559
+ */
1560
+ get dbCasing(): DbCasing;
1561
+ /**
1562
+ * Get the underlying pg Pool instance.
1563
+ */
1564
+ getPoolInstance(): Pool;
1565
+ /**
1566
+ * Compile a plan to executable SQL.
1567
+ */
1568
+ compile<T = unknown>(plan: PlanReport, options?: CompileOptions): CompiledQuery<T>;
1569
+ /**
1570
+ * Compile a plan with includes, returning subquery include metadata (DX-033).
1571
+ */
1572
+ compileWithIncludes<T = unknown>(plan: PlanReport, options?: CompileOptions): CompileResultWithIncludes<T>;
1573
+ /**
1574
+ * Compile a subquery include query for given parent IDs (DX-033).
1575
+ * Generates: SELECT * FROM targetTable WHERE foreignKey IN ($1, $2, ...)
1576
+ *
1577
+ * @param info - Subquery include metadata
1578
+ * @param parentIds - Parent record IDs to fetch related records for
1579
+ * @param options - Compile options
1580
+ * @returns Compiled query for fetching related records
1581
+ */
1582
+ compileSubqueryInclude(info: SubqueryIncludeInfo, parentIds: readonly unknown[], options?: CompileOptions): CompiledQuery;
1583
+ /**
1584
+ * Compile a FROM-less SELECT expression to SQL.
1585
+ *
1586
+ * Produces: SELECT <expr>
1587
+ * Example: SELECT nextval('my_seq')
1588
+ *
1589
+ * @param expr - ExpressionIntent to evaluate
1590
+ * @returns Compiled SQL and parameters
1591
+ */
1592
+ compileSelectExpression(expr: ExpressionIntent): CompiledQuery;
1593
+ /**
1594
+ * Compile an insert intent to executable SQL.
1595
+ *
1596
+ * Strategy switch (per CompileOptions):
1597
+ * - rows <= batchThreshold (default 50): VALUES ($1,$2),($3,$4),...
1598
+ * - rows > batchThreshold OR batchThreshold === 0: SELECT unnest($1::type[]),...
1599
+ */
1600
+ compileInsert(intent: InsertIntent, options?: CompileOptions): CompiledQuery;
1601
+ /**
1602
+ * Compile an insert-from intent to executable SQL (NQL-ALIGN).
1603
+ * INSERT INTO target (cols) SELECT cols FROM source WHERE ... LIMIT ... RETURNING ...
1604
+ */
1605
+ compileInsertFrom(intent: InsertFromIntent, options?: CompileOptions): CompiledQuery;
1606
+ /**
1607
+ * Compile an update intent to executable SQL.
1608
+ */
1609
+ compileUpdate(intent: UpdateIntent, options?: CompileOptions): CompiledQuery;
1610
+ /**
1611
+ * Compile a batch update intent to executable SQL using unnest FROM strategy (BATCH-001).
1612
+ *
1613
+ * Generates:
1614
+ * UPDATE "table" SET "update_col" = t."update_col" [, "scalar_col" = $N]
1615
+ * FROM unnest(CAST($1 AS type[]), CAST($2 AS type[])) AS t("match_col", "update_col")
1616
+ * WHERE "table"."match_col" = t."match_col"
1617
+ * [RETURNING ...]
1618
+ */
1619
+ compileBatchUpdate(intent: BatchUpdateIntent, options?: CompileOptions): CompiledQuery;
1620
+ /**
1621
+ * Compile a delete intent to executable SQL.
1622
+ */
1623
+ compileDelete(intent: DeleteIntent, options?: CompileOptions): CompiledQuery;
1624
+ /**
1625
+ * Compile an upsert intent to executable SQL (DX-026).
1626
+ */
1627
+ compileUpsert(intent: UpsertIntent, options?: CompileOptions): CompiledQuery;
1628
+ /**
1629
+ * Compile an upsert-from intent to executable SQL (NQL-BIND).
1630
+ * INSERT INTO target SELECT ... FROM source ON CONFLICT (cols) DO UPDATE SET ...
1631
+ */
1632
+ compileUpsertFrom(intent: UpsertFromIntent, options?: CompileOptions): CompiledQuery;
1633
+ /**
1634
+ * Compile a recursive CTE plan to executable SQL.
1635
+ * Supports adjacency-list and edge-table traversal modes.
1636
+ */
1637
+ compileRecursive(report: RecursivePlanReport, model: ModelIR, options?: CompileOptions): CompiledQuery;
1638
+ /**
1639
+ * Compile a CTE query backed by unnest() arrays (BATCH-001 Block 5).
1640
+ *
1641
+ * Strategy: compile CTE nodes to SQL fragments, compile outer query
1642
+ * independently (parameters starting at $1), then renumber outer params
1643
+ * to start after CTE params and prepend WITH clause.
1644
+ */
1645
+ compileCteQuery(intent: CteQueryIntent, options?: CompileOptions): CompiledQuery;
1646
+ /**
1647
+ * Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL.
1648
+ */
1649
+ compileSetOperation(intent: SetOperationIntent, model: ModelIR, _options?: CompileOptions): CompiledQuery;
1650
+ /**
1651
+ * Create a dump for observability.
1652
+ */
1653
+ createDump(plan: PlanReport, query: CompiledQuery, meta?: DumpMeta): Dump;
1654
+ /**
1655
+ * Execute a query and return all results.
1656
+ * Results are transformed to use model naming convention (e.g., snake_case → camelCase)
1657
+ */
1658
+ execute<T>(query: CompiledQuery<T>): Promise<T[]>;
1659
+ /**
1660
+ * Transform result rows from database naming to model naming convention.
1661
+ * For CamelCaseNamingPlugin: price_cents → priceCents
1662
+ */
1663
+ private transformResultRows;
1664
+ /**
1665
+ * Execute a query and return the first result or null.
1666
+ */
1667
+ executeOne<T>(query: CompiledQuery<T>): Promise<T | null>;
1668
+ /**
1669
+ * Execute a query and return the first result or throw.
1670
+ */
1671
+ executeOneOrThrow<T>(query: CompiledQuery<T>): Promise<T>;
1672
+ /**
1673
+ * Stream query results as an async iterable iterator.
1674
+ * Uses PostgreSQL cursors for efficient streaming.
1675
+ *
1676
+ * Note: The cursor must be used within a transaction. If not already
1677
+ * in a transaction, this method wraps the streaming in one.
1678
+ *
1679
+ * @param query - Compiled query to stream
1680
+ * @param options - Stream options (chunkSize)
1681
+ * @returns AsyncIterableIterator that yields rows one by one
1682
+ */
1683
+ stream<T>(query: CompiledQuery<T>, options?: AdapterStreamOptions): AsyncIterableIterator<T>;
1684
+ /**
1685
+ * Internal: Stream with an existing client using cursors.
1686
+ */
1687
+ private streamWithClient;
1688
+ /**
1689
+ * Introspect the database schema and return a ModelIR.
1690
+ *
1691
+ * @param options - Optional introspection options (schema, include/exclude filters)
1692
+ * @returns IntrospectedModelIR with tables, relations, and hierarchy metadata
1693
+ *
1694
+ * @example
1695
+ * ```typescript
1696
+ * const model = await adapter.introspect();
1697
+ * const model = await adapter.introspect({ schema: 'tenant_1' });
1698
+ * const model = await adapter.introspect({ exclude: ['_prisma*'] });
1699
+ * ```
1700
+ */
1701
+ introspect(options?: IntrospectionOptions): Promise<IntrospectedModelIR>;
1702
+ /**
1703
+ * Execute a callback within a database transaction.
1704
+ */
1705
+ transaction<T>(fn: (adapter: Adapter<DB>) => Promise<T>): Promise<T>;
1706
+ /**
1707
+ * Create a schema-scoped adapter for multi-tenant queries.
1708
+ */
1709
+ withSchema(schemaName: string): Adapter<DB>;
1710
+ /**
1711
+ * Execute raw SQL directly.
1712
+ *
1713
+ * ⚠️ WARNING: Use parameter placeholders ($1, $2, etc.) for all values.
1714
+ */
1715
+ executeRaw<T = unknown>(sql: string, parameters?: readonly unknown[]): Promise<T[]>;
1716
+ /**
1717
+ * Generate DDL statements from a ModelIR schema.
1718
+ *
1719
+ * Uses PostgreSQL AST nodes and pgsql-deparser for consistent SQL generation.
1720
+ * Applies the naming plugin for identifier transformation.
1721
+ *
1722
+ * @param schema - The ModelIR schema to generate DDL from
1723
+ * @param overrideOptions - Optional overrides for DDL generation (e.g., includeDropStatements)
1724
+ * @returns Array of DDL statements in dependency order
1725
+ */
1726
+ generateDDL(schema: ModelIR, overrideOptions?: Partial<GenerateDDLOptions>): string[];
1727
+ /**
1728
+ * Execute a DDL statement directly (e.g. TRUNCATE, VACUUM, ALTER TABLE, CREATE INDEX).
1729
+ *
1730
+ * @throws Error if called on a compile-only adapter (no pool)
1731
+ * @since DDL-TABLE-001
1732
+ */
1733
+ executeDDL(sql: string): Promise<void>;
1734
+ /**
1735
+ * Whether this adapter instance is scoped inside a transaction.
1736
+ * Guards unsafe DDL operations (VACUUM, CREATE INDEX CONCURRENTLY).
1737
+ *
1738
+ * @since DDL-TABLE-001
1739
+ */
1740
+ get inTransaction(): boolean;
1741
+ /**
1742
+ * List all indexes on a table by querying pg_indexes.
1743
+ *
1744
+ * @param table - Table name
1745
+ * @param schema - Schema name (defaults to adapter schema or 'public')
1746
+ */
1747
+ listIndexes(table: string, schema?: string, options?: {
1748
+ namePattern?: string;
1749
+ }): Promise<IndexInfo[]>;
1750
+ /**
1751
+ * Check whether an index with the given name exists on a table.
1752
+ *
1753
+ * @param name - Index name
1754
+ * @param table - Table name
1755
+ * @param schema - Schema name (defaults to adapter schema or 'public')
1756
+ */
1757
+ indexExists(name: string, table: string, schema?: string): Promise<boolean>;
1758
+ /**
1759
+ * Return the total storage size of a table in bytes.
1760
+ *
1761
+ * @param table - Table name
1762
+ * @param schema - Schema name (defaults to adapter schema or 'public')
1763
+ */
1764
+ /**
1765
+ * Return the total storage size of a table in bytes (includes indexes and TOAST).
1766
+ *
1767
+ * The table name is a SQL identifier — it is double-quoted, not parameterized,
1768
+ * because PostgreSQL does not allow parameterized table names in FROM clauses.
1769
+ *
1770
+ * @param table - Table name
1771
+ * @param schema - Schema name (defaults to adapter schema or 'public')
1772
+ */
1773
+ storageSize(table: string, schema?: string): Promise<number>;
1774
+ /**
1775
+ * Generate SQL for TRUNCATE TABLE.
1776
+ * Implements TableDDLGeneratorAdapter.generateTruncate.
1777
+ */
1778
+ generateTruncate(table: string, schema?: string, options?: TruncateOptions): string;
1779
+ /**
1780
+ * Generate SQL for VACUUM.
1781
+ * Implements TableDDLGeneratorAdapter.generateVacuum.
1782
+ */
1783
+ generateVacuum(table: string, schema?: string, options?: VacuumOptions): string;
1784
+ /**
1785
+ * Generate SQL for ALTER TABLE ... ALTER COLUMN.
1786
+ * Implements TableDDLGeneratorAdapter.generateAlterColumn.
1787
+ */
1788
+ generateAlterColumn(table: string, column: string, options: AlterColumnOptions, schema?: string): string;
1789
+ /**
1790
+ * Generate SQL for CREATE INDEX.
1791
+ * Implements TableDDLGeneratorAdapter.generateCreateIndex.
1792
+ */
1793
+ generateCreateIndex(table: string, options: CreateIndexOptions, schema?: string): string;
1794
+ /**
1795
+ * Generate SQL for DROP INDEX.
1796
+ * Implements TableDDLGeneratorAdapter.generateDropIndex.
1797
+ */
1798
+ generateDropIndex(name: string, options?: DropIndexOptions): string;
1799
+ /**
1800
+ * Validate an identifier (table name, column name, schema name).
1801
+ */
1802
+ validateIdentifier(value: string, type: string): void;
1803
+ }
1804
+ /**
1805
+ * Create a PgsqlAdapter from a pg Pool instance.
1806
+ *
1807
+ * @param pool - pg Pool instance
1808
+ * @param options - Optional configuration
1809
+ * @returns A new PgsqlAdapter instance
1810
+ *
1811
+ * @example
1812
+ * ```typescript
1813
+ * import { Pool } from 'pg';
1814
+ * import { createPgsqlAdapter } from '@dbsp/adapter-pgsql';
1815
+ *
1816
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
1817
+ * const adapter = createPgsqlAdapter(pool);
1818
+ *
1819
+ * // With naming convention
1820
+ * const adapter = createPgsqlAdapter(pool, { dbCasing: 'snake_case' });
1821
+ * ```
1822
+ */
1823
+ declare function createPgsqlAdapter<DB = unknown>(pool: Pool, options?: PgsqlAdapterOptions): PgsqlAdapter<DB>;
1824
+ /**
1825
+ * Creates a compile-only PgsqlAdapter for SQL generation without a database connection.
1826
+ *
1827
+ * All compilation methods (compile, compileInsert, etc.), createDump(), and generateDDL()
1828
+ * work normally. Execution methods (execute, stream, transaction, etc.) throw an error.
1829
+ *
1830
+ * @example
1831
+ * ```typescript
1832
+ * import { createPgsqlCompileOnlyAdapter } from '@dbsp/adapter-pgsql';
1833
+ * import { createOrm } from '@dbsp/core';
1834
+ *
1835
+ * const adapter = createPgsqlCompileOnlyAdapter();
1836
+ * const orm = createOrm({ model, adapter });
1837
+ * const dump = await orm.select('users').dump();
1838
+ * console.log(dump.sql);
1839
+ * ```
1840
+ */
1841
+ declare function createPgsqlCompileOnlyAdapter<DB = unknown>(options?: PgsqlAdapterOptions): CompileOnlyAdapter;
1842
+
1843
+ /**
1844
+ * Redact sensitive values in a query dump's `params` array before logging.
1845
+ *
1846
+ * Defense-in-depth helper: when application code may have inserted PII as
1847
+ * literal parameter values (e.g. an email in a WHERE clause), this replaces
1848
+ * any string value matching a configured pattern with the `replacement`
1849
+ * placeholder. Non-string values are passed through unchanged.
1850
+ */
1851
+ type RedactionPattern = string | RegExp;
1852
+ type RedactionConfig = {
1853
+ /** Patterns to match against string param values. String = substring (case-insensitive); RegExp = `.test()`. */
1854
+ readonly patterns: ReadonlyArray<RedactionPattern>;
1855
+ /** Placeholder substituted for matched values. Default `'[REDACTED]'`. */
1856
+ readonly replacement?: string;
1857
+ };
1858
+ /**
1859
+ * Curated regex set for common PII shapes. Match against the value itself
1860
+ * (not the column name), so they detect data shaped like an email / token /
1861
+ * credit-card / SSN regardless of which `$N` slot it landed in.
1862
+ *
1863
+ * @stable Adding entries is non-breaking; removing one is a semver-major change
1864
+ * because callers may rely on a specific shape being redacted.
1865
+ */
1866
+ declare const DEFAULT_REDACTION_PATTERNS: ReadonlyArray<RegExp>;
1867
+ /**
1868
+ * Returns a NEW array of params with sensitive string values replaced.
1869
+ * The input array is never mutated. Non-string values pass through unchanged.
1870
+ */
1871
+ declare function redactParams(params: readonly unknown[], config: RedactionConfig): readonly unknown[];
1872
+
1873
+ /**
1874
+ * Set operation compiler (UNION / INTERSECT / EXCEPT)
1875
+ *
1876
+ * Recursively compiles a SetOperationIntent tree into a single SQL string
1877
+ * with correctly renumbered positional parameters ($1, $2, ...).
1878
+ */
1879
+
1880
+ /**
1881
+ * Compiled SQL with positional parameters.
1882
+ */
1883
+ interface SetOperationResult {
1884
+ readonly sql: string;
1885
+ readonly parameters: readonly unknown[];
1886
+ }
1887
+ /**
1888
+ * Function that compiles a single QueryIntent leaf to SQL + parameters.
1889
+ * Provided by the caller to decouple from adapter internals.
1890
+ */
1891
+ type LeafCompileFn = (query: QueryIntent) => {
1892
+ sql: string;
1893
+ parameters: readonly unknown[];
1894
+ };
1895
+ /**
1896
+ * Recursively compile a SetOperationIntent to SQL with merged parameters.
1897
+ *
1898
+ * Each leaf QueryIntent is compiled via `compileFn`. When merging left and
1899
+ * right branches, the right side's `$N` placeholders are renumbered so they
1900
+ * don't collide with the left side's parameters.
1901
+ *
1902
+ * @param intent - The set operation intent (recursive tree)
1903
+ * @param compileFn - Compiles a single QueryIntent to SQL + params
1904
+ * @returns Combined SQL string and merged parameter array
1905
+ *
1906
+ * @example
1907
+ * ```typescript
1908
+ * const result = compileSetOperation(setOpIntent, (query) => {
1909
+ * const planReport = plan(query, model, { dialectCapabilities });
1910
+ * return adapter.compile(planReport, { model });
1911
+ * });
1912
+ * console.log(result.sql); // (SELECT ...) UNION (SELECT ...)
1913
+ * console.log(result.parameters); // [...leftParams, ...rightParams]
1914
+ * ```
1915
+ */
1916
+ declare function compileSetOperation(intent: SetOperationIntent, compileFn: LeafCompileFn): SetOperationResult;
1917
+ /**
1918
+ * Create a leaf compile function from adapter + model + capabilities.
1919
+ *
1920
+ * Convenience factory for the common case where you have a PgsqlAdapter
1921
+ * and need a compileFn for `compileSetOperation`.
1922
+ *
1923
+ * @param adapter - Adapter with compile() and dialectCapabilities
1924
+ * @param model - ModelIR schema
1925
+ * @param planFn - The plan() function from @dbsp/core
1926
+ */
1927
+ declare function createLeafCompileFn(adapter: {
1928
+ compile(plan: PlanReport, options: {
1929
+ model: ModelIR$1;
1930
+ }): {
1931
+ sql: string;
1932
+ parameters: readonly unknown[];
1933
+ };
1934
+ dialectCapabilities: DialectCapabilities;
1935
+ }, model: ModelIR$1, planFn: (intent: QueryIntent, model: ModelIR$1, options: {
1936
+ dialectCapabilities: DialectCapabilities;
1937
+ }) => PlanReport): LeafCompileFn;
1938
+
1939
+ /**
1940
+ * Cursor-Based Streaming Support
1941
+ *
1942
+ * Generates PostgreSQL cursor statements for streaming large result sets.
1943
+ * Supports:
1944
+ * - DECLARE CURSOR
1945
+ * - FETCH (forward, backward, all)
1946
+ * - CLOSE CURSOR
1947
+ *
1948
+ * Note: This generates AST nodes for cursor operations.
1949
+ * Actual cursor execution requires a transaction context.
1950
+ */
1951
+
1952
+ /**
1953
+ * Cursor scroll options.
1954
+ */
1955
+ type CursorScrollOption = 'scroll' | 'no_scroll';
1956
+ /**
1957
+ * Cursor hold option (whether cursor survives transaction commit).
1958
+ */
1959
+ type CursorHoldOption = 'with_hold' | 'without_hold';
1960
+ /**
1961
+ * Fetch direction for cursor.
1962
+ */
1963
+ type FetchDirection = 'next' | 'prior' | 'first' | 'last' | 'absolute' | 'relative' | 'forward' | 'backward' | 'forward_all' | 'backward_all';
1964
+ /**
1965
+ * Options for DECLARE CURSOR.
1966
+ */
1967
+ interface CursorOptions {
1968
+ /** Cursor name */
1969
+ name: string;
1970
+ /** The query to execute */
1971
+ query: Node;
1972
+ /** Scroll option (default: no_scroll) */
1973
+ scroll?: CursorScrollOption;
1974
+ /** Hold option (default: without_hold) */
1975
+ hold?: CursorHoldOption;
1976
+ /** Binary output (rarely used) */
1977
+ binary?: boolean;
1978
+ }
1979
+ /**
1980
+ * Options for FETCH.
1981
+ */
1982
+ interface FetchOptions {
1983
+ /** Cursor name */
1984
+ cursorName: string;
1985
+ /** Fetch direction */
1986
+ direction?: FetchDirection;
1987
+ /** Number of rows to fetch (for forward/backward) */
1988
+ count?: number;
1989
+ }
1990
+ /**
1991
+ * Build a DECLARE CURSOR statement.
1992
+ *
1993
+ * @param options - Cursor declaration options
1994
+ * @returns DeclareCursorStmt AST node
1995
+ *
1996
+ * @example
1997
+ * ```typescript
1998
+ * const selectAst = { SelectStmt: { ... } };
1999
+ * const cursorAst = buildDeclareCursor({
2000
+ * name: 'my_cursor',
2001
+ * query: selectAst,
2002
+ * scroll: 'no_scroll',
2003
+ * hold: 'without_hold'
2004
+ * });
2005
+ * // Produces: DECLARE my_cursor NO SCROLL CURSOR WITHOUT HOLD FOR SELECT ...
2006
+ * ```
2007
+ */
2008
+ declare function buildDeclareCursor(options: CursorOptions): Node;
2009
+ /**
2010
+ * Build a FETCH statement.
2011
+ *
2012
+ * @param options - Fetch options
2013
+ * @returns FetchStmt AST node
2014
+ *
2015
+ * @example
2016
+ * ```typescript
2017
+ * const fetchAst = buildFetch({
2018
+ * cursorName: 'my_cursor',
2019
+ * direction: 'forward',
2020
+ * count: 100
2021
+ * });
2022
+ * // Produces: FETCH FORWARD 100 FROM my_cursor
2023
+ * ```
2024
+ */
2025
+ declare function buildFetch(options: FetchOptions): Node;
2026
+ /**
2027
+ * Build a CLOSE cursor statement.
2028
+ *
2029
+ * @param cursorName - Name of cursor to close (or '*' for all)
2030
+ * @returns ClosePortalStmt AST node
2031
+ */
2032
+ declare function buildCloseCursor(cursorName: string): Node;
2033
+ /**
2034
+ * Build FETCH NEXT (single row).
2035
+ */
2036
+ declare function buildFetchNext(cursorName: string): Node;
2037
+ /**
2038
+ * Build FETCH FORWARD N (multiple rows).
2039
+ */
2040
+ declare function buildFetchForward(cursorName: string, count: number): Node;
2041
+ /**
2042
+ * Build FETCH ALL (remaining rows).
2043
+ */
2044
+ declare function buildFetchAll(cursorName: string): Node;
2045
+ /**
2046
+ * Build FETCH FIRST (move to start and get first row).
2047
+ */
2048
+ declare function buildFetchFirst(cursorName: string): Node;
2049
+ /**
2050
+ * Configuration for streaming query execution.
2051
+ */
2052
+ interface StreamConfig {
2053
+ /** Cursor name prefix (will be appended with unique ID) */
2054
+ cursorPrefix?: string;
2055
+ /** Batch size for each fetch (default: 100) */
2056
+ batchSize?: number;
2057
+ /** Whether cursor should survive transaction (default: false) */
2058
+ withHold?: boolean;
2059
+ }
2060
+ /**
2061
+ * Generate a unique cursor name.
2062
+ *
2063
+ * @param prefix - Cursor name prefix
2064
+ * @returns Unique cursor name
2065
+ */
2066
+ declare function generateCursorName(prefix?: string): string;
2067
+ /**
2068
+ * Build all statements needed for streaming query execution.
2069
+ *
2070
+ * @param query - The SELECT query to stream
2071
+ * @param config - Streaming configuration
2072
+ * @returns Object with cursor name and statement builders
2073
+ *
2074
+ * @example
2075
+ * ```typescript
2076
+ * const { cursorName, declare, fetchBatch, close } = buildStreamingStatements(
2077
+ * selectAst,
2078
+ * { batchSize: 100 }
2079
+ * );
2080
+ *
2081
+ * // In transaction:
2082
+ * // 1. Execute declare
2083
+ * // 2. Loop: execute fetchBatch, process rows, until empty
2084
+ * // 3. Execute close
2085
+ * ```
2086
+ */
2087
+ declare function buildStreamingStatements(query: Node, config?: StreamConfig): {
2088
+ cursorName: string;
2089
+ declare: Node;
2090
+ fetchBatch: Node;
2091
+ fetchAll: Node;
2092
+ close: Node;
2093
+ };
2094
+
2095
+ /**
2096
+ * Identifier Validation for adapter-pgsql
2097
+ *
2098
+ * Security layer to prevent SQL injection via identifiers.
2099
+ * All table names, column names, schema names, and aliases MUST pass validation.
2100
+ */
2101
+ /**
2102
+ * Error thrown when an identifier fails validation.
2103
+ */
2104
+ declare class InvalidIdentifierError extends Error {
2105
+ readonly identifier: string;
2106
+ readonly identifierType: string;
2107
+ readonly reason: string;
2108
+ constructor(identifier: string, identifierType: string, reason: string);
2109
+ }
2110
+ /**
2111
+ * Validate that a string is a safe SQL identifier.
2112
+ *
2113
+ * Rules:
2114
+ * 1. Must not be empty
2115
+ * 2. Must not exceed 63 characters (PostgreSQL limit)
2116
+ * 3. Must start with letter or underscore
2117
+ * 4. Must contain only alphanumeric, underscore, or dollar sign
2118
+ * 5. Must not contain null bytes or control characters
2119
+ * 6. Reserved keywords are allowed (will be quoted)
2120
+ *
2121
+ * @param value The identifier to validate
2122
+ * @param type Type of identifier (for error messages): 'table', 'column', 'schema', 'alias'
2123
+ * @throws InvalidIdentifierError if validation fails
2124
+ */
2125
+ declare function validateIdentifier(value: string, type: 'table' | 'column' | 'schema' | 'alias'): void;
2126
+ /**
2127
+ * Check if an identifier is a SQL reserved keyword.
2128
+ */
2129
+ declare function isReservedKeyword(value: string): boolean;
2130
+ /**
2131
+ * Validate a schema-qualified identifier (schema.table).
2132
+ *
2133
+ * @param schemaTable String in format "schema.table" or just "table"
2134
+ * @returns Object with validated schema and table names
2135
+ * @throws InvalidIdentifierError if validation fails
2136
+ */
2137
+ declare function validateQualifiedIdentifier(schemaTable: string): {
2138
+ schema?: string;
2139
+ table: string;
2140
+ };
2141
+ /**
2142
+ * Batch validate multiple identifiers.
2143
+ *
2144
+ * @param identifiers Map of identifier values to their types
2145
+ * @throws InvalidIdentifierError on first validation failure
2146
+ */
2147
+ declare function validateIdentifiers(identifiers: Record<string, 'table' | 'column' | 'schema' | 'alias'>): void;
2148
+ /**
2149
+ * Sanitize an identifier for safe logging/display.
2150
+ * NOT for use in SQL - use validateIdentifier + AST helpers for that.
2151
+ */
2152
+ declare function sanitizeForDisplay(value: string): string;
2153
+
2154
+ 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, acquireMigrationLock, bm25Search, booleanSearch, boost, buildCloseCursor, buildDeclareCursor, buildExplain, buildExplainAnalyzeJson, buildExplainPlan, buildExplainVerbose, buildFetch, buildFetchAll, buildFetchFirst, buildFetchForward, buildFetchNext, buildOnConflictClause, buildStreamingStatements, camelCaseNaming, collectAndValidateParamRefs, compareSchemata, compileDelete, compileInsert, compileMutation, compilePlan, compileSetOperation, compileUpdate, compileUpsert, conditionalUpdate, cosineDistance, createAnyExpr, createEqualityExpr, createLeafCompileFn, createParamRef, createPgsqlAdapter, createPgsqlCompileOnlyAdapter, createTypeCastParamRef, defaultFkDerivation, ensureMigrationsTable, excludedRef, 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, releaseMigrationLock, removeMigrationRecord, resolveLogicalName, sanitizeForDisplay, score, validateIdentifier, validateIdentifiers, validateParamRef, validateQualifiedIdentifier, vectorDims, withMigrationLock };