@dbsp/types 1.0.1 → 1.0.2
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/{chunk-5L5N5N5J.js → chunk-5WW2KG3P.js} +7 -19
- package/dist/chunk-5WW2KG3P.js.map +1 -0
- package/dist/index.d.ts +202 -60
- package/dist/index.js +1 -3
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +1 -3
- package/package.json +1 -1
- package/dist/chunk-5L5N5N5J.js.map +0 -1
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
// src/adapter.ts
|
|
2
|
-
var UnsupportedFeatureError = class extends Error {
|
|
3
|
-
constructor(feature, adapter, element) {
|
|
4
|
-
super(
|
|
5
|
-
`Unsupported feature "${feature}" on adapter "${adapter}" for "${element}"`
|
|
6
|
-
);
|
|
7
|
-
this.feature = feature;
|
|
8
|
-
this.adapter = adapter;
|
|
9
|
-
this.element = element;
|
|
10
|
-
this.name = "UnsupportedFeatureError";
|
|
11
|
-
}
|
|
12
|
-
feature;
|
|
13
|
-
adapter;
|
|
14
|
-
element;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
1
|
// src/intent/recursive-intent.ts
|
|
18
2
|
function getNodeIdAlias(expr) {
|
|
19
3
|
if (expr.as) return expr.as;
|
|
@@ -129,7 +113,7 @@ function isUpsertIntent(intent) {
|
|
|
129
113
|
return intent.type === "upsert";
|
|
130
114
|
}
|
|
131
115
|
function isMutationIntent(intent) {
|
|
132
|
-
return intent.type === "insert" || intent.type === "update" || intent.type === "delete" || intent.type === "upsert";
|
|
116
|
+
return intent.type === "insert" || intent.type === "insert_from" || intent.type === "upsert_from" || intent.type === "update" || intent.type === "batchUpdate" || intent.type === "delete" || intent.type === "upsert";
|
|
133
117
|
}
|
|
134
118
|
|
|
135
119
|
// src/intent/where-intent.ts
|
|
@@ -146,11 +130,15 @@ function isValidSchema(schema) {
|
|
|
146
130
|
if (typeof s.model !== "object" || s.model === null) return false;
|
|
147
131
|
if (!("tables" in s.model) || !("relations" in s.model)) return false;
|
|
148
132
|
if (!Array.isArray(s.tableNames)) return false;
|
|
133
|
+
if (typeof s.model.getTable !== "function") return false;
|
|
134
|
+
if (typeof s.model.getRelation !== "function") return false;
|
|
135
|
+
if (typeof s.model.getRelationsFrom !== "function") return false;
|
|
136
|
+
if (typeof s.model.getRelationsTo !== "function") return false;
|
|
137
|
+
if (typeof s.model.isAmbiguous !== "function") return false;
|
|
149
138
|
return true;
|
|
150
139
|
}
|
|
151
140
|
|
|
152
141
|
export {
|
|
153
|
-
UnsupportedFeatureError,
|
|
154
142
|
getNodeIdAlias,
|
|
155
143
|
isWindowIntent,
|
|
156
144
|
isAggregateWindowFunction,
|
|
@@ -191,4 +179,4 @@ export {
|
|
|
191
179
|
isFieldRef,
|
|
192
180
|
isValidSchema
|
|
193
181
|
};
|
|
194
|
-
//# sourceMappingURL=chunk-
|
|
182
|
+
//# sourceMappingURL=chunk-5WW2KG3P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/intent/recursive-intent.ts","../src/intent/type-guards.ts","../src/intent/where-intent.ts","../src/loaded-schema.ts"],"sourcesContent":["/**\n * @module intent/recursive-intent\n * Recursive CTE intent types for hierarchical data traversal (RFC-001).\n */\n\nimport type { OrderByIntent } from './include-intent.js';\nimport type { WhereIntent } from './where-intent.js';\n\n// ============================================================================\n// Recursive CTE Intent - Hierarchical Data Traversal (RFC-001)\n// ============================================================================\n\n/**\n * Node ID expression for recursive CTE anchor.\n * Used to define the join key for recursive traversal.\n */\nexport type RecursiveNodeIdExpr =\n\t| { readonly kind: 'column'; readonly name: string; readonly as?: string }\n\t| {\n\t\t\treadonly kind: 'literal';\n\t\t\treadonly value: unknown;\n\t\t\treadonly as?: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'binary';\n\t\t\treadonly left: RecursiveNodeIdExpr;\n\t\t\treadonly op: string;\n\t\t\treadonly right: RecursiveNodeIdExpr;\n\t\t\treadonly as?: string;\n\t };\n\n/**\n * Get the alias for a node ID expression.\n * Used by both planner and compiler for consistent CTE column naming.\n *\n * @param expr - The node ID expression\n * @returns The alias to use (explicit alias, column name, or 'node_id' fallback)\n */\nexport function getNodeIdAlias(expr: RecursiveNodeIdExpr): string {\n\tif (expr.as) return expr.as;\n\tif (expr.kind === 'column') return expr.name;\n\tif (expr.kind === 'literal') return 'node_id';\n\t// Binary expression needs explicit alias\n\treturn 'node_id';\n}\n\n/**\n * Adjacency-list traversal (self-referential table).\n * Example: roles.parent_id → roles.id\n */\nexport interface AdjacencyTraversal {\n\treadonly kind: 'adjacency';\n\n\t/** Table containing hierarchical data */\n\treadonly nodeTable: string;\n\n\t/** Primary key column (e.g., \"id\") */\n\treadonly nodeId: string;\n\n\t/** Foreign key pointing to parent (e.g., \"parent_id\") */\n\treadonly parentId: string;\n\n\t/** Traversal direction */\n\treadonly direction: 'descendants' | 'ancestors';\n\n\t/** Filter applied to each step (e.g., active = true) */\n\treadonly stepWhere?: WhereIntent;\n}\n\n/**\n * Edge-table traversal (separate join table).\n * Example: role_inheritance(from_role_id, to_role_id)\n */\nexport interface EdgeTableTraversal {\n\treadonly kind: 'edge-table';\n\n\t/** Node table containing hierarchical data */\n\treadonly nodeTable: string;\n\n\t/** Edge table containing relationships */\n\treadonly edgeTable: string;\n\n\t/** Primary key column in node table (e.g., \"id\") */\n\treadonly nodeId: string;\n\n\t/** Source column in edge table (e.g., \"from_role_id\") */\n\treadonly edgeFrom: string;\n\n\t/** Target column in edge table (e.g., \"to_role_id\") */\n\treadonly edgeTo: string;\n\n\t/** Traversal direction */\n\treadonly direction: 'out' | 'in' | 'both';\n\n\t/** Filter on edges (e.g., relationship_type = 'inheritance') */\n\treadonly edgeWhere?: WhereIntent;\n\n\t/** Filter on nodes (e.g., active = true) */\n\treadonly nodeWhere?: WhereIntent;\n\n\t/** Edge attributes to include in result */\n\treadonly edgeSelect?: readonly string[];\n\n\t/**\n\t * Hint for edge storage semantics (only affects `direction: 'both'`).\n\t *\n\t * - 'unknown' (default): Edges may exist in both directions (A→B and B→A).\n\t * Uses UNION (distinct) to avoid duplicates. Safe but slower.\n\t * - 'directed-only': Caller guarantees edges are stored once only.\n\t * Uses UNION ALL for performance. INCORRECT if duplicates exist.\n\t */\n\treadonly edgeStorageHint?: 'unknown' | 'directed-only';\n}\n\n/**\n * Custom traversal for complex cases (P2 escape hatch).\n */\nexport interface CustomTraversal {\n\treadonly kind: 'custom';\n\t/** Explicit step query builder - reserved for P2 */\n\treadonly stepBuilder?: unknown;\n}\n\n/**\n * Recursive traversal type union.\n */\nexport type RecursiveTraversal =\n\t| AdjacencyTraversal\n\t| EdgeTableTraversal\n\t| CustomTraversal;\n\n/**\n * Tracking options for recursive traversal.\n */\nexport interface RecursiveTrackOptions {\n\t/** Depth counter (starts at 0) */\n\treadonly depth?: {\n\t\treadonly as?: string; // Default: \"depth\"\n\t};\n\n\t/** Path tracking for cycle detection + debugging */\n\treadonly path?: {\n\t\t/** Columns to trace in path (default: nodeId only) */\n\t\treadonly by?: 'nodeId' | readonly string[];\n\t\t/** Result column name (default: \"path\") */\n\t\treadonly as?: string;\n\t\t/** Storage strategy (default: 'array' for PostgreSQL, 'string' for others) */\n\t\treadonly strategy?: 'array' | 'string';\n\t\t/** Separator for string strategy (default: '/') */\n\t\treadonly separator?: string;\n\t};\n\n\t/** Cycle detection marker */\n\treadonly isCycle?: {\n\t\treadonly as?: string; // Default: \"is_cycle\"\n\t};\n}\n\n/**\n * Join clause for CTE emit composition.\n * Allows joining the CTE result with additional tables for final projection.\n */\nexport interface EmitJoinClause {\n\t/** Table to join with */\n\treadonly table: string;\n\n\t/** Join type (default: 'inner') */\n\treadonly type?: 'inner' | 'left';\n\n\t/** Alias for this table (auto-generated if not provided) */\n\treadonly as?: string;\n\n\t/** Join condition */\n\treadonly on: {\n\t\t/** Column from CTE or previous joined table */\n\t\treadonly left: string;\n\t\t/** Column from this table */\n\t\treadonly right: string;\n\t};\n\n\t/** Columns to select from this table */\n\treadonly select?: readonly (\n\t\t| string\n\t\t| { readonly column: string; readonly as: string }\n\t)[];\n}\n\n/**\n * Emit options for recursive CTE final projection.\n */\nexport interface RecursiveEmitOptions {\n\t/** Fields to select from CTE */\n\treadonly select?: readonly string[];\n\t/** Filter on generated rows */\n\treadonly where?: WhereIntent;\n\t/** Ordering */\n\treadonly orderBy?: readonly OrderByIntent[];\n\t/** Join CTE result with additional tables for composition */\n\treadonly joinWith?: readonly EmitJoinClause[];\n\t/** Apply DISTINCT to final result */\n\treadonly distinct?: boolean;\n}\n\n/**\n * PostgreSQL-specific options for recursive CTE (capability-gated).\n */\nexport interface RecursiveAdvancedOptions {\n\t/**\n\t * Cycle detection strategy (adapter-specific implementation).\n\t * - 'error': Throw on cycle detection\n\t * - 'stop': Stop traversal at cycle (prune branch)\n\t * - 'mark': Add is_cycle column to results\n\t *\n\t * PostgreSQL 14+ uses native CYCLE clause.\n\t * Other adapters may use application-level detection.\n\t */\n\treadonly cycle?: 'error' | 'stop' | 'mark';\n\n\t/**\n\t * Traversal search order (adapter-specific implementation).\n\t * - 'depth': Depth-first search order\n\t * - 'breadth': Breadth-first search order\n\t *\n\t * PostgreSQL 14+ uses native SEARCH clause.\n\t * Other adapters may use ORDER BY on depth column.\n\t */\n\treadonly search?: 'depth' | 'breadth';\n}\n\n/**\n * Deduplication strategy for recursive CTE.\n *\n * - 'none': No dedup. May return same node multiple times via different paths.\n * Fastest. Use when you need all paths or when graph is known to be a tree.\n *\n * - 'final': One row per nodeId in final output.\n * Implemented via `DISTINCT ON (nodeId)` (PostgreSQL) or\n * `ROW_NUMBER() OVER (PARTITION BY nodeId)` fallback.\n * ⚠️ NOT the same as `query.distinct()` which dedupes on entire row!\n *\n * Note: 'global' (UNION instead of UNION ALL) was considered but not implemented.\n * 'final' provides the same end result with better performance characteristics.\n */\nexport type RecursiveDedupe = 'none' | 'final';\n\n/**\n * Recursive CTE intent for hierarchical data traversal.\n *\n * Key invariant: anchor and step MUST produce identical column shape.\n * The planner validates this and auto-injects nodeIdExpr.\n *\n * @see RFC-001 for detailed specification\n */\nexport interface RecursiveIntent {\n\treadonly type: 'recursive';\n\n\t/** CTE name for the recursive query */\n\treadonly cteName: string;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// START (anchor/seed)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\treadonly start: {\n\t\t/** Source table for anchor query */\n\t\treadonly from: string;\n\n\t\t/** Filter for seed rows (e.g., where id = $userId) */\n\t\treadonly where?: WhereIntent;\n\n\t\t/**\n\t\t * REQUIRED: Expression for node ID. Auto-injected into select.\n\t\t * This ensures the recursive join always has the key column.\n\t\t */\n\t\treadonly nodeIdExpr: RecursiveNodeIdExpr;\n\n\t\t/** Additional fields to select (beyond nodeId) */\n\t\treadonly select?: readonly string[];\n\t};\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// TRAVERSAL\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Traversal configuration (adjacency-list or edge-table) */\n\treadonly traversal: RecursiveTraversal;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// TRACKING (system columns)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Tracking options for depth, path, and cycle detection */\n\treadonly track?: RecursiveTrackOptions;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// SAFETY\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Maximum recursion depth (REQUIRED) */\n\treadonly maxDepth: number;\n\n\t/** Maximum rows (optional safety limit) */\n\treadonly maxRows?: number;\n\n\t/** Deduplication strategy */\n\treadonly dedupe?: RecursiveDedupe;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// EMIT (final projection)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Final projection options */\n\treadonly emit?: RecursiveEmitOptions;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// ADVANCED OPTIONS (capability-gated, adapter-specific implementation)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Advanced recursive options (cycle detection, search order) */\n\treadonly advancedOptions?: RecursiveAdvancedOptions;\n}\n","/**\n * @module intent/type-guards\n * Type guard functions for all intent AST types.\n */\n\nimport type {\n\tAggregateWindowFunction,\n\tCoalesceExpressionIntent,\n\tColumnAliasIntent,\n\tExpressionIntent,\n\tOffsetWindowFunction,\n\tRankingWindowFunction,\n\tRawExpressionIntent,\n\tRelationColumnIntent,\n\tWindowFunction,\n\tWindowIntent,\n} from './expression-intent.js';\nimport type {\n\tDeleteIntent,\n\tInsertIntent,\n\tMutationIntent,\n\tUpdateIntent,\n\tUpsertIntent,\n} from './mutation-intent.js';\nimport type { QueryIntent } from './query-intent.js';\nimport type {\n\tAdjacencyTraversal,\n\tCustomTraversal,\n\tEdgeTableTraversal,\n\tRecursiveIntent,\n\tRecursiveTraversal,\n} from './recursive-intent.js';\nimport type {\n\tSelectAggregateIntent,\n\tSelectAllIntent,\n\tSelectFieldsIntent,\n\tSelectIntent,\n\tSelectWithExpressionsIntent,\n} from './select-intent.js';\nimport type {\n\tSubqueryRefIntent,\n\tWhereAndIntent,\n\tWhereAnyIntent,\n\tWhereComparisonIntent,\n\tWhereExistsIntent,\n\tWhereInIntent,\n\tWhereIntent,\n\tWhereLikeIntent,\n\tWhereNotExistsIntent,\n\tWhereNotIntent,\n\tWhereNullIntent,\n\tWhereOrIntent,\n\tWhereRangeIntent,\n\tWhereRelationFilterIntent,\n\tWhereSubqueryIntent,\n} from './where-intent.js';\n\n// ============================================================================\n// Window Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an intent is a window function intent\n */\nexport function isWindowIntent(intent: unknown): intent is WindowIntent {\n\treturn (\n\t\ttypeof intent === 'object' &&\n\t\tintent !== null &&\n\t\t'kind' in intent &&\n\t\t(intent as Record<string, unknown>).kind === 'window'\n\t);\n}\n\n/**\n * Check if a window function requires a field (aggregate or offset functions)\n */\nexport function isAggregateWindowFunction(\n\tfn: WindowFunction,\n): fn is AggregateWindowFunction | OffsetWindowFunction {\n\treturn ['sum', 'avg', 'count', 'min', 'max', 'lag', 'lead'].includes(fn);\n}\n\n/**\n * Check if a window function is a ranking function (no field required)\n */\nexport function isRankingWindowFunction(\n\tfn: WindowFunction,\n): fn is RankingWindowFunction {\n\treturn ['row_number', 'rank', 'dense_rank'].includes(fn);\n}\n\n// ============================================================================\n// Where Intent Type Guards\n// ============================================================================\n\n/**\n * Check if a where intent is a comparison\n */\nexport function isWhereComparison(\n\twhere: WhereIntent,\n): where is WhereComparisonIntent {\n\treturn where.kind === 'comparison';\n}\n\n/**\n * Check if a where intent is a like filter\n */\nexport function isWhereLike(where: WhereIntent): where is WhereLikeIntent {\n\treturn where.kind === 'like';\n}\n\n/**\n * Check if a where intent is a subquery filter\n */\nexport function isWhereSubquery(\n\twhere: WhereIntent,\n): where is WhereSubqueryIntent {\n\treturn where.kind === 'subquery';\n}\n\n/**\n * Check if a value is a subquery ref (column reference in subquery)\n */\nexport function isSubqueryRef(value: unknown): value is SubqueryRefIntent {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'kind' in value &&\n\t\t(value as Record<string, unknown>).kind === 'ref'\n\t);\n}\n\n/**\n * Check if a where intent is an in filter\n */\nexport function isWhereIn(where: WhereIntent): where is WhereInIntent {\n\treturn where.kind === 'in';\n}\n\n/**\n * Check if a where intent is an any filter (= ANY($N::type[]))\n */\nexport function isWhereAny(where: WhereIntent): where is WhereAnyIntent {\n\treturn where.kind === 'any';\n}\n\n/**\n * Check if a where intent is a null filter\n */\nexport function isWhereNull(where: WhereIntent): where is WhereNullIntent {\n\treturn where.kind === 'null';\n}\n\n/**\n * Check if a where intent is a range filter (PostgreSQL range types)\n */\nexport function isWhereRange(where: WhereIntent): where is WhereRangeIntent {\n\treturn where.kind === 'range';\n}\n\n/**\n * Check if a where intent is a logical AND\n */\nexport function isWhereAnd(where: WhereIntent): where is WhereAndIntent {\n\treturn where.kind === 'and';\n}\n\n/**\n * Check if a where intent is a logical OR\n */\nexport function isWhereOr(where: WhereIntent): where is WhereOrIntent {\n\treturn where.kind === 'or';\n}\n\n/**\n * Check if a where intent is a logical NOT\n */\nexport function isWhereNot(where: WhereIntent): where is WhereNotIntent {\n\treturn where.kind === 'not';\n}\n\n/**\n * Check if a where intent is an exists filter\n */\nexport function isWhereExists(where: WhereIntent): where is WhereExistsIntent {\n\treturn where.kind === 'exists';\n}\n\n/**\n * Check if a where intent is a not exists filter\n */\nexport function isWhereNotExists(\n\twhere: WhereIntent,\n): where is WhereNotExistsIntent {\n\treturn where.kind === 'notExists';\n}\n\n/**\n * Check if a where intent is a relation filter\n */\nexport function isWhereRelationFilter(\n\twhere: WhereIntent,\n): where is WhereRelationFilterIntent {\n\treturn where.kind === 'relationFilter';\n}\n\n/**\n * Check if a where intent is any relation-based filter\n */\nexport function isWhereRelationBased(\n\twhere: WhereIntent,\n): where is\n\t| WhereExistsIntent\n\t| WhereNotExistsIntent\n\t| WhereRelationFilterIntent {\n\treturn (\n\t\twhere.kind === 'exists' ||\n\t\twhere.kind === 'notExists' ||\n\t\twhere.kind === 'relationFilter'\n\t);\n}\n\n/**\n * Check if a where intent is a logical operator (and/or/not)\n */\nexport function isWhereLogical(\n\twhere: WhereIntent,\n): where is WhereAndIntent | WhereOrIntent | WhereNotIntent {\n\treturn where.kind === 'and' || where.kind === 'or' || where.kind === 'not';\n}\n\n// ============================================================================\n// Select Intent Type Guards\n// ============================================================================\n\n/**\n * Check if a select intent selects all columns\n */\nexport function isSelectAll(select: SelectIntent): select is SelectAllIntent {\n\treturn select.type === 'all';\n}\n\n/**\n * Check if a select intent selects specific fields\n */\nexport function isSelectFields(\n\tselect: SelectIntent,\n): select is SelectFieldsIntent {\n\treturn select.type === 'fields';\n}\n\n/**\n * Check if a select intent is an aggregate select\n */\nexport function isSelectAggregate(\n\tselect: SelectIntent,\n): select is SelectAggregateIntent {\n\treturn select.type === 'aggregate';\n}\n\n/**\n * Check if a select intent has expressions\n */\nexport function isSelectWithExpressions(\n\tselect: SelectIntent,\n): select is SelectWithExpressionsIntent {\n\treturn select.type === 'expressions';\n}\n\n// ============================================================================\n// Expression Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an expression is a COALESCE expression\n */\nexport function isCoalesceExpression(\n\texpr: ExpressionIntent,\n): expr is CoalesceExpressionIntent {\n\treturn expr.kind === 'coalesce';\n}\n\n/**\n * Check if an expression is a raw SQL expression\n */\nexport function isRawExpression(\n\texpr: ExpressionIntent,\n): expr is RawExpressionIntent {\n\treturn expr.kind === 'raw';\n}\n\n/**\n * Check if an expression is a column alias expression\n */\nexport function isColumnAliasExpression(\n\texpr: ExpressionIntent,\n): expr is ColumnAliasIntent {\n\treturn expr.kind === 'columnAlias';\n}\n\n/**\n * Check if an expression is a relation column expression\n */\nexport function isRelationColumnExpression(\n\texpr: ExpressionIntent,\n): expr is RelationColumnIntent {\n\treturn expr.kind === 'relationColumn';\n}\n\n// ============================================================================\n// Recursive CTE Type Guards\n// ============================================================================\n\n/**\n * Check if a traversal is adjacency-list based\n */\nexport function isAdjacencyTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is AdjacencyTraversal {\n\treturn traversal.kind === 'adjacency';\n}\n\n/**\n * Check if a traversal is edge-table based\n */\nexport function isEdgeTableTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is EdgeTableTraversal {\n\treturn traversal.kind === 'edge-table';\n}\n\n/**\n * Check if a traversal is custom\n */\nexport function isCustomTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is CustomTraversal {\n\treturn traversal.kind === 'custom';\n}\n\n/**\n * Check if an intent is a recursive CTE intent\n */\nexport function isRecursiveIntent(\n\tintent: QueryIntent | RecursiveIntent,\n): intent is RecursiveIntent {\n\treturn intent.type === 'recursive';\n}\n\n// ============================================================================\n// Mutation Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an intent is an insert intent\n */\nexport function isInsertIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is InsertIntent {\n\treturn intent.type === 'insert';\n}\n\n/**\n * Check if an intent is an update intent\n */\nexport function isUpdateIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is UpdateIntent {\n\treturn intent.type === 'update';\n}\n\n/**\n * Check if an intent is a delete intent\n */\nexport function isDeleteIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is DeleteIntent {\n\treturn intent.type === 'delete';\n}\n\n/**\n * Check if an intent is an upsert intent (DX-026)\n */\nexport function isUpsertIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is UpsertIntent {\n\treturn intent.type === 'upsert';\n}\n\n/**\n * Check if an intent is any mutation intent\n */\nexport function isMutationIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is MutationIntent {\n\treturn (\n\t\tintent.type === 'insert' ||\n\t\tintent.type === 'insert_from' ||\n\t\tintent.type === 'upsert_from' ||\n\t\tintent.type === 'update' ||\n\t\tintent.type === 'batchUpdate' ||\n\t\tintent.type === 'delete' ||\n\t\tintent.type === 'upsert'\n\t);\n}\n","/**\n * @module intent/where-intent\n * Where intent types for filter conditions.\n */\n\nimport type { RangeValue } from '../shared/utils.js';\nimport type { ExpressionIntent } from './expression-intent.js';\nimport type { ComparisonOperator, NullOperator } from './operators.js';\nimport type { QueryIntent } from './query-intent.js';\nimport type { RecursiveExistsOptions } from './recursive-types.js';\n\nexport type { RangeValue };\n\n// ============================================================================\n// Where Intent - Filter Conditions\n// ============================================================================\n\n/**\n * Typed field reference for cross-table column comparisons in relation filters.\n *\n * When using aliased relation filters like `some(orders as o, o.total > minOrder)`,\n * the RHS `minOrder` is a reference to the parent table's column, not a literal value.\n * FieldRef captures this distinction so the adapter can compile it as a column reference\n * instead of a parameterized value.\n *\n * @example\n * // some(rel as r, r.col > bareCol) → value: { kind: 'fieldRef', column: 'bareCol', scope: 'outer' }\n * // some(rel as r, r.col > r.otherCol) → value: { kind: 'fieldRef', column: 'otherCol', scope: 'inner' }\n * // some(a as x, some(b as y, y.f > x.g)) → value: { kind: 'fieldRef', column: 'g', scope: 'outer', alias: 'x' }\n */\nexport interface FieldRef {\n\treadonly kind: 'fieldRef';\n\treadonly column: string;\n\treadonly scope: 'inner' | 'outer';\n\t/** Named alias for outer scope (when referencing a specific outer alias in nested filters) */\n\treadonly alias?: string;\n}\n\n/**\n * Type guard for FieldRef values\n */\nexport function isFieldRef(value: unknown): value is FieldRef {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === 'object' &&\n\t\t(value as Record<string, unknown>).kind === 'fieldRef'\n\t);\n}\n\nexport interface WhereComparisonIntent {\n\treadonly kind: 'comparison';\n\treadonly field: string;\n\treadonly operator: ComparisonOperator;\n\treadonly value: unknown;\n\t/** JSON path extraction before comparison (e.g., data->'key' = 'val') */\n\treadonly jsonPath?: readonly string[];\n\t/** JSON extraction mode: 'json' = ->, 'text' = ->> */\n\treadonly jsonMode?: 'json' | 'text';\n}\n\n/**\n * String filter: field like pattern\n */\nexport interface WhereLikeIntent {\n\treadonly kind: 'like';\n\treadonly field: string;\n\treadonly pattern: string;\n\t/** Case-insensitive matching */\n\treadonly caseInsensitive?: boolean;\n\t/** Escape character for LIKE pattern (e.g. '\\\\' to escape _ and %) */\n\treadonly escape?: string;\n}\n\n/**\n * Array filter: field in [values]\n */\n/**\n * Array filter (values branch): field IN (v1, v2, ...)\n */\nexport interface WhereInValueIntent {\n\treadonly kind: 'in';\n\treadonly field: string;\n\treadonly values: readonly unknown[];\n\treadonly subquery?: never;\n\treadonly not?: boolean;\n}\n\n/**\n * Array filter (subquery branch): field IN (SELECT ...)\n */\nexport interface WhereInSubqueryIntent {\n\treadonly kind: 'in';\n\treadonly field: string;\n\treadonly subquery: QueryIntent;\n\treadonly values?: never;\n\treadonly not?: boolean;\n}\n\n/**\n * Array filter: field in [values] OR field IN (subquery)\n * XOR: exactly one of `values` or `subquery` must be present.\n */\nexport type WhereInIntent = WhereInValueIntent | WhereInSubqueryIntent;\n\n/**\n * Array membership filter using PostgreSQL ANY() operator.\n * Compiles to: \"col\" = ANY($N::type[])\n */\nexport interface WhereAnyIntent {\n\treadonly kind: 'any';\n\treadonly field: string;\n\treadonly values: readonly unknown[];\n}\n\n/**\n * Operand accepted by range WHERE filters.\n * - RangeValue: for range-to-range operators (overlaps, contains, containedBy)\n * - string: ISO date/timestamp literals (e.g. '2025-01-15', '2025-01-15T08:00:00Z')\n * - number: integer/numeric point values (e.g. 50000 for salary_range @> 50000)\n * - boolean: rarely used but valid PostgreSQL range operand\n */\nexport type RangeOperand = RangeValue | string | number | boolean;\n\n/**\n * Range operator for PostgreSQL range types.\n * - overlaps: && (ranges have common points)\n * - contains: @> (range contains value or range)\n * - containedBy: <@ (range is contained by another range)\n */\nexport type RangeOperator = 'overlaps' | 'contains' | 'containedBy' | 'between';\n\n/**\n * Range filter: field overlaps/contains/containedBy range value\n * PostgreSQL range types: daterange, tsrange, tstzrange, int4range, int8range, numrange\n *\n * @example\n * // Check if booking dates overlap a period\n * { kind: 'range', field: 'dates', operator: 'overlaps', value: { lower: '2025-01-15', upper: '2025-01-20' } }\n *\n * // Check if salary range contains a value\n * { kind: 'range', field: 'salary_range', operator: 'contains', value: 50000 }\n */\n/**\n * Range filter: field overlaps/contains/containedBy range value\n * PostgreSQL range types: daterange, tsrange, tstzrange, int4range, int8range, numrange\n *\n * @example\n * // Check if booking dates overlap a period\n * { kind: 'range', field: 'dates', operator: 'overlaps', value: { lower: '2025-01-15', upper: '2025-01-20' } }\n *\n * // Check if salary range contains a value\n * { kind: 'range', field: 'salary_range', operator: 'contains', value: 50000 }\n */\nexport interface WhereRangeIntent {\n\treadonly kind: 'range';\n\treadonly field: string;\n\treadonly operator: RangeOperator;\n\t/** Operand: RangeValue for range-to-range ops, or a scalar (string | number | boolean) for point-in-range ops */\n\treadonly value: RangeOperand;\n}\n\n/**\n * Null filter: field is null / is not null\n */\nexport interface WhereNullIntent {\n\treadonly kind: 'null';\n\treadonly field: string;\n\treadonly operator: NullOperator;\n}\n\n/**\n * Logical AND: all conditions must match\n */\nexport interface WhereAndIntent {\n\treadonly kind: 'and';\n\treadonly conditions: readonly WhereIntent[];\n}\n\n/**\n * Logical OR: at least one condition must match\n */\nexport interface WhereOrIntent {\n\treadonly kind: 'or';\n\treadonly conditions: readonly WhereIntent[];\n}\n\n/**\n * Logical NOT: condition must not match\n */\nexport interface WhereNotIntent {\n\treadonly kind: 'not';\n\treadonly condition: WhereIntent;\n}\n\n/**\n * Relation exists filter: filter by existence of related records\n * Critical for Q1 golden test - enables EXISTS subquery strategy\n *\n * @example\n * // Find users who have at least one published post\n * { kind: 'exists', relation: 'posts', where: { kind: 'comparison', field: 'status', operator: 'eq', value: 'published' } }\n */\nexport interface WhereExistsIntent {\n\treadonly kind: 'exists';\n\t/** Relation name to check existence */\n\treadonly relation: string;\n\t/** Optional filter on related records */\n\treadonly where?: WhereIntent;\n\t/**\n\t * Recursive options for ancestor/descendant existence checks.\n\t * When present, generates a recursive CTE instead of simple EXISTS.\n\t */\n\treadonly recursive?: RecursiveExistsOptions;\n\t/**\n\t * Optional JOIN declarations inside the EXISTS subquery.\n\t * Keys are relation names (used as aliases), values specify join type.\n\t * Enables filtering on joined tables inside the subquery.\n\t *\n\t * @example\n\t * exists('callers', {\n\t * include: { callerFile: { join: 'inner' } },\n\t * where: eq('callerFile.project_id', projectId)\n\t * })\n\t */\n\treadonly include?: Readonly<Record<string, { join?: 'inner' | 'left' }>>;\n}\n\n/**\n * Relation not exists filter: filter by absence of related records\n *\n * @example\n * // Find users who have no posts\n * { kind: 'notExists', relation: 'posts' }\n */\nexport interface WhereNotExistsIntent {\n\treadonly kind: 'notExists';\n\t/** Relation name to check absence */\n\treadonly relation: string;\n\t/** Optional filter on related records */\n\treadonly where?: WhereIntent;\n\t/**\n\t * Recursive options for ancestor/descendant absence checks.\n\t * When present, generates a recursive CTE instead of simple NOT EXISTS.\n\t */\n\treadonly recursive?: RecursiveExistsOptions;\n\t/**\n\t * Optional JOIN declarations inside the NOT EXISTS subquery.\n\t * Keys are relation names (used as aliases), values specify join type.\n\t * Enables filtering on joined tables inside the subquery.\n\t *\n\t * @example\n\t * notExists('callers', {\n\t * include: { callerFile: { join: 'inner' } },\n\t * where: eq('callerFile.project_id', projectId)\n\t * })\n\t */\n\treadonly include?: Readonly<Record<string, { join?: 'inner' | 'left' }>>;\n}\n\n/**\n * Raw EXISTS subquery filter using an arbitrary QueryIntent.\n * Unlike WhereExistsIntent (which uses FK-resolved relation names),\n * this wraps a fully-specified subquery for correlated EXISTS checks.\n *\n * @example\n * // EXISTS (SELECT 1 FROM symbols WHERE symbols.id = calls.symbol_id AND ...)\n * exists(subquery('symbols').where(eq('id', ref('calls.symbol_id'))))\n */\nexport interface WhereRawExistsIntent {\n\treadonly kind: 'rawExists';\n\t/** The subquery producing rows for the EXISTS check */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Raw NOT EXISTS subquery filter using an arbitrary QueryIntent.\n *\n * @example\n * // NOT EXISTS (SELECT 1 FROM symbols WHERE ...)\n * notExists(subquery('symbols').where(...))\n */\nexport interface WhereRawNotExistsIntent {\n\treadonly kind: 'rawNotExists';\n\t/** The subquery producing rows for the NOT EXISTS check */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Relation filter: filter parent by conditions on related records\n * More flexible than exists - allows filtering by related record attributes\n *\n * @example\n * // Find users whose latest post was created in 2024\n * { kind: 'relationFilter', relation: 'posts', where: {...}, mode: 'some' }\n */\nexport interface WhereRelationFilterIntent {\n\treadonly kind: 'relationFilter';\n\t/**\n\t * Relation path for filtering.\n\t * - Single relation: 'posts' or ['posts']\n\t * - Multi-hop (SPEC-002): ['author', 'company'] for author.company traversal\n\t */\n\treadonly relation: string | readonly string[];\n\t/** Filter conditions on related records */\n\treadonly where: WhereIntent;\n\t/**\n\t * Match mode:\n\t * - 'some': At least one related record matches (default)\n\t * - 'every': All related records match\n\t * - 'none': No related records match\n\t */\n\treadonly mode: 'some' | 'every' | 'none';\n\t/** Optional alias for complex conditions (SPEC-002) */\n\treadonly alias?: string | undefined;\n}\n\n// ============================================================================\n// Subquery Intent - Scalar Subquery in WHERE\n// ============================================================================\n\n/**\n * Reference to a parent query column in a subquery.\n * Used to create correlated subqueries.\n *\n * @example\n * // Reference parent 'id' column in subquery WHERE\n * { kind: 'ref', column: 'id' }\n * { kind: 'ref', column: 't0.id' } // with alias\n */\nexport interface SubqueryRefIntent {\n\treadonly kind: 'ref';\n\t/** Column name or aliased column (e.g., 'id' or 't0.id') */\n\treadonly column: string;\n}\n\n/**\n * Subquery intent for scalar subquery comparisons.\n * Produces correlated subqueries in SQL.\n *\n * @example\n * // Find products where price equals max price of category\n * {\n * kind: 'subquery',\n * field: 'price',\n * operator: 'eq',\n * subquery: { from: 'products', select: { kind: 'aggregate', fn: 'max', field: 'price' } }\n * }\n */\nexport interface WhereSubqueryIntent {\n\treadonly kind: 'subquery';\n\t/** Field to compare on the parent query */\n\treadonly field: string;\n\t/** Comparison operator */\n\treadonly operator: ComparisonOperator;\n\t/** Subquery producing scalar value */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Scalar subquery intent - produces a single value.\n * Simplified QueryIntent for subquery context.\n */\n/** @deprecated Use QueryIntent instead — subqueries are full queries with contextual validation */\nexport type ScalarSubqueryIntent = QueryIntent;\n\n// ============================================================================\n// JSON/JSONB WHERE Intents (E13)\n// ============================================================================\n\n/**\n * JSON containment filter: col @> value or col <@ value.\n * @example { kind: 'jsonContains', field: 'data', value: '{\"active\":true}', reversed: false }\n * → WHERE \"data\" @> $1\n */\nexport interface WhereJsonContainsIntent {\n\treadonly kind: 'jsonContains';\n\treadonly field: string;\n\treadonly value: unknown;\n\t/** false = @> (field contains value), true = <@ (field contained by value) */\n\treadonly reversed: boolean;\n}\n\n/**\n * JSON key existence filter: col ? 'key'.\n * @example { kind: 'jsonExists', field: 'data', key: 'email' }\n * → WHERE \"data\" ? $1\n */\nexport interface WhereJsonExistsIntent {\n\treadonly kind: 'jsonExists';\n\treadonly field: string;\n\treadonly key: string;\n}\n\n/** WHERE clause using a custom expression with comparison */\nexport interface WhereExpressionIntent {\n\treadonly kind: 'expression';\n\treadonly expr: ExpressionIntent;\n\treadonly operator: ComparisonOperator;\n\treadonly value: unknown;\n}\n\n/**\n * Where intent - filter conditions union type\n * Discriminated union using 'kind' field\n */\nexport type WhereIntent =\n\t| WhereComparisonIntent\n\t| WhereLikeIntent\n\t| WhereInIntent\n\t| WhereAnyIntent\n\t| WhereNullIntent\n\t| WhereRangeIntent\n\t| WhereAndIntent\n\t| WhereOrIntent\n\t| WhereNotIntent\n\t| WhereExistsIntent\n\t| WhereNotExistsIntent\n\t| WhereRawExistsIntent\n\t| WhereRawNotExistsIntent\n\t| WhereRelationFilterIntent\n\t| WhereSubqueryIntent\n\t| WhereJsonContainsIntent\n\t| WhereJsonExistsIntent\n\t| WhereExpressionIntent;\n","import type { ModelIR } from './model-ir.js';\n\n/**\n * Canonical shape of a `schema()` factory result as produced by\n * `createOrm({schema: ...})` callers and consumed by tooling\n * (cli, gui sidecar, mcp-server).\n *\n * ARCH-005: Schema type from schema() function.\n * Contains the definition, pre-computed ModelIR, and table names.\n */\nexport interface LoadedSchema {\n\treadonly definition: Record<string, unknown>;\n\treadonly model: ModelIR;\n\treadonly tableNames: readonly string[];\n}\n\n/**\n * Runtime type guard for `LoadedSchema` — verifies the object has\n * `definition`, `model` (with nested `tables` + `relations`), and\n * `tableNames` as an array. Structural check only — does not validate\n * the inner values of any field.\n *\n * Type guard for ARCH-005 schema() output.\n */\nexport function isValidSchema(schema: unknown): schema is LoadedSchema {\n\tif (\n\t\ttypeof schema !== 'object' ||\n\t\tschema === null ||\n\t\t!('model' in schema) ||\n\t\t!('definition' in schema) ||\n\t\t!('tableNames' in schema)\n\t) {\n\t\treturn false;\n\t}\n\tconst s = schema as LoadedSchema;\n\tif (typeof s.model !== 'object' || s.model === null) return false;\n\tif (!('tables' in s.model) || !('relations' in s.model)) return false;\n\tif (!Array.isArray(s.tableNames)) return false;\n\t// Validate required ModelIR methods are present\n\tif (typeof s.model.getTable !== 'function') return false;\n\tif (typeof s.model.getRelation !== 'function') return false;\n\tif (typeof s.model.getRelationsFrom !== 'function') return false;\n\tif (typeof s.model.getRelationsTo !== 'function') return false;\n\tif (typeof s.model.isAmbiguous !== 'function') return false;\n\treturn true;\n}\n"],"mappings":";AAsCO,SAAS,eAAe,MAAmC;AACjE,MAAI,KAAK,GAAI,QAAO,KAAK;AACzB,MAAI,KAAK,SAAS,SAAU,QAAO,KAAK;AACxC,MAAI,KAAK,SAAS,UAAW,QAAO;AAEpC,SAAO;AACR;;;ACoBO,SAAS,eAAe,QAAyC;AACvE,SACC,OAAO,WAAW,YAClB,WAAW,QACX,UAAU,UACT,OAAmC,SAAS;AAE/C;AAKO,SAAS,0BACf,IACuD;AACvD,SAAO,CAAC,OAAO,OAAO,SAAS,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,EAAE;AACxE;AAKO,SAAS,wBACf,IAC8B;AAC9B,SAAO,CAAC,cAAc,QAAQ,YAAY,EAAE,SAAS,EAAE;AACxD;AASO,SAAS,kBACf,OACiC;AACjC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,YAAY,OAA8C;AACzE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,gBACf,OAC+B;AAC/B,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,cAAc,OAA4C;AACzE,SACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAAkC,SAAS;AAE9C;AAKO,SAAS,UAAU,OAA4C;AACrE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,YAAY,OAA8C;AACzE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,aAAa,OAA+C;AAC3E,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,UAAU,OAA4C;AACrE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,cAAc,OAAgD;AAC7E,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,iBACf,OACgC;AAChC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,sBACf,OACqC;AACrC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,qBACf,OAI4B;AAC5B,SACC,MAAM,SAAS,YACf,MAAM,SAAS,eACf,MAAM,SAAS;AAEjB;AAKO,SAAS,eACf,OAC2D;AAC3D,SAAO,MAAM,SAAS,SAAS,MAAM,SAAS,QAAQ,MAAM,SAAS;AACtE;AASO,SAAS,YAAY,QAAiD;AAC5E,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QAC+B;AAC/B,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,kBACf,QACkC;AAClC,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,wBACf,QACwC;AACxC,SAAO,OAAO,SAAS;AACxB;AASO,SAAS,qBACf,MACmC;AACnC,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,gBACf,MAC8B;AAC9B,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,wBACf,MAC4B;AAC5B,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,2BACf,MAC+B;AAC/B,SAAO,KAAK,SAAS;AACtB;AASO,SAAS,qBACf,WACkC;AAClC,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,qBACf,WACkC;AAClC,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,kBACf,WAC+B;AAC/B,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,kBACf,QAC4B;AAC5B,SAAO,OAAO,SAAS;AACxB;AASO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,iBACf,QAC2B;AAC3B,SACC,OAAO,SAAS,YAChB,OAAO,SAAS,iBAChB,OAAO,SAAS,iBAChB,OAAO,SAAS,YAChB,OAAO,SAAS,iBAChB,OAAO,SAAS,YAChB,OAAO,SAAS;AAElB;;;AC3WO,SAAS,WAAW,OAAmC;AAC7D,SACC,UAAU,QACV,OAAO,UAAU,YAChB,MAAkC,SAAS;AAE9C;;;ACvBO,SAAS,cAAc,QAAyC;AACtE,MACC,OAAO,WAAW,YAClB,WAAW,QACX,EAAE,WAAW,WACb,EAAE,gBAAgB,WAClB,EAAE,gBAAgB,SACjB;AACD,WAAO;AAAA,EACR;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,UAAU,YAAY,EAAE,UAAU,KAAM,QAAO;AAC5D,MAAI,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,OAAQ,QAAO;AAChE,MAAI,CAAC,MAAM,QAAQ,EAAE,UAAU,EAAG,QAAO;AAEzC,MAAI,OAAO,EAAE,MAAM,aAAa,WAAY,QAAO;AACnD,MAAI,OAAO,EAAE,MAAM,gBAAgB,WAAY,QAAO;AACtD,MAAI,OAAO,EAAE,MAAM,qBAAqB,WAAY,QAAO;AAC3D,MAAI,OAAO,EAAE,MAAM,mBAAmB,WAAY,QAAO;AACzD,MAAI,OAAO,EAAE,MAAM,gBAAgB,WAAY,QAAO;AACtD,SAAO;AACR;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -652,13 +652,31 @@ interface WhereLikeIntent {
|
|
|
652
652
|
/**
|
|
653
653
|
* Array filter: field in [values]
|
|
654
654
|
*/
|
|
655
|
-
|
|
655
|
+
/**
|
|
656
|
+
* Array filter (values branch): field IN (v1, v2, ...)
|
|
657
|
+
*/
|
|
658
|
+
interface WhereInValueIntent {
|
|
656
659
|
readonly kind: 'in';
|
|
657
660
|
readonly field: string;
|
|
658
661
|
readonly values: readonly unknown[];
|
|
659
|
-
|
|
660
|
-
readonly
|
|
662
|
+
readonly subquery?: never;
|
|
663
|
+
readonly not?: boolean;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Array filter (subquery branch): field IN (SELECT ...)
|
|
667
|
+
*/
|
|
668
|
+
interface WhereInSubqueryIntent {
|
|
669
|
+
readonly kind: 'in';
|
|
670
|
+
readonly field: string;
|
|
671
|
+
readonly subquery: QueryIntent;
|
|
672
|
+
readonly values?: never;
|
|
673
|
+
readonly not?: boolean;
|
|
661
674
|
}
|
|
675
|
+
/**
|
|
676
|
+
* Array filter: field in [values] OR field IN (subquery)
|
|
677
|
+
* XOR: exactly one of `values` or `subquery` must be present.
|
|
678
|
+
*/
|
|
679
|
+
type WhereInIntent = WhereInValueIntent | WhereInSubqueryIntent;
|
|
662
680
|
/**
|
|
663
681
|
* Array membership filter using PostgreSQL ANY() operator.
|
|
664
682
|
* Compiles to: "col" = ANY($N::type[])
|
|
@@ -668,6 +686,14 @@ interface WhereAnyIntent {
|
|
|
668
686
|
readonly field: string;
|
|
669
687
|
readonly values: readonly unknown[];
|
|
670
688
|
}
|
|
689
|
+
/**
|
|
690
|
+
* Operand accepted by range WHERE filters.
|
|
691
|
+
* - RangeValue: for range-to-range operators (overlaps, contains, containedBy)
|
|
692
|
+
* - string: ISO date/timestamp literals (e.g. '2025-01-15', '2025-01-15T08:00:00Z')
|
|
693
|
+
* - number: integer/numeric point values (e.g. 50000 for salary_range @> 50000)
|
|
694
|
+
* - boolean: rarely used but valid PostgreSQL range operand
|
|
695
|
+
*/
|
|
696
|
+
type RangeOperand = RangeValue | string | number | boolean;
|
|
671
697
|
/**
|
|
672
698
|
* Range operator for PostgreSQL range types.
|
|
673
699
|
* - overlaps: && (ranges have common points)
|
|
@@ -675,6 +701,17 @@ interface WhereAnyIntent {
|
|
|
675
701
|
* - containedBy: <@ (range is contained by another range)
|
|
676
702
|
*/
|
|
677
703
|
type RangeOperator = 'overlaps' | 'contains' | 'containedBy' | 'between';
|
|
704
|
+
/**
|
|
705
|
+
* Range filter: field overlaps/contains/containedBy range value
|
|
706
|
+
* PostgreSQL range types: daterange, tsrange, tstzrange, int4range, int8range, numrange
|
|
707
|
+
*
|
|
708
|
+
* @example
|
|
709
|
+
* // Check if booking dates overlap a period
|
|
710
|
+
* { kind: 'range', field: 'dates', operator: 'overlaps', value: { lower: '2025-01-15', upper: '2025-01-20' } }
|
|
711
|
+
*
|
|
712
|
+
* // Check if salary range contains a value
|
|
713
|
+
* { kind: 'range', field: 'salary_range', operator: 'contains', value: 50000 }
|
|
714
|
+
*/
|
|
678
715
|
/**
|
|
679
716
|
* Range filter: field overlaps/contains/containedBy range value
|
|
680
717
|
* PostgreSQL range types: daterange, tsrange, tstzrange, int4range, int8range, numrange
|
|
@@ -690,8 +727,8 @@ interface WhereRangeIntent {
|
|
|
690
727
|
readonly kind: 'range';
|
|
691
728
|
readonly field: string;
|
|
692
729
|
readonly operator: RangeOperator;
|
|
693
|
-
/**
|
|
694
|
-
readonly value:
|
|
730
|
+
/** Operand: RangeValue for range-to-range ops, or a scalar (string | number | boolean) for point-in-range ops */
|
|
731
|
+
readonly value: RangeOperand;
|
|
695
732
|
}
|
|
696
733
|
/**
|
|
697
734
|
* Null filter: field is null / is not null
|
|
@@ -943,10 +980,14 @@ type AggregateFunction = 'count' | 'sum' | 'avg' | 'min' | 'max' | 'array_agg' |
|
|
|
943
980
|
* @example { function: 'count' } → COUNT(*)
|
|
944
981
|
* @example { function: 'sum', field: 'price' } → SUM(price)
|
|
945
982
|
*/
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
983
|
+
/**
|
|
984
|
+
* Aggregate operation intent (count branch): COUNT(*) — field is '*', may be omitted in builders.
|
|
985
|
+
* @example { function: 'count' } → COUNT(*)
|
|
986
|
+
* @example { function: 'count', field: '*', as: 'total' } → COUNT(*) AS total
|
|
987
|
+
*/
|
|
988
|
+
interface AggregateCountIntent {
|
|
989
|
+
readonly function: 'count';
|
|
990
|
+
/** Field to aggregate; use '*' for COUNT(*) */
|
|
950
991
|
readonly field?: string;
|
|
951
992
|
/** Alias for result column */
|
|
952
993
|
readonly as?: string;
|
|
@@ -955,6 +996,26 @@ interface AggregateIntent {
|
|
|
955
996
|
/** FILTER (WHERE ...) clause for conditional aggregation */
|
|
956
997
|
readonly filter?: WhereIntent;
|
|
957
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* Aggregate operation intent (field-required branch): SUM / AVG / MIN / MAX / ARRAY_AGG / STRING_AGG.
|
|
1001
|
+
* @example { function: 'sum', field: 'price' } → SUM(price)
|
|
1002
|
+
*/
|
|
1003
|
+
interface AggregateFieldIntent {
|
|
1004
|
+
readonly function: Exclude<AggregateFunction, 'count'>;
|
|
1005
|
+
/** Field to aggregate (required for all non-count aggregates) */
|
|
1006
|
+
readonly field: string;
|
|
1007
|
+
/** Alias for result column */
|
|
1008
|
+
readonly as?: string;
|
|
1009
|
+
/** Whether to apply DISTINCT to the aggregate (e.g., COUNT(DISTINCT field)) */
|
|
1010
|
+
readonly distinct?: boolean;
|
|
1011
|
+
/** FILTER (WHERE ...) clause for conditional aggregation */
|
|
1012
|
+
readonly filter?: WhereIntent;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Aggregate operation intent.
|
|
1016
|
+
* XOR: `count` may omit field (defaults to '*'); all other aggregates require `field`.
|
|
1017
|
+
*/
|
|
1018
|
+
type AggregateIntent = AggregateCountIntent | AggregateFieldIntent;
|
|
958
1019
|
/**
|
|
959
1020
|
* Select with aggregate functions
|
|
960
1021
|
*/
|
|
@@ -1338,26 +1399,90 @@ interface WindowOrderBy {
|
|
|
1338
1399
|
* over: { partitionBy: ['account_id'], orderBy: [{ field: 'date' }] }
|
|
1339
1400
|
* }
|
|
1340
1401
|
*/
|
|
1341
|
-
|
|
1402
|
+
/**
|
|
1403
|
+
* Window function intent (ranking branch): ROW_NUMBER / RANK / DENSE_RANK — no field required.
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* { kind: 'window', function: 'row_number', alias: 'rn', over: { orderBy: [{ field: 'created_at', direction: 'desc' }] } }
|
|
1407
|
+
*/
|
|
1408
|
+
interface RankingWindowIntent {
|
|
1409
|
+
readonly kind: 'window';
|
|
1410
|
+
readonly function: RankingWindowFunction;
|
|
1411
|
+
readonly field?: never;
|
|
1412
|
+
/** Result column alias (required) */
|
|
1413
|
+
readonly alias: string;
|
|
1414
|
+
readonly offset?: never;
|
|
1415
|
+
readonly defaultValue?: never;
|
|
1416
|
+
/** OVER clause specification */
|
|
1417
|
+
readonly over: {
|
|
1418
|
+
readonly partitionBy?: readonly string[] | undefined;
|
|
1419
|
+
readonly orderBy?: readonly WindowOrderBy[] | undefined;
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Window function intent (aggregate branch): SUM / AVG / COUNT / MIN / MAX — field required.
|
|
1424
|
+
*
|
|
1425
|
+
* @example
|
|
1426
|
+
* { kind: 'window', function: 'sum', field: 'amount', alias: 'running_total', over: { partitionBy: ['account_id'] } }
|
|
1427
|
+
*/
|
|
1428
|
+
/**
|
|
1429
|
+
* Window function intent (aggregate branch): SUM / AVG / COUNT / MIN / MAX.
|
|
1430
|
+
* Field is required for sum/avg/min/max; COUNT omits field to produce COUNT(*) OVER (...).
|
|
1431
|
+
*
|
|
1432
|
+
* @example SUM with field
|
|
1433
|
+
* { kind: 'window', function: 'sum', field: 'amount', alias: 'running_total', over: { partitionBy: ['account_id'] } }
|
|
1434
|
+
* @example COUNT(*)
|
|
1435
|
+
* { kind: 'window', function: 'count', alias: 'total', over: {} }
|
|
1436
|
+
*/
|
|
1437
|
+
interface AggregateWindowIntent {
|
|
1342
1438
|
readonly kind: 'window';
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1439
|
+
readonly function: AggregateWindowFunction;
|
|
1440
|
+
/**
|
|
1441
|
+
* Field to aggregate over.
|
|
1442
|
+
* Required for sum/avg/min/max. Omit (or undefined) for COUNT(*) OVER (...).
|
|
1443
|
+
*/
|
|
1346
1444
|
readonly field?: string | undefined;
|
|
1347
1445
|
/** Result column alias (required) */
|
|
1348
1446
|
readonly alias: string;
|
|
1447
|
+
readonly offset?: never;
|
|
1448
|
+
readonly defaultValue?: never;
|
|
1449
|
+
/** OVER clause specification */
|
|
1450
|
+
readonly over: {
|
|
1451
|
+
readonly partitionBy?: readonly string[] | undefined;
|
|
1452
|
+
readonly orderBy?: readonly WindowOrderBy[] | undefined;
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Window function intent (offset branch): LAG / LEAD — field required, offset optional.
|
|
1457
|
+
*
|
|
1458
|
+
* @example
|
|
1459
|
+
* { kind: 'window', function: 'lag', field: 'salary', alias: 'prev_salary', over: { orderBy: [{ field: 'date', direction: 'asc' }] } }
|
|
1460
|
+
*/
|
|
1461
|
+
interface OffsetWindowIntent {
|
|
1462
|
+
readonly kind: 'window';
|
|
1463
|
+
readonly function: OffsetWindowFunction;
|
|
1464
|
+
/** Field to access from the offset row (required for lag/lead) */
|
|
1465
|
+
readonly field: string;
|
|
1466
|
+
/** Result column alias (required) */
|
|
1467
|
+
readonly alias: string;
|
|
1349
1468
|
/** Offset for lag/lead (default: 1 in PostgreSQL) */
|
|
1350
1469
|
readonly offset?: number | undefined;
|
|
1351
1470
|
/** Default value for lag/lead when row doesn't exist */
|
|
1352
1471
|
readonly defaultValue?: unknown;
|
|
1353
1472
|
/** OVER clause specification */
|
|
1354
1473
|
readonly over: {
|
|
1355
|
-
/** PARTITION BY columns (optional) */
|
|
1356
1474
|
readonly partitionBy?: readonly string[] | undefined;
|
|
1357
|
-
/** ORDER BY specification (optional but recommended for ranking) */
|
|
1358
1475
|
readonly orderBy?: readonly WindowOrderBy[] | undefined;
|
|
1359
1476
|
};
|
|
1360
1477
|
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Window function intent for analytics over partitions.
|
|
1480
|
+
* Discriminated by function group:
|
|
1481
|
+
* - RankingWindowIntent: row_number / rank / dense_rank (no field)
|
|
1482
|
+
* - AggregateWindowIntent: sum / avg / count / min / max (field required)
|
|
1483
|
+
* - OffsetWindowIntent: lag / lead (field required, offset optional)
|
|
1484
|
+
*/
|
|
1485
|
+
type WindowIntent = RankingWindowIntent | AggregateWindowIntent | OffsetWindowIntent;
|
|
1361
1486
|
/**
|
|
1362
1487
|
* Ranking window functions (no field required)
|
|
1363
1488
|
*/
|
|
@@ -1492,11 +1617,28 @@ interface IncludeIntent {
|
|
|
1492
1617
|
/**
|
|
1493
1618
|
* OrderBy intent - sort results
|
|
1494
1619
|
*/
|
|
1495
|
-
|
|
1620
|
+
/**
|
|
1621
|
+
* OrderBy intent (field branch): sort by a named column.
|
|
1622
|
+
*/
|
|
1623
|
+
interface OrderByFieldIntent {
|
|
1496
1624
|
/** Field name to sort by */
|
|
1497
|
-
readonly field
|
|
1498
|
-
|
|
1499
|
-
|
|
1625
|
+
readonly field: string;
|
|
1626
|
+
readonly expression?: never;
|
|
1627
|
+
/** Sort direction */
|
|
1628
|
+
readonly direction: SortDirection;
|
|
1629
|
+
/**
|
|
1630
|
+
* Where to place NULL values
|
|
1631
|
+
* @default 'last' for 'asc', 'first' for 'desc' (database default)
|
|
1632
|
+
*/
|
|
1633
|
+
readonly nulls?: NullsPosition;
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* OrderBy intent (expression branch): sort by an arbitrary expression.
|
|
1637
|
+
*/
|
|
1638
|
+
interface OrderByExpressionIntent {
|
|
1639
|
+
readonly field?: never;
|
|
1640
|
+
/** Expression to sort by */
|
|
1641
|
+
readonly expression: ExpressionIntent;
|
|
1500
1642
|
/** Sort direction */
|
|
1501
1643
|
readonly direction: SortDirection;
|
|
1502
1644
|
/**
|
|
@@ -1505,6 +1647,11 @@ interface OrderByIntent {
|
|
|
1505
1647
|
*/
|
|
1506
1648
|
readonly nulls?: NullsPosition;
|
|
1507
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* OrderBy intent - sort results.
|
|
1652
|
+
* XOR: exactly one of `field` or `expression` must be present.
|
|
1653
|
+
*/
|
|
1654
|
+
type OrderByIntent = OrderByFieldIntent | OrderByExpressionIntent;
|
|
1508
1655
|
|
|
1509
1656
|
/**
|
|
1510
1657
|
* Row-level locking intent for SELECT queries (E15).
|
|
@@ -1936,9 +2083,9 @@ interface BatchUpdateIntent {
|
|
|
1936
2083
|
/** Column(s) used to match rows (WHERE clause join condition) */
|
|
1937
2084
|
readonly matchColumns: readonly string[];
|
|
1938
2085
|
/** Array of row objects containing match + update column values */
|
|
1939
|
-
readonly updates: readonly Record<string, unknown
|
|
2086
|
+
readonly updates: readonly Readonly<Record<string, unknown>>[];
|
|
1940
2087
|
/** Optional scalar values applied to ALL rows (non-array SET clause) */
|
|
1941
|
-
readonly scalarSet?: Record<string, unknown
|
|
2088
|
+
readonly scalarSet?: Readonly<Record<string, unknown>>;
|
|
1942
2089
|
/** Columns to return from updated rows (RETURNING clause) */
|
|
1943
2090
|
readonly returning?: readonly string[];
|
|
1944
2091
|
/** Optional WHERE guard applied in addition to match columns (e.g., AND EXISTS(...)) */
|
|
@@ -2358,8 +2505,8 @@ interface PlanDecision {
|
|
|
2358
2505
|
readonly target?: string;
|
|
2359
2506
|
/** Relation name if applicable */
|
|
2360
2507
|
readonly relation?: string;
|
|
2361
|
-
/** Relation type (belongsTo, hasMany, hasOne,
|
|
2362
|
-
readonly relationType?:
|
|
2508
|
+
/** Relation type (belongsTo, hasMany, hasOne, belongsToMany) */
|
|
2509
|
+
readonly relationType?: RelationType;
|
|
2363
2510
|
/** Intent path (e.g., "where.exists.posts") */
|
|
2364
2511
|
readonly intentPath?: string;
|
|
2365
2512
|
/** Full relation path for multi-hop (SPEC-002), e.g., "author.company" */
|
|
@@ -2799,48 +2946,48 @@ type IndexColumnDef = string | {
|
|
|
2799
2946
|
};
|
|
2800
2947
|
/** Options for CREATE INDEX. */
|
|
2801
2948
|
type CreateIndexOptions = {
|
|
2802
|
-
name: string;
|
|
2803
|
-
columns: IndexColumnDef[];
|
|
2804
|
-
method?: IndexMethod;
|
|
2805
|
-
opclass?: Record<string, string
|
|
2806
|
-
include?: string[];
|
|
2807
|
-
with?: Record<string, unknown
|
|
2808
|
-
where?: string;
|
|
2809
|
-
unique?: boolean;
|
|
2810
|
-
ifNotExists?: boolean;
|
|
2811
|
-
concurrently?: boolean;
|
|
2949
|
+
readonly name: string;
|
|
2950
|
+
readonly columns: readonly IndexColumnDef[];
|
|
2951
|
+
readonly method?: IndexMethod;
|
|
2952
|
+
readonly opclass?: Readonly<Record<string, string>>;
|
|
2953
|
+
readonly include?: readonly string[];
|
|
2954
|
+
readonly with?: Readonly<Record<string, unknown>>;
|
|
2955
|
+
readonly where?: string;
|
|
2956
|
+
readonly unique?: boolean;
|
|
2957
|
+
readonly ifNotExists?: boolean;
|
|
2958
|
+
readonly concurrently?: boolean;
|
|
2812
2959
|
};
|
|
2813
2960
|
/** Options for DROP INDEX. */
|
|
2814
2961
|
type DropIndexOptions = {
|
|
2815
|
-
ifExists?: boolean;
|
|
2816
|
-
cascade?: boolean;
|
|
2817
|
-
concurrently?: boolean;
|
|
2818
|
-
schema?: string;
|
|
2962
|
+
readonly ifExists?: boolean;
|
|
2963
|
+
readonly cascade?: boolean;
|
|
2964
|
+
readonly concurrently?: boolean;
|
|
2965
|
+
readonly schema?: string;
|
|
2819
2966
|
};
|
|
2820
2967
|
/** Options for VACUUM. */
|
|
2821
2968
|
type VacuumOptions = {
|
|
2822
|
-
full?: boolean;
|
|
2823
|
-
analyze?: boolean;
|
|
2969
|
+
readonly full?: boolean;
|
|
2970
|
+
readonly analyze?: boolean;
|
|
2824
2971
|
};
|
|
2825
2972
|
/** Options for TRUNCATE. */
|
|
2826
2973
|
type TruncateOptions = {
|
|
2827
|
-
cascade?: boolean;
|
|
2828
|
-
restartIdentity?: boolean;
|
|
2974
|
+
readonly cascade?: boolean;
|
|
2975
|
+
readonly restartIdentity?: boolean;
|
|
2829
2976
|
};
|
|
2830
2977
|
/** Options for ALTER COLUMN. */
|
|
2831
2978
|
type AlterColumnOptions = {
|
|
2832
|
-
type?: string;
|
|
2833
|
-
using?: string;
|
|
2834
|
-
setNotNull?: boolean;
|
|
2835
|
-
setDefault?: unknown;
|
|
2836
|
-
dropDefault?: boolean;
|
|
2979
|
+
readonly type?: string;
|
|
2980
|
+
readonly using?: string;
|
|
2981
|
+
readonly setNotNull?: boolean;
|
|
2982
|
+
readonly setDefault?: unknown;
|
|
2983
|
+
readonly dropDefault?: boolean;
|
|
2837
2984
|
};
|
|
2838
2985
|
/** Index metadata returned by listIndexes(). */
|
|
2839
2986
|
type IndexInfo = {
|
|
2840
|
-
name: string;
|
|
2841
|
-
definition: string;
|
|
2842
|
-
unique: boolean;
|
|
2843
|
-
method: string;
|
|
2987
|
+
readonly name: string;
|
|
2988
|
+
readonly definition: string;
|
|
2989
|
+
readonly unique: boolean;
|
|
2990
|
+
readonly method: string;
|
|
2844
2991
|
};
|
|
2845
2992
|
/**
|
|
2846
2993
|
* Optional mixin for adapters that can generate table-scoped DDL SQL strings.
|
|
@@ -2955,7 +3102,7 @@ interface Adapter<DB = unknown> extends CompilingAdapter, ExecutingAdapter, Stre
|
|
|
2955
3102
|
/** Behavior when schema uses features the adapter doesn't support */
|
|
2956
3103
|
type UnsupportedFeatureBehavior = 'error' | 'warning' | 'ignore';
|
|
2957
3104
|
/** Aligned with DialectCapabilities supportsDDL* flags (1:1 mapping) */
|
|
2958
|
-
type DDLFeature = 'enum' | 'sequence' | 'extension' | 'partition' | 'checkConstraint' | 'onUpdateFK' | 'deferredFK' | 'identity' | 'collation' | 'comment' | 'indexMethod' | 'indexOpclass' | 'indexInclude' | 'partialIndex' | 'expressionIndex';
|
|
3105
|
+
type DDLFeature = 'enum' | 'sequence' | 'extension' | 'partition' | 'checkConstraint' | 'onUpdateFK' | 'deferredFK' | 'identity' | 'collation' | 'comment' | 'indexMethod' | 'indexOpclass' | 'indexInclude' | 'partialIndex' | 'expressionIndex' | 'rowLevelSecurity';
|
|
2959
3106
|
/** Version range for a DDL feature — resolved at createDialectCapabilities() time */
|
|
2960
3107
|
interface DDLFeatureVersionRange {
|
|
2961
3108
|
/** Minimum database version required (inclusive). E.g., '8.0.16' */
|
|
@@ -2970,13 +3117,6 @@ interface FeatureBehaviorConfig {
|
|
|
2970
3117
|
/** Per-feature overrides */
|
|
2971
3118
|
readonly overrides?: Partial<Record<DDLFeature, UnsupportedFeatureBehavior>>;
|
|
2972
3119
|
}
|
|
2973
|
-
/** Error thrown when behavior = 'error' and unsupported feature detected */
|
|
2974
|
-
declare class UnsupportedFeatureError extends Error {
|
|
2975
|
-
readonly feature: string;
|
|
2976
|
-
readonly adapter: string;
|
|
2977
|
-
readonly element: string;
|
|
2978
|
-
constructor(feature: string, adapter: string, element: string);
|
|
2979
|
-
}
|
|
2980
3120
|
/** Warning emitted when behavior = 'warning' */
|
|
2981
3121
|
interface FeatureWarning {
|
|
2982
3122
|
readonly feature: string;
|
|
@@ -3005,6 +3145,8 @@ interface DDLFeatureElementMap {
|
|
|
3005
3145
|
indexInclude: IndexIR;
|
|
3006
3146
|
partialIndex: IndexIR;
|
|
3007
3147
|
expressionIndex: IndexIR;
|
|
3148
|
+
/** Table with rlsEnabled and/or policies (ENABLE ROW LEVEL SECURITY + CREATE POLICY) */
|
|
3149
|
+
rowLevelSecurity: TableIR;
|
|
3008
3150
|
}
|
|
3009
3151
|
/**
|
|
3010
3152
|
* Interface for translating IR features to dialect-specific SQL.
|
|
@@ -3043,7 +3185,7 @@ interface TranslationContext {
|
|
|
3043
3185
|
interface LoadedSchema {
|
|
3044
3186
|
readonly definition: Record<string, unknown>;
|
|
3045
3187
|
readonly model: ModelIR;
|
|
3046
|
-
readonly tableNames: string[];
|
|
3188
|
+
readonly tableNames: readonly string[];
|
|
3047
3189
|
}
|
|
3048
3190
|
/**
|
|
3049
3191
|
* Runtime type guard for `LoadedSchema` — verifies the object has
|
|
@@ -3055,4 +3197,4 @@ interface LoadedSchema {
|
|
|
3055
3197
|
*/
|
|
3056
3198
|
declare function isValidSchema(schema: unknown): schema is LoadedSchema;
|
|
3057
3199
|
|
|
3058
|
-
export { type Adapter, type AdapterCapabilities, type AdapterLogger, type AdapterStreamOptions, type AdjacencyTraversal, type AggOrderByArg, type AggregateExpressionIntent, type AggregateFunction, type AggregateIntent, type AggregateWindowFunction, type AliasIncludedColumnsMode, type AlterColumnOptions, type AmbiguityCheckResult, type ArithmeticExpressionIntent, type ArrayExpressionIntent, type ArrayOperator, type BaseAdapter, type BatchUpdateIntent, type BatchValuesJoinPayload, type CTEDefinition, type Cardinality, type CaseExpressionIntent, type CastExpressionIntent, type CheckConstraintIR, type CoalesceExpressionIntent, type ColumnAliasIntent, type ColumnExpressionIntent, type ColumnIR, type ColumnType, type CommonColumnType, type ComparisonExpressionIntent, type ComparisonOperator, type CompileOnlyAdapter, type CompileOptions, type CompileOptionsBase, type CompileResultWithIncludes, type CompiledQuery, type CompilingAdapter, type CreateIndexOptions, type CteQueryIntent, type CustomFnExpressionIntent, type CustomOpExpressionIntent, type CustomTraversal, type DDLFeature, type DDLFeatureElementMap, type DDLFeatureVersionRange, type DDLGeneratingAdapter, type DbCasing, type DecisionType, type DeleteIntent, type DialectCapabilities, type DialectName, type DropIndexOptions, type DuckDBColumnType, type Dump, type DumpMeta, type EdgeTableTraversal, type EmitJoinClause, type EnumIR, type ExecutingAdapter, type ExpressionIntent, type FeatureBehaviorConfig, type FeatureTranslator, type FeatureWarning, type FieldRef, type FilterStrategy, type ForeignKeyIR, type FunctionExpressionIntent, type HierarchyIR, type IncludeIntent, type IncludeRecursiveOptions, type IncludeStrategy, type IndexColumnDef, type IndexIR, type IndexInfo, type IndexMethod, type InsertFromIntent, type InsertIntent, type IntrospectingAdapter, type IntrospectionOptions, type IntrospectionResult, type IsTypeSupported, type JoinDefault, type JoinIntent, type JsonContainsIntent, type JsonExistsIntent, type JsonExtractIntent, type JsonPathExtractIntent, type LiteralExpressionIntent, type LoadedSchema, type LockIntent, type LockStrength, type LockWaitPolicy, type LogicalOperator, type MSSQLColumnType, type ModelIR, type MutationIntent, type MySQLColumnType, type NamedArgExpressionIntent, type NullOperator, type NullsPosition, type OffsetWindowFunction, type OnDeleteAction, type Optionality, type OrderByIntent, type ParamExpressionIntent, type PartitionIR, type PlanDecision, type PlanOptions, type PlanReport, type PlanWarning, type PlanWarningCode, type PolicyIR, type PostgresColumnType, type PostgresOnlyColumnType, type PseudoColumnExpressionIntent, type PseudoColumnMetadata, type PseudoColumnTraversal, type QueryIntent, type RangeOperator, type RangeValue, type RankingWindowFunction, type RawCteIntent, type RawExpressionIntent, type RawSqlAdapter, type RecursiveAdvancedOptions, type RecursiveDedupe, type RecursiveDirection, type RecursiveEmitOptions, type RecursiveExistsOptions, type RecursiveIntent, type RecursiveMetadata, type RecursiveNodeIdExpr, type RecursivePlanOptions, type RecursivePlanReport, type RecursiveTrackOptions, type RecursiveTraversal, type RefExpressionIntent, type RelationColumnIntent, type RelationIR, type RelationKind, type RelationOperator, type RelationType, type ResolvedIncludeStrategy, type SQLiteColumnType, type ScalarSubqueryIntent, type SelectAggregateIntent, type SelectAllIntent, type SelectFieldsIntent, type SelectIntent, type SelectWithExpressionsIntent, type SequenceIR, type SetOperationIntent, type SetOperationType, type SimpleCteIntent, type SortDirection, type StarExpressionIntent, type StreamingAdapter, type StringOperator, type SubqueryExpressionIntent, type SubqueryIncludeInfo, type SubqueryRefIntent, type SupportedColumnTypes, type TableDDLGeneratorAdapter, type TableIR, type TransactionalAdapter, type TranslationContext, type TruncateOptions, type UnaryExpressionIntent, type UnnestCteIntent, type UnsupportedFeatureBehavior,
|
|
3200
|
+
export { type Adapter, type AdapterCapabilities, type AdapterLogger, type AdapterStreamOptions, type AdjacencyTraversal, type AggOrderByArg, type AggregateCountIntent, type AggregateExpressionIntent, type AggregateFieldIntent, type AggregateFunction, type AggregateIntent, type AggregateWindowFunction, type AggregateWindowIntent, type AliasIncludedColumnsMode, type AlterColumnOptions, type AmbiguityCheckResult, type ArithmeticExpressionIntent, type ArrayExpressionIntent, type ArrayOperator, type BaseAdapter, type BatchUpdateIntent, type BatchValuesJoinPayload, type CTEDefinition, type Cardinality, type CaseExpressionIntent, type CastExpressionIntent, type CheckConstraintIR, type CoalesceExpressionIntent, type ColumnAliasIntent, type ColumnExpressionIntent, type ColumnIR, type ColumnType, type CommonColumnType, type ComparisonExpressionIntent, type ComparisonOperator, type CompileOnlyAdapter, type CompileOptions, type CompileOptionsBase, type CompileResultWithIncludes, type CompiledQuery, type CompilingAdapter, type CreateIndexOptions, type CteQueryIntent, type CustomFnExpressionIntent, type CustomOpExpressionIntent, type CustomTraversal, type DDLFeature, type DDLFeatureElementMap, type DDLFeatureVersionRange, type DDLGeneratingAdapter, type DbCasing, type DecisionType, type DeleteIntent, type DialectCapabilities, type DialectName, type DropIndexOptions, type DuckDBColumnType, type Dump, type DumpMeta, type EdgeTableTraversal, type EmitJoinClause, type EnumIR, type ExecutingAdapter, type ExpressionIntent, type FeatureBehaviorConfig, type FeatureTranslator, type FeatureWarning, type FieldRef, type FilterStrategy, type ForeignKeyIR, type FunctionExpressionIntent, type HierarchyIR, type IncludeIntent, type IncludeRecursiveOptions, type IncludeStrategy, type IndexColumnDef, type IndexIR, type IndexInfo, type IndexMethod, type InsertFromIntent, type InsertIntent, type IntrospectingAdapter, type IntrospectionOptions, type IntrospectionResult, type IsTypeSupported, type JoinDefault, type JoinIntent, type JsonContainsIntent, type JsonExistsIntent, type JsonExtractIntent, type JsonPathExtractIntent, type LiteralExpressionIntent, type LoadedSchema, type LockIntent, type LockStrength, type LockWaitPolicy, type LogicalOperator, type MSSQLColumnType, type ModelIR, type MutationIntent, type MySQLColumnType, type NamedArgExpressionIntent, type NullOperator, type NullsPosition, type OffsetWindowFunction, type OffsetWindowIntent, type OnDeleteAction, type Optionality, type OrderByExpressionIntent, type OrderByFieldIntent, type OrderByIntent, type ParamExpressionIntent, type PartitionIR, type PlanDecision, type PlanOptions, type PlanReport, type PlanWarning, type PlanWarningCode, type PolicyIR, type PostgresColumnType, type PostgresOnlyColumnType, type PseudoColumnExpressionIntent, type PseudoColumnMetadata, type PseudoColumnTraversal, type QueryIntent, type RangeOperand, type RangeOperator, type RangeValue, type RankingWindowFunction, type RankingWindowIntent, type RawCteIntent, type RawExpressionIntent, type RawSqlAdapter, type RecursiveAdvancedOptions, type RecursiveDedupe, type RecursiveDirection, type RecursiveEmitOptions, type RecursiveExistsOptions, type RecursiveIntent, type RecursiveMetadata, type RecursiveNodeIdExpr, type RecursivePlanOptions, type RecursivePlanReport, type RecursiveTrackOptions, type RecursiveTraversal, type RefExpressionIntent, type RelationColumnIntent, type RelationIR, type RelationKind, type RelationOperator, type RelationType, type ResolvedIncludeStrategy, type SQLiteColumnType, type ScalarSubqueryIntent, type SelectAggregateIntent, type SelectAllIntent, type SelectFieldsIntent, type SelectIntent, type SelectWithExpressionsIntent, type SequenceIR, type SetOperationIntent, type SetOperationType, type SimpleCteIntent, type SortDirection, type StarExpressionIntent, type StreamingAdapter, type StringOperator, type SubqueryExpressionIntent, type SubqueryIncludeInfo, type SubqueryRefIntent, type SupportedColumnTypes, type TableDDLGeneratorAdapter, type TableIR, type TransactionalAdapter, type TranslationContext, type TruncateOptions, type UnaryExpressionIntent, type UnnestCteIntent, type UnsupportedFeatureBehavior, type UpdateIntent, type UpsertConflictAction, type UpsertConflictTarget, type UpsertFromIntent, type UpsertIntent, type VacuumOptions, type WhereAndIntent, type WhereAnyIntent, type WhereComparisonIntent, type WhereExistsIntent, type WhereExpressionIntent, type WhereInIntent, type WhereInSubqueryIntent, type WhereInValueIntent, type WhereIntent, type WhereJsonContainsIntent, type WhereJsonExistsIntent, type WhereLikeIntent, type WhereNotExistsIntent, type WhereNotIntent, type WhereNullIntent, type WhereOrIntent, type WhereRangeIntent, type WhereRawExistsIntent, type WhereRawNotExistsIntent, type WhereRelationFilterIntent, type WhereSubqueryIntent, type WindowFunction, type WindowIntent, type WindowOrderBy, getNodeIdAlias, isAdjacencyTraversal, isAggregateWindowFunction, isCoalesceExpression, isColumnAliasExpression, isCustomTraversal, isDeleteIntent, isEdgeTableTraversal, isFieldRef, isInsertIntent, isMutationIntent, isRankingWindowFunction, isRawExpression, isRecursiveIntent, isRelationColumnExpression, isSelectAggregate, isSelectAll, isSelectFields, isSelectWithExpressions, isSubqueryRef, isUpdateIntent, isUpsertIntent, isValidSchema, isWhereAnd, isWhereAny, isWhereComparison, isWhereExists, isWhereIn, isWhereLike, isWhereLogical, isWhereNot, isWhereNotExists, isWhereNull, isWhereOr, isWhereRange, isWhereRelationBased, isWhereRelationFilter, isWhereSubquery, isWindowIntent };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
UnsupportedFeatureError,
|
|
3
2
|
getNodeIdAlias,
|
|
4
3
|
isAdjacencyTraversal,
|
|
5
4
|
isAggregateWindowFunction,
|
|
@@ -39,9 +38,8 @@ import {
|
|
|
39
38
|
isWhereRelationFilter,
|
|
40
39
|
isWhereSubquery,
|
|
41
40
|
isWindowIntent
|
|
42
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-5WW2KG3P.js";
|
|
43
42
|
export {
|
|
44
|
-
UnsupportedFeatureError,
|
|
45
43
|
getNodeIdAlias,
|
|
46
44
|
isAdjacencyTraversal,
|
|
47
45
|
isAggregateWindowFunction,
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Adapter, AdapterCapabilities, AdapterLogger, AdapterStreamOptions, AdjacencyTraversal, AggOrderByArg, AggregateExpressionIntent, AggregateFunction, AggregateIntent, AggregateWindowFunction, AliasIncludedColumnsMode, AlterColumnOptions, AmbiguityCheckResult, ArithmeticExpressionIntent, ArrayExpressionIntent, ArrayOperator, BaseAdapter, BatchUpdateIntent, BatchValuesJoinPayload, CTEDefinition, Cardinality, CaseExpressionIntent, CastExpressionIntent, CheckConstraintIR, CoalesceExpressionIntent, ColumnAliasIntent, ColumnExpressionIntent, ColumnIR, ColumnType, CommonColumnType, ComparisonExpressionIntent, ComparisonOperator, CompileOnlyAdapter, CompileOptions, CompileOptionsBase, CompileResultWithIncludes, CompiledQuery, CompilingAdapter, CreateIndexOptions, CteQueryIntent, CustomFnExpressionIntent, CustomOpExpressionIntent, CustomTraversal, DDLFeature, DDLFeatureElementMap, DDLFeatureVersionRange, DDLGeneratingAdapter, DbCasing, DecisionType, DeleteIntent, DialectCapabilities, DialectName, DropIndexOptions, DuckDBColumnType, Dump, DumpMeta, EdgeTableTraversal, EmitJoinClause, EnumIR, ExecutingAdapter, ExpressionIntent, FeatureBehaviorConfig, FeatureTranslator, FeatureWarning, FieldRef, FilterStrategy, ForeignKeyIR, FunctionExpressionIntent, HierarchyIR, IncludeIntent, IncludeRecursiveOptions, IncludeStrategy, IndexColumnDef, IndexIR, IndexInfo, IndexMethod, InsertFromIntent, InsertIntent, IntrospectingAdapter, IntrospectionOptions, IntrospectionResult, IsTypeSupported, JoinDefault, JoinIntent, JsonContainsIntent, JsonExistsIntent, JsonExtractIntent, JsonPathExtractIntent, LiteralExpressionIntent, LoadedSchema, LockIntent, LockStrength, LockWaitPolicy, LogicalOperator, MSSQLColumnType, ModelIR, MutationIntent, MySQLColumnType, NamedArgExpressionIntent, NullOperator, NullsPosition, OffsetWindowFunction, OnDeleteAction, Optionality, OrderByIntent, ParamExpressionIntent, PartitionIR, PlanDecision, PlanOptions, PlanReport, PlanWarning, PlanWarningCode, PolicyIR, PostgresColumnType, PostgresOnlyColumnType, PseudoColumnExpressionIntent, PseudoColumnMetadata, PseudoColumnTraversal, QueryIntent, RangeOperator, RangeValue, RankingWindowFunction, RawCteIntent, RawExpressionIntent, RawSqlAdapter, RecursiveAdvancedOptions, RecursiveDedupe, RecursiveDirection, RecursiveEmitOptions, RecursiveExistsOptions, RecursiveIntent, RecursiveMetadata, RecursiveNodeIdExpr, RecursivePlanOptions, RecursivePlanReport, RecursiveTrackOptions, RecursiveTraversal, RefExpressionIntent, RelationColumnIntent, RelationIR, RelationKind, RelationOperator, RelationType, ResolvedIncludeStrategy, SQLiteColumnType, ScalarSubqueryIntent, SelectAggregateIntent, SelectAllIntent, SelectFieldsIntent, SelectIntent, SelectWithExpressionsIntent, SequenceIR, SetOperationIntent, SetOperationType, SimpleCteIntent, SortDirection, StarExpressionIntent, StreamingAdapter, StringOperator, SubqueryExpressionIntent, SubqueryIncludeInfo, SubqueryRefIntent, SupportedColumnTypes, TableDDLGeneratorAdapter, TableIR, TransactionalAdapter, TranslationContext, TruncateOptions, UnaryExpressionIntent, UnnestCteIntent, UnsupportedFeatureBehavior,
|
|
1
|
+
export { Adapter, AdapterCapabilities, AdapterLogger, AdapterStreamOptions, AdjacencyTraversal, AggOrderByArg, AggregateCountIntent, AggregateExpressionIntent, AggregateFieldIntent, AggregateFunction, AggregateIntent, AggregateWindowFunction, AggregateWindowIntent, AliasIncludedColumnsMode, AlterColumnOptions, AmbiguityCheckResult, ArithmeticExpressionIntent, ArrayExpressionIntent, ArrayOperator, BaseAdapter, BatchUpdateIntent, BatchValuesJoinPayload, CTEDefinition, Cardinality, CaseExpressionIntent, CastExpressionIntent, CheckConstraintIR, CoalesceExpressionIntent, ColumnAliasIntent, ColumnExpressionIntent, ColumnIR, ColumnType, CommonColumnType, ComparisonExpressionIntent, ComparisonOperator, CompileOnlyAdapter, CompileOptions, CompileOptionsBase, CompileResultWithIncludes, CompiledQuery, CompilingAdapter, CreateIndexOptions, CteQueryIntent, CustomFnExpressionIntent, CustomOpExpressionIntent, CustomTraversal, DDLFeature, DDLFeatureElementMap, DDLFeatureVersionRange, DDLGeneratingAdapter, DbCasing, DecisionType, DeleteIntent, DialectCapabilities, DialectName, DropIndexOptions, DuckDBColumnType, Dump, DumpMeta, EdgeTableTraversal, EmitJoinClause, EnumIR, ExecutingAdapter, ExpressionIntent, FeatureBehaviorConfig, FeatureTranslator, FeatureWarning, FieldRef, FilterStrategy, ForeignKeyIR, FunctionExpressionIntent, HierarchyIR, IncludeIntent, IncludeRecursiveOptions, IncludeStrategy, IndexColumnDef, IndexIR, IndexInfo, IndexMethod, InsertFromIntent, InsertIntent, IntrospectingAdapter, IntrospectionOptions, IntrospectionResult, IsTypeSupported, JoinDefault, JoinIntent, JsonContainsIntent, JsonExistsIntent, JsonExtractIntent, JsonPathExtractIntent, LiteralExpressionIntent, LoadedSchema, LockIntent, LockStrength, LockWaitPolicy, LogicalOperator, MSSQLColumnType, ModelIR, MutationIntent, MySQLColumnType, NamedArgExpressionIntent, NullOperator, NullsPosition, OffsetWindowFunction, OffsetWindowIntent, OnDeleteAction, Optionality, OrderByExpressionIntent, OrderByFieldIntent, OrderByIntent, ParamExpressionIntent, PartitionIR, PlanDecision, PlanOptions, PlanReport, PlanWarning, PlanWarningCode, PolicyIR, PostgresColumnType, PostgresOnlyColumnType, PseudoColumnExpressionIntent, PseudoColumnMetadata, PseudoColumnTraversal, QueryIntent, RangeOperand, RangeOperator, RangeValue, RankingWindowFunction, RankingWindowIntent, RawCteIntent, RawExpressionIntent, RawSqlAdapter, RecursiveAdvancedOptions, RecursiveDedupe, RecursiveDirection, RecursiveEmitOptions, RecursiveExistsOptions, RecursiveIntent, RecursiveMetadata, RecursiveNodeIdExpr, RecursivePlanOptions, RecursivePlanReport, RecursiveTrackOptions, RecursiveTraversal, RefExpressionIntent, RelationColumnIntent, RelationIR, RelationKind, RelationOperator, RelationType, ResolvedIncludeStrategy, SQLiteColumnType, ScalarSubqueryIntent, SelectAggregateIntent, SelectAllIntent, SelectFieldsIntent, SelectIntent, SelectWithExpressionsIntent, SequenceIR, SetOperationIntent, SetOperationType, SimpleCteIntent, SortDirection, StarExpressionIntent, StreamingAdapter, StringOperator, SubqueryExpressionIntent, SubqueryIncludeInfo, SubqueryRefIntent, SupportedColumnTypes, TableDDLGeneratorAdapter, TableIR, TransactionalAdapter, TranslationContext, TruncateOptions, UnaryExpressionIntent, UnnestCteIntent, UnsupportedFeatureBehavior, UpdateIntent, UpsertConflictAction, UpsertConflictTarget, UpsertFromIntent, UpsertIntent, VacuumOptions, WhereAndIntent, WhereAnyIntent, WhereComparisonIntent, WhereExistsIntent, WhereExpressionIntent, WhereInIntent, WhereInSubqueryIntent, WhereInValueIntent, WhereIntent, WhereJsonContainsIntent, WhereJsonExistsIntent, WhereLikeIntent, WhereNotExistsIntent, WhereNotIntent, WhereNullIntent, WhereOrIntent, WhereRangeIntent, WhereRawExistsIntent, WhereRawNotExistsIntent, WhereRelationFilterIntent, WhereSubqueryIntent, WindowFunction, WindowIntent, WindowOrderBy, getNodeIdAlias, isAdjacencyTraversal, isAggregateWindowFunction, isCoalesceExpression, isColumnAliasExpression, isCustomTraversal, isDeleteIntent, isEdgeTableTraversal, isFieldRef, isInsertIntent, isMutationIntent, isRankingWindowFunction, isRawExpression, isRecursiveIntent, isRelationColumnExpression, isSelectAggregate, isSelectAll, isSelectFields, isSelectWithExpressions, isSubqueryRef, isUpdateIntent, isUpsertIntent, isValidSchema, isWhereAnd, isWhereAny, isWhereComparison, isWhereExists, isWhereIn, isWhereLike, isWhereLogical, isWhereNot, isWhereNotExists, isWhereNull, isWhereOr, isWhereRange, isWhereRelationBased, isWhereRelationFilter, isWhereSubquery, isWindowIntent } from './index.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @module builders
|
package/dist/internal.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
UnsupportedFeatureError,
|
|
3
2
|
getNodeIdAlias,
|
|
4
3
|
isAdjacencyTraversal,
|
|
5
4
|
isAggregateWindowFunction,
|
|
@@ -39,9 +38,8 @@ import {
|
|
|
39
38
|
isWhereRelationFilter,
|
|
40
39
|
isWhereSubquery,
|
|
41
40
|
isWindowIntent
|
|
42
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-5WW2KG3P.js";
|
|
43
42
|
export {
|
|
44
|
-
UnsupportedFeatureError,
|
|
45
43
|
getNodeIdAlias,
|
|
46
44
|
isAdjacencyTraversal,
|
|
47
45
|
isAggregateWindowFunction,
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter.ts","../src/intent/recursive-intent.ts","../src/intent/type-guards.ts","../src/intent/where-intent.ts","../src/loaded-schema.ts"],"sourcesContent":["/**\n * @module adapter\n * Adapter interface type definitions.\n *\n * Runtime functions (assertCapability, supportsExecution, etc.) and\n * error classes (AdapterRequiredError, UnsupportedCapabilityError)\n * remain in @dbsp/core.\n */\n\nimport type { DialectCapabilities } from './dialects.js';\nimport type {\n\tBatchUpdateIntent,\n\tCteQueryIntent,\n\tDeleteIntent,\n\tExpressionIntent,\n\tInsertFromIntent,\n\tInsertIntent,\n\tSelectIntent,\n\tSetOperationIntent,\n\tUpdateIntent,\n\tUpsertFromIntent,\n\tUpsertIntent,\n\tWhereIntent,\n} from './intent-ast.js';\nimport type {\n\tCheckConstraintIR,\n\tColumnIR,\n\tEnumIR,\n\tForeignKeyIR,\n\tHierarchyIR,\n\tIndexIR,\n\tModelIR,\n\tPartitionIR,\n\tSequenceIR,\n} from './model-ir.js';\nimport type { PlanReport, RecursivePlanReport } from './planner.js';\n\n// ============================================================================\n// Logger\n// ============================================================================\n\n/**\n * Minimal logger interface for adapter debug/error logging.\n * Adapters accept an optional logger for observability without\n * coupling to any specific logging framework.\n */\nexport interface AdapterLogger {\n\tdebug?(message: string, ...args: unknown[]): void;\n\twarn?(message: string, ...args: unknown[]): void;\n\terror?(message: string, ...args: unknown[]): void;\n}\n\n// ============================================================================\n// Capabilities\n// ============================================================================\n\n/**\n * Adapter capabilities - what the underlying database/ORM supports.\n * Used for feature detection and graceful degradation.\n */\nexport interface AdapterCapabilities {\n\treadonly supportsReturning: boolean;\n\treadonly supportsSchemas: boolean;\n\treadonly supportsStreaming: boolean;\n\treadonly supportsRecursiveCTE: boolean;\n\treadonly supportsWindowFunctions: boolean;\n\treadonly supportsArrayType: boolean;\n}\n\n// ============================================================================\n// Compiled Query\n// ============================================================================\n\n/**\n * A compiled query ready for execution.\n *\n * @typeParam T - The expected result type (phantom type for inference)\n */\nexport interface CompiledQuery<T = unknown> {\n\treadonly sql: string;\n\treadonly parameters: readonly unknown[];\n\t/** Phantom type for result inference - not used at runtime */\n\treadonly __resultType?: T;\n}\n\n// ============================================================================\n// Options\n// ============================================================================\n\n/**\n * Base compile options shared across all adapters.\n * Adapters can extend this with adapter-specific options.\n */\nexport interface CompileOptionsBase {\n\t/** Schema name for schema-scoped/multi-tenant queries */\n\treadonly schemaName?: string;\n\n\t/** Query name for logging */\n\treadonly queryName?: string;\n\n\t/** Correlation ID for distributed tracing */\n\treadonly correlationId?: string;\n\n\t/**\n\t * Row count threshold for switching INSERT compilation from VALUES to unnest strategy.\n\t * Rows <= threshold use VALUES ($1,$2),... Rows > threshold use SELECT unnest($1::type[]),...\n\t * Set to 0 to force unnest for all batch sizes.\n\t * @default 50\n\t */\n\treadonly batchThreshold?: number;\n\n\t/**\n\t * Maximum allowed batch size for INSERT operations.\n\t * If set and the number of rows exceeds this limit, an InvalidOperationError is thrown.\n\t * Useful to prevent accidental unbounded inserts.\n\t * @default undefined (no limit)\n\t */\n\treadonly maxBatchSize?: number;\n}\n\n/**\n * Options for streaming query results.\n */\nexport interface AdapterStreamOptions {\n\t/** Number of rows to fetch per chunk */\n\treadonly chunkSize?: number;\n}\n\n/**\n * Alias mode for included relation columns.\n *\n * - `'always'` (default): Alias all columns from included tables (e.g., `\"author.id\"`, `\"author.name\"`)\n * - `'onCollision'`: Only alias columns that exist in multiple tables (e.g., `id`, `createdAt`)\n *\n * Note: `'never'` is intentionally excluded as it would cause data loss from duplicate column names.\n */\nexport type AliasIncludedColumnsMode = 'always' | 'onCollision';\n\n/**\n * Describes the casing convention used for column names in the database.\n * This is the intuitive \"what does your DB look like?\" type:\n *\n * - `'snake_case'`: DB columns use snake_case → adapter transforms to camelCase for JS\n * - `'camelCase'`: DB columns use camelCase → no transformation needed\n * - `'preserve'`: No transformation applied\n */\nexport type DbCasing = 'snake_case' | 'camelCase' | 'preserve';\n\n/**\n * Options for query compilation.\n * Extends CompileOptionsBase with core-specific options.\n */\nexport interface CompileOptions extends CompileOptionsBase {\n\t/** Model IR for relation lookups during compilation */\n\treadonly model?: ModelIR;\n\t/**\n\t * Alias mode for included relation columns.\n\t * @default 'always'\n\t */\n\treadonly aliasIncludedColumns?: AliasIncludedColumnsMode;\n}\n\n// ============================================================================\n// Include Hydration (DX-033)\n// ============================================================================\n\n/**\n * Metadata for a subquery include query.\n * Used when planner decides include-strategy: 'subquery' for hasMany/manyToMany relations.\n */\nexport interface SubqueryIncludeInfo {\n\t/** Name of the relation being included */\n\treadonly relationName: string;\n\t/** Target table to fetch from */\n\treadonly targetTable: string;\n\t/** Foreign key column(s) in target table */\n\treadonly foreignKey: string | readonly string[];\n\t/** Source key column(s) in parent table */\n\treadonly sourceKey: string | readonly string[];\n\t/** Optional select clause from include intent */\n\treadonly select?: SelectIntent;\n\t/** Optional where clause from include intent */\n\treadonly where?: WhereIntent;\n\t/** Optional nested includes (for recursive hydration) */\n\treadonly nestedIncludes?: readonly SubqueryIncludeInfo[];\n\n\t// --- M:N (manyToMany) support ---\n\t/** Junction table for M:N relations (e.g., 'postTags') */\n\treadonly through?: string;\n\t/** FK in junction table pointing to source (e.g., 'postId') */\n\treadonly throughSourceKey?: string;\n\t/** FK in junction table pointing to target (e.g., 'tagId') */\n\treadonly throughTargetKey?: string;\n\n\t// --- Relation metadata ---\n\t/** Relation type for to-one unwrapping (belongsTo/hasOne → single object) */\n\treadonly relationType?: string;\n\n\t// --- Subquery optimization (NQL-ALIGN Block 5) ---\n\t/** Source/parent table name for subquery optimization */\n\treadonly sourceTable?: string;\n\t/** Parent query's WHERE conditions for subquery optimization */\n\treadonly parentWhere?: WhereIntent;\n}\n\n/**\n * Result of compiling a query with subquery includes.\n */\nexport interface CompileResultWithIncludes<T = unknown> {\n\t/** The main query (includes any JOIN includes) */\n\treadonly main: CompiledQuery<T>;\n\t/** Metadata for subquery include queries (empty if all includes use JOIN) */\n\treadonly subqueryIncludes: readonly SubqueryIncludeInfo[];\n}\n\n// ============================================================================\n// Dump (Observability)\n// ============================================================================\n\n/**\n * Metadata for a query dump.\n */\nexport interface DumpMeta {\n\treadonly schema?: string;\n\treadonly queryName?: string;\n\treadonly correlationId?: string;\n\treadonly compiledAt?: Date;\n}\n\n/**\n * A dump contains the plan, compiled SQL, and parameters for observability.\n */\nexport interface Dump {\n\treadonly plan?: PlanReport | undefined;\n\treadonly sql: string;\n\treadonly params: readonly unknown[];\n\treadonly meta?: DumpMeta;\n}\n\n// ============================================================================\n// Split Adapter Interfaces (DX-104: ISP Compliance)\n// ============================================================================\n\n/**\n * Base adapter interface - core capabilities all adapters must have.\n */\nexport interface BaseAdapter {\n\t/** Adapter capabilities for feature detection */\n\treadonly capabilities: AdapterCapabilities;\n\n\t/**\n\t * Dialect capabilities for planner strategy selection.\n\t * Determines which SQL features the adapter's database supports\n\t * (LATERAL JOIN, json_agg, window functions, etc.).\n\t */\n\treadonly dialectCapabilities: DialectCapabilities;\n\n\t/**\n\t * Validate an identifier (table name, column name, schema name).\n\t * Throws if the identifier contains unsafe characters.\n\t */\n\tvalidateIdentifier(value: string, type: string): void;\n}\n\n/**\n * Compiling adapter - can compile plans to SQL queries.\n */\nexport interface CompilingAdapter extends BaseAdapter {\n\t/** Compile a plan to executable SQL. */\n\tcompile<T = unknown>(\n\t\tplan: PlanReport,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery<T>;\n\n\t/** Compile a plan with includes, returning subquery include metadata (DX-033). */\n\tcompileWithIncludes<T = unknown>(\n\t\tplan: PlanReport,\n\t\toptions?: CompileOptions,\n\t): CompileResultWithIncludes<T>;\n\n\t/** Compile a subquery include query for given parent IDs (DX-033). */\n\tcompileSubqueryInclude(\n\t\tinfo: SubqueryIncludeInfo,\n\t\tparentIds: readonly unknown[],\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile an insert intent to executable SQL. */\n\tcompileInsert(intent: InsertIntent, options?: CompileOptions): CompiledQuery;\n\n\t/** Compile an insert-from intent to executable SQL (NQL-ALIGN). */\n\tcompileInsertFrom(\n\t\tintent: InsertFromIntent,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile an update intent to executable SQL. */\n\tcompileUpdate(intent: UpdateIntent, options?: CompileOptions): CompiledQuery;\n\n\t/** Compile a batch update intent to executable SQL (BATCH-001). */\n\tcompileBatchUpdate(\n\t\tintent: BatchUpdateIntent,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile a delete intent to executable SQL. */\n\tcompileDelete(intent: DeleteIntent, options?: CompileOptions): CompiledQuery;\n\n\t/** Compile an upsert intent to executable SQL (DX-026). */\n\tcompileUpsert(intent: UpsertIntent, options?: CompileOptions): CompiledQuery;\n\n\t/** Compile an upsert-from intent to executable SQL (NQL-BIND). */\n\tcompileUpsertFrom(\n\t\tintent: UpsertFromIntent,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile a recursive CTE plan to executable SQL. */\n\tcompileRecursive(\n\t\treport: RecursivePlanReport,\n\t\tmodel: ModelIR,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile a CTE query backed by unnest() arrays (BATCH-001). */\n\tcompileCteQuery(\n\t\tintent: CteQueryIntent,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL. */\n\tcompileSetOperation(\n\t\tintent: SetOperationIntent,\n\t\tmodel: ModelIR,\n\t\toptions?: CompileOptions,\n\t): CompiledQuery;\n\n\t/** Compile a FROM-less SELECT expression to SQL (e.g. SELECT nextval('seq')). */\n\tcompileSelectExpression(expr: ExpressionIntent): CompiledQuery;\n\n\t/** Create a dump for observability. */\n\tcreateDump(plan: PlanReport, query: CompiledQuery, meta?: DumpMeta): Dump;\n}\n\n/**\n * Executing adapter - can execute compiled queries.\n */\nexport interface ExecutingAdapter extends BaseAdapter {\n\t/** Execute a query and return all results. */\n\texecute<T>(query: CompiledQuery<T>): Promise<T[]>;\n\n\t/** Execute a query and return the first result or null. */\n\texecuteOne<T>(query: CompiledQuery<T>): Promise<T | null>;\n\n\t/** Execute a query and return the first result or throw. */\n\texecuteOneOrThrow<T>(query: CompiledQuery<T>): Promise<T>;\n}\n\n/**\n * Streaming adapter - can stream query results.\n */\nexport interface StreamingAdapter extends BaseAdapter {\n\t/** Stream query results as an async iterable iterator. */\n\tstream<T>(\n\t\tquery: CompiledQuery<T>,\n\t\toptions?: AdapterStreamOptions,\n\t): AsyncIterableIterator<T>;\n}\n\n/**\n * Options for database introspection.\n */\nexport interface IntrospectionOptions {\n\t/** Schema name to introspect (default: 'public' for PostgreSQL) */\n\treadonly schema?: string;\n\t/** Tables to include (default: all). Applied before exclude. */\n\treadonly include?: readonly string[];\n\t/** Tables to exclude (glob patterns: * matches any chars) */\n\treadonly exclude?: readonly string[];\n}\n\n/**\n * Result of database introspection.\n * Extends ModelIR with introspection-specific metadata.\n */\nexport interface IntrospectionResult extends ModelIR {\n\t/** Timestamp when introspection was performed */\n\treadonly introspectedAt: Date;\n\t/** Warnings from introspection (e.g., unsupported types) */\n\treadonly warnings?: readonly string[];\n\t/** Hierarchy patterns detected during introspection (adjacency-list / edge-table) */\n\treadonly hierarchies?: readonly HierarchyIR[];\n}\n\n/**\n * Introspecting adapter - can introspect database schema.\n */\nexport interface IntrospectingAdapter extends BaseAdapter {\n\t/** Database column casing convention */\n\treadonly dbCasing?: DbCasing;\n\t/** Introspect the database schema and return a ModelIR. */\n\tintrospect(options?: IntrospectionOptions): Promise<IntrospectionResult>;\n}\n\n/**\n * Transactional adapter - supports database transactions.\n */\nexport interface TransactionalAdapter<DB = unknown> extends BaseAdapter {\n\t/** Execute a callback within a database transaction. */\n\ttransaction<T>(fn: (adapter: Adapter<DB>) => Promise<T>): Promise<T>;\n\n\t/** Create a schema-scoped adapter for multi-tenant queries. */\n\twithSchema(schemaName: string): Adapter<DB>;\n}\n\n/**\n * Raw SQL adapter - can execute raw SQL directly.\n *\n * @warning **SECURITY RISK: POTENTIAL SQL INJECTION**\n * Use parameter placeholders ($1, $2, etc.) for ALL values.\n */\nexport interface RawSqlAdapter extends BaseAdapter {\n\t/**\n\t * Execute raw SQL directly - the ultimate escape hatch.\n\t *\n\t * @param sql - Raw SQL string with parameter placeholders\n\t * @param parameters - Parameter values (safely bound by driver)\n\t */\n\texecuteRaw<T = unknown>(\n\t\tsql: string,\n\t\tparameters?: readonly unknown[],\n\t): Promise<T[]>;\n}\n\n// ============================================================================\n// Table DDL Operation Types (DDL-TABLE-001)\n// Defined here so adapter.ts can reference them without importing from @dbsp/core.\n// ============================================================================\n\n/**\n * PostgreSQL index access method.\n */\nexport type IndexMethod =\n\t| 'btree'\n\t| 'hash'\n\t| 'gist'\n\t| 'gin'\n\t| 'brin'\n\t| 'hnsw'\n\t| 'ivfflat'\n\t| 'bm25';\n\n/** A column reference in an index: either a column name or an expression. */\nexport type IndexColumnDef =\n\t| string\n\t| {\n\t\t\texpression: string;\n\t\t\topclass?: string;\n\t };\n\n/** Options for CREATE INDEX. */\nexport type CreateIndexOptions = {\n\tname: string;\n\tcolumns: IndexColumnDef[];\n\tmethod?: IndexMethod;\n\topclass?: Record<string, string>;\n\tinclude?: string[];\n\twith?: Record<string, unknown>;\n\twhere?: string;\n\tunique?: boolean;\n\tifNotExists?: boolean;\n\tconcurrently?: boolean;\n};\n\n/** Options for DROP INDEX. */\nexport type DropIndexOptions = {\n\tifExists?: boolean;\n\tcascade?: boolean;\n\tconcurrently?: boolean;\n\tschema?: string;\n};\n\n/** Options for VACUUM. */\nexport type VacuumOptions = {\n\tfull?: boolean;\n\tanalyze?: boolean;\n};\n\n/** Options for TRUNCATE. */\nexport type TruncateOptions = {\n\tcascade?: boolean;\n\trestartIdentity?: boolean;\n};\n\n/** Options for ALTER COLUMN. */\nexport type AlterColumnOptions = {\n\ttype?: string;\n\tusing?: string;\n\tsetNotNull?: boolean;\n\tsetDefault?: unknown;\n\tdropDefault?: boolean;\n};\n\n/** Index metadata returned by listIndexes(). */\nexport type IndexInfo = {\n\tname: string;\n\tdefinition: string;\n\tunique: boolean;\n\tmethod: string;\n};\n\n// ============================================================================\n// Table DDL Generator Adapter (DDL-TABLE-001)\n// ============================================================================\n\n/**\n * Optional mixin for adapters that can generate table-scoped DDL SQL strings.\n * When present on an adapter, buildTableDDL in core delegates SQL generation\n * to these methods instead of generating SQL inline.\n */\nexport interface TableDDLGeneratorAdapter {\n\t/**\n\t * Generate SQL for TRUNCATE TABLE.\n\t */\n\tgenerateTruncate?(\n\t\ttable: string,\n\t\tschema?: string,\n\t\toptions?: TruncateOptions,\n\t): string;\n\n\t/**\n\t * Generate SQL for VACUUM.\n\t */\n\tgenerateVacuum?(\n\t\ttable: string,\n\t\tschema?: string,\n\t\toptions?: VacuumOptions,\n\t): string;\n\n\t/**\n\t * Generate SQL for ALTER TABLE ... ALTER COLUMN.\n\t */\n\tgenerateAlterColumn?(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\toptions: AlterColumnOptions,\n\t\tschema?: string,\n\t): string;\n\n\t/**\n\t * Generate SQL for CREATE INDEX.\n\t */\n\tgenerateCreateIndex?(\n\t\ttable: string,\n\t\toptions: CreateIndexOptions,\n\t\tschema?: string,\n\t): string;\n\n\t/**\n\t * Generate SQL for DROP INDEX.\n\t */\n\tgenerateDropIndex?(name: string, options?: DropIndexOptions): string;\n\n\t/**\n\t * List all indexes on a table, with optional name pattern filter.\n\t */\n\tlistIndexes?(\n\t\ttable: string,\n\t\tschema?: string,\n\t\toptions?: { namePattern?: string },\n\t): Promise<IndexInfo[]>;\n\n\t/**\n\t * Check whether an index with the given name exists on a table.\n\t */\n\tindexExists?(name: string, table: string, schema?: string): Promise<boolean>;\n\n\t/**\n\t * Return the total storage size of a table in bytes.\n\t * Requires a live pool connection — compile-only adapters must throw.\n\t */\n\tstorageSize?(table: string, schema?: string): Promise<number>;\n}\n\n/**\n * DDL-generating adapter - can generate DDL (CREATE TABLE statements) from a schema.\n */\nexport interface DDLGeneratingAdapter extends BaseAdapter {\n\t/**\n\t * Generate DDL statements from a schema.\n\t *\n\t * @param schema - The ModelIR schema to generate DDL from\n\t * @param options - Optional adapter-specific options (e.g., includeDropStatements)\n\t * @returns Array of DDL statements (CREATE TABLE, CREATE INDEX, etc.)\n\t */\n\tgenerateDDL(schema: ModelIR, options?: Record<string, unknown>): string[];\n}\n\n// ============================================================================\n// Convenience Composed Types (DX-104)\n// ============================================================================\n\n/**\n * Compile-only adapter - can compile SQL and generate DDL, but cannot execute\n * queries or stream results. Useful for tooling, CLI, and testing without a\n * live database connection.\n *\n * Includes DDLGeneratingAdapter because DDL generation is purely compile-time\n * (no DB connection required — same rationale as SQL compilation).\n *\n * Explicitly excludes execution interfaces so that type-checking catches\n * misuse (e.g. calling execute() on a compile-only instance) at compile time.\n */\nexport type CompileOnlyAdapter = CompilingAdapter &\n\tDDLGeneratingAdapter & {\n\t\t/** Naming convention used by this adapter. */\n\t\treadonly dbCasing: DbCasing;\n\n\t\t/**\n\t\t * Create a schema-scoped compile-only adapter.\n\t\t * Purely a schema-name prefix — no DB interaction required.\n\t\t */\n\t\twithSchema(schemaName: string): CompileOnlyAdapter;\n\n\t\treadonly execute?: never;\n\t\treadonly executeOne?: never;\n\t\treadonly executeOneOrThrow?: never;\n\t\treadonly stream?: never;\n\t\treadonly introspect?: never;\n\t\treadonly transaction?: never;\n\t\treadonly executeRaw?: never;\n\t\treadonly executeDDL?: never;\n\t};\n\n// ============================================================================\n// Full Adapter Interface\n// ============================================================================\n\n/**\n * Database adapter interface - full adapter with all capabilities.\n *\n * @typeParam DB - Database schema type for type inference\n */\nexport interface Adapter<DB = unknown>\n\textends CompilingAdapter,\n\t\tExecutingAdapter,\n\t\tStreamingAdapter,\n\t\tIntrospectingAdapter,\n\t\tTransactionalAdapter<DB>,\n\t\tRawSqlAdapter,\n\t\tDDLGeneratingAdapter,\n\t\tTableDDLGeneratorAdapter {\n\t/**\n\t * Naming convention used by this adapter.\n\t *\n\t * @since ARCH-006\n\t */\n\treadonly dbCasing: DbCasing;\n\n\t/**\n\t * Execute a DDL statement directly (e.g. TRUNCATE, VACUUM, ALTER TABLE, CREATE INDEX).\n\t * Optional — compile-only adapters do not implement this.\n\t *\n\t * @since DDL-TABLE-001\n\t */\n\texecuteDDL?(sql: string): Promise<void>;\n\n\t/**\n\t * Whether this adapter instance is scoped inside a transaction.\n\t * Used by table DDL methods to guard against unsafe operations (e.g. VACUUM).\n\t *\n\t * @since DDL-TABLE-001\n\t */\n\treadonly inTransaction?: boolean;\n}\n\n// ============================================================================\n// DDL Feature Negotiation (CAPS-001/002)\n// ============================================================================\n\n/** Behavior when schema uses features the adapter doesn't support */\nexport type UnsupportedFeatureBehavior = 'error' | 'warning' | 'ignore';\n\n/** Aligned with DialectCapabilities supportsDDL* flags (1:1 mapping) */\nexport type DDLFeature =\n\t| 'enum'\n\t| 'sequence'\n\t| 'extension'\n\t| 'partition'\n\t| 'checkConstraint'\n\t| 'onUpdateFK'\n\t| 'deferredFK'\n\t| 'identity'\n\t| 'collation'\n\t| 'comment'\n\t| 'indexMethod'\n\t| 'indexOpclass'\n\t| 'indexInclude'\n\t| 'partialIndex'\n\t| 'expressionIndex';\n\n/** Version range for a DDL feature — resolved at createDialectCapabilities() time */\nexport interface DDLFeatureVersionRange {\n\t/** Minimum database version required (inclusive). E.g., '8.0.16' */\n\treadonly min?: string;\n\t/** Maximum database version supported (inclusive, optional). For deprecation. */\n\treadonly max?: string;\n}\n\n/** Per-feature behavior overrides (global default + optional per-feature) */\nexport interface FeatureBehaviorConfig {\n\t/** Global default behavior (default: 'warning') */\n\treadonly default: UnsupportedFeatureBehavior;\n\t/** Per-feature overrides */\n\treadonly overrides?: Partial<Record<DDLFeature, UnsupportedFeatureBehavior>>;\n}\n\n/** Error thrown when behavior = 'error' and unsupported feature detected */\nexport class UnsupportedFeatureError extends Error {\n\tconstructor(\n\t\treadonly feature: string,\n\t\treadonly adapter: string,\n\t\treadonly element: string,\n\t) {\n\t\tsuper(\n\t\t\t`Unsupported feature \"${feature}\" on adapter \"${adapter}\" for \"${element}\"`,\n\t\t);\n\t\tthis.name = 'UnsupportedFeatureError';\n\t}\n}\n\n/** Warning emitted when behavior = 'warning' */\nexport interface FeatureWarning {\n\treadonly feature: string;\n\treadonly adapter: string;\n\treadonly element: string;\n\treadonly message: string;\n}\n\n// ============================================================================\n// Feature Translation Interface (CAPS-005 — design only)\n// ============================================================================\n\n/** Type-safe element map: DDLFeature → IR type (INV-12) */\nexport interface DDLFeatureElementMap {\n\tenum: EnumIR;\n\tsequence: SequenceIR;\n\textension: string;\n\tpartition: PartitionIR;\n\tcheckConstraint: CheckConstraintIR;\n\tonUpdateFK: ForeignKeyIR;\n\tdeferredFK: ForeignKeyIR;\n\tidentity: ColumnIR;\n\tcollation: ColumnIR;\n\tcomment: { target: 'table' | 'column'; name: string; comment: string };\n\tindexMethod: IndexIR;\n\tindexOpclass: IndexIR;\n\tindexInclude: IndexIR;\n\tpartialIndex: IndexIR;\n\texpressionIndex: IndexIR;\n}\n\n/**\n * Interface for translating IR features to dialect-specific SQL.\n * Adapters register translators to handle features their way.\n *\n * @example PG enum translator\n * ```typescript\n * const pgEnumTranslator: FeatureTranslator<'enum'> = {\n * feature: 'enum',\n * translate(element, context) {\n * return [`CREATE TYPE \"${element.name}\" AS ENUM (${element.values.map(v => `'${v}'`).join(', ')})`];\n * },\n * };\n * ```\n */\nexport interface FeatureTranslator<F extends DDLFeature = DDLFeature> {\n\t/** Which IR feature this translator handles */\n\treadonly feature: F;\n\t/** Generate SQL for this feature. Return null to skip (use default behavior). */\n\ttranslate(\n\t\telement: DDLFeatureElementMap[F],\n\t\tcontext: TranslationContext,\n\t): string[] | null;\n}\n\nexport interface TranslationContext {\n\treadonly schemaName?: string;\n\treadonly tableName?: string;\n\treadonly dialectCapabilities: DialectCapabilities;\n}\n","/**\n * @module intent/recursive-intent\n * Recursive CTE intent types for hierarchical data traversal (RFC-001).\n */\n\nimport type { OrderByIntent } from './include-intent.js';\nimport type { WhereIntent } from './where-intent.js';\n\n// ============================================================================\n// Recursive CTE Intent - Hierarchical Data Traversal (RFC-001)\n// ============================================================================\n\n/**\n * Node ID expression for recursive CTE anchor.\n * Used to define the join key for recursive traversal.\n */\nexport type RecursiveNodeIdExpr =\n\t| { readonly kind: 'column'; readonly name: string; readonly as?: string }\n\t| {\n\t\t\treadonly kind: 'literal';\n\t\t\treadonly value: unknown;\n\t\t\treadonly as?: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'binary';\n\t\t\treadonly left: RecursiveNodeIdExpr;\n\t\t\treadonly op: string;\n\t\t\treadonly right: RecursiveNodeIdExpr;\n\t\t\treadonly as?: string;\n\t };\n\n/**\n * Get the alias for a node ID expression.\n * Used by both planner and compiler for consistent CTE column naming.\n *\n * @param expr - The node ID expression\n * @returns The alias to use (explicit alias, column name, or 'node_id' fallback)\n */\nexport function getNodeIdAlias(expr: RecursiveNodeIdExpr): string {\n\tif (expr.as) return expr.as;\n\tif (expr.kind === 'column') return expr.name;\n\tif (expr.kind === 'literal') return 'node_id';\n\t// Binary expression needs explicit alias\n\treturn 'node_id';\n}\n\n/**\n * Adjacency-list traversal (self-referential table).\n * Example: roles.parent_id → roles.id\n */\nexport interface AdjacencyTraversal {\n\treadonly kind: 'adjacency';\n\n\t/** Table containing hierarchical data */\n\treadonly nodeTable: string;\n\n\t/** Primary key column (e.g., \"id\") */\n\treadonly nodeId: string;\n\n\t/** Foreign key pointing to parent (e.g., \"parent_id\") */\n\treadonly parentId: string;\n\n\t/** Traversal direction */\n\treadonly direction: 'descendants' | 'ancestors';\n\n\t/** Filter applied to each step (e.g., active = true) */\n\treadonly stepWhere?: WhereIntent;\n}\n\n/**\n * Edge-table traversal (separate join table).\n * Example: role_inheritance(from_role_id, to_role_id)\n */\nexport interface EdgeTableTraversal {\n\treadonly kind: 'edge-table';\n\n\t/** Node table containing hierarchical data */\n\treadonly nodeTable: string;\n\n\t/** Edge table containing relationships */\n\treadonly edgeTable: string;\n\n\t/** Primary key column in node table (e.g., \"id\") */\n\treadonly nodeId: string;\n\n\t/** Source column in edge table (e.g., \"from_role_id\") */\n\treadonly edgeFrom: string;\n\n\t/** Target column in edge table (e.g., \"to_role_id\") */\n\treadonly edgeTo: string;\n\n\t/** Traversal direction */\n\treadonly direction: 'out' | 'in' | 'both';\n\n\t/** Filter on edges (e.g., relationship_type = 'inheritance') */\n\treadonly edgeWhere?: WhereIntent;\n\n\t/** Filter on nodes (e.g., active = true) */\n\treadonly nodeWhere?: WhereIntent;\n\n\t/** Edge attributes to include in result */\n\treadonly edgeSelect?: readonly string[];\n\n\t/**\n\t * Hint for edge storage semantics (only affects `direction: 'both'`).\n\t *\n\t * - 'unknown' (default): Edges may exist in both directions (A→B and B→A).\n\t * Uses UNION (distinct) to avoid duplicates. Safe but slower.\n\t * - 'directed-only': Caller guarantees edges are stored once only.\n\t * Uses UNION ALL for performance. INCORRECT if duplicates exist.\n\t */\n\treadonly edgeStorageHint?: 'unknown' | 'directed-only';\n}\n\n/**\n * Custom traversal for complex cases (P2 escape hatch).\n */\nexport interface CustomTraversal {\n\treadonly kind: 'custom';\n\t/** Explicit step query builder - reserved for P2 */\n\treadonly stepBuilder?: unknown;\n}\n\n/**\n * Recursive traversal type union.\n */\nexport type RecursiveTraversal =\n\t| AdjacencyTraversal\n\t| EdgeTableTraversal\n\t| CustomTraversal;\n\n/**\n * Tracking options for recursive traversal.\n */\nexport interface RecursiveTrackOptions {\n\t/** Depth counter (starts at 0) */\n\treadonly depth?: {\n\t\treadonly as?: string; // Default: \"depth\"\n\t};\n\n\t/** Path tracking for cycle detection + debugging */\n\treadonly path?: {\n\t\t/** Columns to trace in path (default: nodeId only) */\n\t\treadonly by?: 'nodeId' | readonly string[];\n\t\t/** Result column name (default: \"path\") */\n\t\treadonly as?: string;\n\t\t/** Storage strategy (default: 'array' for PostgreSQL, 'string' for others) */\n\t\treadonly strategy?: 'array' | 'string';\n\t\t/** Separator for string strategy (default: '/') */\n\t\treadonly separator?: string;\n\t};\n\n\t/** Cycle detection marker */\n\treadonly isCycle?: {\n\t\treadonly as?: string; // Default: \"is_cycle\"\n\t};\n}\n\n/**\n * Join clause for CTE emit composition.\n * Allows joining the CTE result with additional tables for final projection.\n */\nexport interface EmitJoinClause {\n\t/** Table to join with */\n\treadonly table: string;\n\n\t/** Join type (default: 'inner') */\n\treadonly type?: 'inner' | 'left';\n\n\t/** Alias for this table (auto-generated if not provided) */\n\treadonly as?: string;\n\n\t/** Join condition */\n\treadonly on: {\n\t\t/** Column from CTE or previous joined table */\n\t\treadonly left: string;\n\t\t/** Column from this table */\n\t\treadonly right: string;\n\t};\n\n\t/** Columns to select from this table */\n\treadonly select?: readonly (\n\t\t| string\n\t\t| { readonly column: string; readonly as: string }\n\t)[];\n}\n\n/**\n * Emit options for recursive CTE final projection.\n */\nexport interface RecursiveEmitOptions {\n\t/** Fields to select from CTE */\n\treadonly select?: readonly string[];\n\t/** Filter on generated rows */\n\treadonly where?: WhereIntent;\n\t/** Ordering */\n\treadonly orderBy?: readonly OrderByIntent[];\n\t/** Join CTE result with additional tables for composition */\n\treadonly joinWith?: readonly EmitJoinClause[];\n\t/** Apply DISTINCT to final result */\n\treadonly distinct?: boolean;\n}\n\n/**\n * PostgreSQL-specific options for recursive CTE (capability-gated).\n */\nexport interface RecursiveAdvancedOptions {\n\t/**\n\t * Cycle detection strategy (adapter-specific implementation).\n\t * - 'error': Throw on cycle detection\n\t * - 'stop': Stop traversal at cycle (prune branch)\n\t * - 'mark': Add is_cycle column to results\n\t *\n\t * PostgreSQL 14+ uses native CYCLE clause.\n\t * Other adapters may use application-level detection.\n\t */\n\treadonly cycle?: 'error' | 'stop' | 'mark';\n\n\t/**\n\t * Traversal search order (adapter-specific implementation).\n\t * - 'depth': Depth-first search order\n\t * - 'breadth': Breadth-first search order\n\t *\n\t * PostgreSQL 14+ uses native SEARCH clause.\n\t * Other adapters may use ORDER BY on depth column.\n\t */\n\treadonly search?: 'depth' | 'breadth';\n}\n\n/**\n * Deduplication strategy for recursive CTE.\n *\n * - 'none': No dedup. May return same node multiple times via different paths.\n * Fastest. Use when you need all paths or when graph is known to be a tree.\n *\n * - 'final': One row per nodeId in final output.\n * Implemented via `DISTINCT ON (nodeId)` (PostgreSQL) or\n * `ROW_NUMBER() OVER (PARTITION BY nodeId)` fallback.\n * ⚠️ NOT the same as `query.distinct()` which dedupes on entire row!\n *\n * Note: 'global' (UNION instead of UNION ALL) was considered but not implemented.\n * 'final' provides the same end result with better performance characteristics.\n */\nexport type RecursiveDedupe = 'none' | 'final';\n\n/**\n * Recursive CTE intent for hierarchical data traversal.\n *\n * Key invariant: anchor and step MUST produce identical column shape.\n * The planner validates this and auto-injects nodeIdExpr.\n *\n * @see RFC-001 for detailed specification\n */\nexport interface RecursiveIntent {\n\treadonly type: 'recursive';\n\n\t/** CTE name for the recursive query */\n\treadonly cteName: string;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// START (anchor/seed)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\treadonly start: {\n\t\t/** Source table for anchor query */\n\t\treadonly from: string;\n\n\t\t/** Filter for seed rows (e.g., where id = $userId) */\n\t\treadonly where?: WhereIntent;\n\n\t\t/**\n\t\t * REQUIRED: Expression for node ID. Auto-injected into select.\n\t\t * This ensures the recursive join always has the key column.\n\t\t */\n\t\treadonly nodeIdExpr: RecursiveNodeIdExpr;\n\n\t\t/** Additional fields to select (beyond nodeId) */\n\t\treadonly select?: readonly string[];\n\t};\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// TRAVERSAL\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Traversal configuration (adjacency-list or edge-table) */\n\treadonly traversal: RecursiveTraversal;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// TRACKING (system columns)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Tracking options for depth, path, and cycle detection */\n\treadonly track?: RecursiveTrackOptions;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// SAFETY\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Maximum recursion depth (REQUIRED) */\n\treadonly maxDepth: number;\n\n\t/** Maximum rows (optional safety limit) */\n\treadonly maxRows?: number;\n\n\t/** Deduplication strategy */\n\treadonly dedupe?: RecursiveDedupe;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// EMIT (final projection)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Final projection options */\n\treadonly emit?: RecursiveEmitOptions;\n\n\t// ─────────────────────────────────────────────────────────────────────────\n\t// ADVANCED OPTIONS (capability-gated, adapter-specific implementation)\n\t// ─────────────────────────────────────────────────────────────────────────\n\n\t/** Advanced recursive options (cycle detection, search order) */\n\treadonly advancedOptions?: RecursiveAdvancedOptions;\n}\n","/**\n * @module intent/type-guards\n * Type guard functions for all intent AST types.\n */\n\nimport type {\n\tAggregateWindowFunction,\n\tCoalesceExpressionIntent,\n\tColumnAliasIntent,\n\tExpressionIntent,\n\tOffsetWindowFunction,\n\tRankingWindowFunction,\n\tRawExpressionIntent,\n\tRelationColumnIntent,\n\tWindowFunction,\n\tWindowIntent,\n} from './expression-intent.js';\nimport type {\n\tDeleteIntent,\n\tInsertIntent,\n\tMutationIntent,\n\tUpdateIntent,\n\tUpsertIntent,\n} from './mutation-intent.js';\nimport type { QueryIntent } from './query-intent.js';\nimport type {\n\tAdjacencyTraversal,\n\tCustomTraversal,\n\tEdgeTableTraversal,\n\tRecursiveIntent,\n\tRecursiveTraversal,\n} from './recursive-intent.js';\nimport type {\n\tSelectAggregateIntent,\n\tSelectAllIntent,\n\tSelectFieldsIntent,\n\tSelectIntent,\n\tSelectWithExpressionsIntent,\n} from './select-intent.js';\nimport type {\n\tSubqueryRefIntent,\n\tWhereAndIntent,\n\tWhereAnyIntent,\n\tWhereComparisonIntent,\n\tWhereExistsIntent,\n\tWhereInIntent,\n\tWhereIntent,\n\tWhereLikeIntent,\n\tWhereNotExistsIntent,\n\tWhereNotIntent,\n\tWhereNullIntent,\n\tWhereOrIntent,\n\tWhereRangeIntent,\n\tWhereRelationFilterIntent,\n\tWhereSubqueryIntent,\n} from './where-intent.js';\n\n// ============================================================================\n// Window Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an intent is a window function intent\n */\nexport function isWindowIntent(intent: unknown): intent is WindowIntent {\n\treturn (\n\t\ttypeof intent === 'object' &&\n\t\tintent !== null &&\n\t\t'kind' in intent &&\n\t\t(intent as Record<string, unknown>).kind === 'window'\n\t);\n}\n\n/**\n * Check if a window function requires a field (aggregate or offset functions)\n */\nexport function isAggregateWindowFunction(\n\tfn: WindowFunction,\n): fn is AggregateWindowFunction | OffsetWindowFunction {\n\treturn ['sum', 'avg', 'count', 'min', 'max', 'lag', 'lead'].includes(fn);\n}\n\n/**\n * Check if a window function is a ranking function (no field required)\n */\nexport function isRankingWindowFunction(\n\tfn: WindowFunction,\n): fn is RankingWindowFunction {\n\treturn ['row_number', 'rank', 'dense_rank'].includes(fn);\n}\n\n// ============================================================================\n// Where Intent Type Guards\n// ============================================================================\n\n/**\n * Check if a where intent is a comparison\n */\nexport function isWhereComparison(\n\twhere: WhereIntent,\n): where is WhereComparisonIntent {\n\treturn where.kind === 'comparison';\n}\n\n/**\n * Check if a where intent is a like filter\n */\nexport function isWhereLike(where: WhereIntent): where is WhereLikeIntent {\n\treturn where.kind === 'like';\n}\n\n/**\n * Check if a where intent is a subquery filter\n */\nexport function isWhereSubquery(\n\twhere: WhereIntent,\n): where is WhereSubqueryIntent {\n\treturn where.kind === 'subquery';\n}\n\n/**\n * Check if a value is a subquery ref (column reference in subquery)\n */\nexport function isSubqueryRef(value: unknown): value is SubqueryRefIntent {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'kind' in value &&\n\t\t(value as Record<string, unknown>).kind === 'ref'\n\t);\n}\n\n/**\n * Check if a where intent is an in filter\n */\nexport function isWhereIn(where: WhereIntent): where is WhereInIntent {\n\treturn where.kind === 'in';\n}\n\n/**\n * Check if a where intent is an any filter (= ANY($N::type[]))\n */\nexport function isWhereAny(where: WhereIntent): where is WhereAnyIntent {\n\treturn where.kind === 'any';\n}\n\n/**\n * Check if a where intent is a null filter\n */\nexport function isWhereNull(where: WhereIntent): where is WhereNullIntent {\n\treturn where.kind === 'null';\n}\n\n/**\n * Check if a where intent is a range filter (PostgreSQL range types)\n */\nexport function isWhereRange(where: WhereIntent): where is WhereRangeIntent {\n\treturn where.kind === 'range';\n}\n\n/**\n * Check if a where intent is a logical AND\n */\nexport function isWhereAnd(where: WhereIntent): where is WhereAndIntent {\n\treturn where.kind === 'and';\n}\n\n/**\n * Check if a where intent is a logical OR\n */\nexport function isWhereOr(where: WhereIntent): where is WhereOrIntent {\n\treturn where.kind === 'or';\n}\n\n/**\n * Check if a where intent is a logical NOT\n */\nexport function isWhereNot(where: WhereIntent): where is WhereNotIntent {\n\treturn where.kind === 'not';\n}\n\n/**\n * Check if a where intent is an exists filter\n */\nexport function isWhereExists(where: WhereIntent): where is WhereExistsIntent {\n\treturn where.kind === 'exists';\n}\n\n/**\n * Check if a where intent is a not exists filter\n */\nexport function isWhereNotExists(\n\twhere: WhereIntent,\n): where is WhereNotExistsIntent {\n\treturn where.kind === 'notExists';\n}\n\n/**\n * Check if a where intent is a relation filter\n */\nexport function isWhereRelationFilter(\n\twhere: WhereIntent,\n): where is WhereRelationFilterIntent {\n\treturn where.kind === 'relationFilter';\n}\n\n/**\n * Check if a where intent is any relation-based filter\n */\nexport function isWhereRelationBased(\n\twhere: WhereIntent,\n): where is\n\t| WhereExistsIntent\n\t| WhereNotExistsIntent\n\t| WhereRelationFilterIntent {\n\treturn (\n\t\twhere.kind === 'exists' ||\n\t\twhere.kind === 'notExists' ||\n\t\twhere.kind === 'relationFilter'\n\t);\n}\n\n/**\n * Check if a where intent is a logical operator (and/or/not)\n */\nexport function isWhereLogical(\n\twhere: WhereIntent,\n): where is WhereAndIntent | WhereOrIntent | WhereNotIntent {\n\treturn where.kind === 'and' || where.kind === 'or' || where.kind === 'not';\n}\n\n// ============================================================================\n// Select Intent Type Guards\n// ============================================================================\n\n/**\n * Check if a select intent selects all columns\n */\nexport function isSelectAll(select: SelectIntent): select is SelectAllIntent {\n\treturn select.type === 'all';\n}\n\n/**\n * Check if a select intent selects specific fields\n */\nexport function isSelectFields(\n\tselect: SelectIntent,\n): select is SelectFieldsIntent {\n\treturn select.type === 'fields';\n}\n\n/**\n * Check if a select intent is an aggregate select\n */\nexport function isSelectAggregate(\n\tselect: SelectIntent,\n): select is SelectAggregateIntent {\n\treturn select.type === 'aggregate';\n}\n\n/**\n * Check if a select intent has expressions\n */\nexport function isSelectWithExpressions(\n\tselect: SelectIntent,\n): select is SelectWithExpressionsIntent {\n\treturn select.type === 'expressions';\n}\n\n// ============================================================================\n// Expression Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an expression is a COALESCE expression\n */\nexport function isCoalesceExpression(\n\texpr: ExpressionIntent,\n): expr is CoalesceExpressionIntent {\n\treturn expr.kind === 'coalesce';\n}\n\n/**\n * Check if an expression is a raw SQL expression\n */\nexport function isRawExpression(\n\texpr: ExpressionIntent,\n): expr is RawExpressionIntent {\n\treturn expr.kind === 'raw';\n}\n\n/**\n * Check if an expression is a column alias expression\n */\nexport function isColumnAliasExpression(\n\texpr: ExpressionIntent,\n): expr is ColumnAliasIntent {\n\treturn expr.kind === 'columnAlias';\n}\n\n/**\n * Check if an expression is a relation column expression\n */\nexport function isRelationColumnExpression(\n\texpr: ExpressionIntent,\n): expr is RelationColumnIntent {\n\treturn expr.kind === 'relationColumn';\n}\n\n// ============================================================================\n// Recursive CTE Type Guards\n// ============================================================================\n\n/**\n * Check if a traversal is adjacency-list based\n */\nexport function isAdjacencyTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is AdjacencyTraversal {\n\treturn traversal.kind === 'adjacency';\n}\n\n/**\n * Check if a traversal is edge-table based\n */\nexport function isEdgeTableTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is EdgeTableTraversal {\n\treturn traversal.kind === 'edge-table';\n}\n\n/**\n * Check if a traversal is custom\n */\nexport function isCustomTraversal(\n\ttraversal: RecursiveTraversal,\n): traversal is CustomTraversal {\n\treturn traversal.kind === 'custom';\n}\n\n/**\n * Check if an intent is a recursive CTE intent\n */\nexport function isRecursiveIntent(\n\tintent: QueryIntent | RecursiveIntent,\n): intent is RecursiveIntent {\n\treturn intent.type === 'recursive';\n}\n\n// ============================================================================\n// Mutation Intent Type Guards\n// ============================================================================\n\n/**\n * Check if an intent is an insert intent\n */\nexport function isInsertIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is InsertIntent {\n\treturn intent.type === 'insert';\n}\n\n/**\n * Check if an intent is an update intent\n */\nexport function isUpdateIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is UpdateIntent {\n\treturn intent.type === 'update';\n}\n\n/**\n * Check if an intent is a delete intent\n */\nexport function isDeleteIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is DeleteIntent {\n\treturn intent.type === 'delete';\n}\n\n/**\n * Check if an intent is an upsert intent (DX-026)\n */\nexport function isUpsertIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is UpsertIntent {\n\treturn intent.type === 'upsert';\n}\n\n/**\n * Check if an intent is any mutation intent\n */\nexport function isMutationIntent(\n\tintent: QueryIntent | RecursiveIntent | MutationIntent,\n): intent is MutationIntent {\n\treturn (\n\t\tintent.type === 'insert' ||\n\t\tintent.type === 'update' ||\n\t\tintent.type === 'delete' ||\n\t\tintent.type === 'upsert'\n\t);\n}\n","/**\n * @module intent/where-intent\n * Where intent types for filter conditions.\n */\n\nimport type { RangeValue } from '../shared/utils.js';\nimport type { ExpressionIntent } from './expression-intent.js';\nimport type { ComparisonOperator, NullOperator } from './operators.js';\nimport type { QueryIntent } from './query-intent.js';\nimport type { RecursiveExistsOptions } from './recursive-types.js';\n\nexport type { RangeValue };\n\n// ============================================================================\n// Where Intent - Filter Conditions\n// ============================================================================\n\n/**\n * Typed field reference for cross-table column comparisons in relation filters.\n *\n * When using aliased relation filters like `some(orders as o, o.total > minOrder)`,\n * the RHS `minOrder` is a reference to the parent table's column, not a literal value.\n * FieldRef captures this distinction so the adapter can compile it as a column reference\n * instead of a parameterized value.\n *\n * @example\n * // some(rel as r, r.col > bareCol) → value: { kind: 'fieldRef', column: 'bareCol', scope: 'outer' }\n * // some(rel as r, r.col > r.otherCol) → value: { kind: 'fieldRef', column: 'otherCol', scope: 'inner' }\n * // some(a as x, some(b as y, y.f > x.g)) → value: { kind: 'fieldRef', column: 'g', scope: 'outer', alias: 'x' }\n */\nexport interface FieldRef {\n\treadonly kind: 'fieldRef';\n\treadonly column: string;\n\treadonly scope: 'inner' | 'outer';\n\t/** Named alias for outer scope (when referencing a specific outer alias in nested filters) */\n\treadonly alias?: string;\n}\n\n/**\n * Type guard for FieldRef values\n */\nexport function isFieldRef(value: unknown): value is FieldRef {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === 'object' &&\n\t\t(value as Record<string, unknown>).kind === 'fieldRef'\n\t);\n}\n\nexport interface WhereComparisonIntent {\n\treadonly kind: 'comparison';\n\treadonly field: string;\n\treadonly operator: ComparisonOperator;\n\treadonly value: unknown;\n\t/** JSON path extraction before comparison (e.g., data->'key' = 'val') */\n\treadonly jsonPath?: readonly string[];\n\t/** JSON extraction mode: 'json' = ->, 'text' = ->> */\n\treadonly jsonMode?: 'json' | 'text';\n}\n\n/**\n * String filter: field like pattern\n */\nexport interface WhereLikeIntent {\n\treadonly kind: 'like';\n\treadonly field: string;\n\treadonly pattern: string;\n\t/** Case-insensitive matching */\n\treadonly caseInsensitive?: boolean;\n\t/** Escape character for LIKE pattern (e.g. '\\\\' to escape _ and %) */\n\treadonly escape?: string;\n}\n\n/**\n * Array filter: field in [values]\n */\nexport interface WhereInIntent {\n\treadonly kind: 'in';\n\treadonly field: string;\n\treadonly values: readonly unknown[];\n\t/** Optional subquery producing the value set (when present, values is empty) */\n\treadonly subquery?: QueryIntent;\n}\n\n/**\n * Array membership filter using PostgreSQL ANY() operator.\n * Compiles to: \"col\" = ANY($N::type[])\n */\nexport interface WhereAnyIntent {\n\treadonly kind: 'any';\n\treadonly field: string;\n\treadonly values: readonly unknown[];\n}\n\n/**\n * Range operator for PostgreSQL range types.\n * - overlaps: && (ranges have common points)\n * - contains: @> (range contains value or range)\n * - containedBy: <@ (range is contained by another range)\n */\nexport type RangeOperator = 'overlaps' | 'contains' | 'containedBy' | 'between';\n\n/**\n * Range filter: field overlaps/contains/containedBy range value\n * PostgreSQL range types: daterange, tsrange, tstzrange, int4range, int8range, numrange\n *\n * @example\n * // Check if booking dates overlap a period\n * { kind: 'range', field: 'dates', operator: 'overlaps', value: { lower: '2025-01-15', upper: '2025-01-20' } }\n *\n * // Check if salary range contains a value\n * { kind: 'range', field: 'salary_range', operator: 'contains', value: 50000 }\n */\nexport interface WhereRangeIntent {\n\treadonly kind: 'range';\n\treadonly field: string;\n\treadonly operator: RangeOperator;\n\t/** Can be a RangeValue (for range-to-range ops) or scalar (for contains/containedBy with point) */\n\treadonly value: RangeValue | unknown;\n}\n\n/**\n * Null filter: field is null / is not null\n */\nexport interface WhereNullIntent {\n\treadonly kind: 'null';\n\treadonly field: string;\n\treadonly operator: NullOperator;\n}\n\n/**\n * Logical AND: all conditions must match\n */\nexport interface WhereAndIntent {\n\treadonly kind: 'and';\n\treadonly conditions: readonly WhereIntent[];\n}\n\n/**\n * Logical OR: at least one condition must match\n */\nexport interface WhereOrIntent {\n\treadonly kind: 'or';\n\treadonly conditions: readonly WhereIntent[];\n}\n\n/**\n * Logical NOT: condition must not match\n */\nexport interface WhereNotIntent {\n\treadonly kind: 'not';\n\treadonly condition: WhereIntent;\n}\n\n/**\n * Relation exists filter: filter by existence of related records\n * Critical for Q1 golden test - enables EXISTS subquery strategy\n *\n * @example\n * // Find users who have at least one published post\n * { kind: 'exists', relation: 'posts', where: { kind: 'comparison', field: 'status', operator: 'eq', value: 'published' } }\n */\nexport interface WhereExistsIntent {\n\treadonly kind: 'exists';\n\t/** Relation name to check existence */\n\treadonly relation: string;\n\t/** Optional filter on related records */\n\treadonly where?: WhereIntent;\n\t/**\n\t * Recursive options for ancestor/descendant existence checks.\n\t * When present, generates a recursive CTE instead of simple EXISTS.\n\t */\n\treadonly recursive?: RecursiveExistsOptions;\n\t/**\n\t * Optional JOIN declarations inside the EXISTS subquery.\n\t * Keys are relation names (used as aliases), values specify join type.\n\t * Enables filtering on joined tables inside the subquery.\n\t *\n\t * @example\n\t * exists('callers', {\n\t * include: { callerFile: { join: 'inner' } },\n\t * where: eq('callerFile.project_id', projectId)\n\t * })\n\t */\n\treadonly include?: Readonly<Record<string, { join?: 'inner' | 'left' }>>;\n}\n\n/**\n * Relation not exists filter: filter by absence of related records\n *\n * @example\n * // Find users who have no posts\n * { kind: 'notExists', relation: 'posts' }\n */\nexport interface WhereNotExistsIntent {\n\treadonly kind: 'notExists';\n\t/** Relation name to check absence */\n\treadonly relation: string;\n\t/** Optional filter on related records */\n\treadonly where?: WhereIntent;\n\t/**\n\t * Recursive options for ancestor/descendant absence checks.\n\t * When present, generates a recursive CTE instead of simple NOT EXISTS.\n\t */\n\treadonly recursive?: RecursiveExistsOptions;\n\t/**\n\t * Optional JOIN declarations inside the NOT EXISTS subquery.\n\t * Keys are relation names (used as aliases), values specify join type.\n\t * Enables filtering on joined tables inside the subquery.\n\t *\n\t * @example\n\t * notExists('callers', {\n\t * include: { callerFile: { join: 'inner' } },\n\t * where: eq('callerFile.project_id', projectId)\n\t * })\n\t */\n\treadonly include?: Readonly<Record<string, { join?: 'inner' | 'left' }>>;\n}\n\n/**\n * Raw EXISTS subquery filter using an arbitrary QueryIntent.\n * Unlike WhereExistsIntent (which uses FK-resolved relation names),\n * this wraps a fully-specified subquery for correlated EXISTS checks.\n *\n * @example\n * // EXISTS (SELECT 1 FROM symbols WHERE symbols.id = calls.symbol_id AND ...)\n * exists(subquery('symbols').where(eq('id', ref('calls.symbol_id'))))\n */\nexport interface WhereRawExistsIntent {\n\treadonly kind: 'rawExists';\n\t/** The subquery producing rows for the EXISTS check */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Raw NOT EXISTS subquery filter using an arbitrary QueryIntent.\n *\n * @example\n * // NOT EXISTS (SELECT 1 FROM symbols WHERE ...)\n * notExists(subquery('symbols').where(...))\n */\nexport interface WhereRawNotExistsIntent {\n\treadonly kind: 'rawNotExists';\n\t/** The subquery producing rows for the NOT EXISTS check */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Relation filter: filter parent by conditions on related records\n * More flexible than exists - allows filtering by related record attributes\n *\n * @example\n * // Find users whose latest post was created in 2024\n * { kind: 'relationFilter', relation: 'posts', where: {...}, mode: 'some' }\n */\nexport interface WhereRelationFilterIntent {\n\treadonly kind: 'relationFilter';\n\t/**\n\t * Relation path for filtering.\n\t * - Single relation: 'posts' or ['posts']\n\t * - Multi-hop (SPEC-002): ['author', 'company'] for author.company traversal\n\t */\n\treadonly relation: string | readonly string[];\n\t/** Filter conditions on related records */\n\treadonly where: WhereIntent;\n\t/**\n\t * Match mode:\n\t * - 'some': At least one related record matches (default)\n\t * - 'every': All related records match\n\t * - 'none': No related records match\n\t */\n\treadonly mode: 'some' | 'every' | 'none';\n\t/** Optional alias for complex conditions (SPEC-002) */\n\treadonly alias?: string | undefined;\n}\n\n// ============================================================================\n// Subquery Intent - Scalar Subquery in WHERE\n// ============================================================================\n\n/**\n * Reference to a parent query column in a subquery.\n * Used to create correlated subqueries.\n *\n * @example\n * // Reference parent 'id' column in subquery WHERE\n * { kind: 'ref', column: 'id' }\n * { kind: 'ref', column: 't0.id' } // with alias\n */\nexport interface SubqueryRefIntent {\n\treadonly kind: 'ref';\n\t/** Column name or aliased column (e.g., 'id' or 't0.id') */\n\treadonly column: string;\n}\n\n/**\n * Subquery intent for scalar subquery comparisons.\n * Produces correlated subqueries in SQL.\n *\n * @example\n * // Find products where price equals max price of category\n * {\n * kind: 'subquery',\n * field: 'price',\n * operator: 'eq',\n * subquery: { from: 'products', select: { kind: 'aggregate', fn: 'max', field: 'price' } }\n * }\n */\nexport interface WhereSubqueryIntent {\n\treadonly kind: 'subquery';\n\t/** Field to compare on the parent query */\n\treadonly field: string;\n\t/** Comparison operator */\n\treadonly operator: ComparisonOperator;\n\t/** Subquery producing scalar value */\n\treadonly subquery: QueryIntent;\n}\n\n/**\n * Scalar subquery intent - produces a single value.\n * Simplified QueryIntent for subquery context.\n */\n/** @deprecated Use QueryIntent instead — subqueries are full queries with contextual validation */\nexport type ScalarSubqueryIntent = QueryIntent;\n\n// ============================================================================\n// JSON/JSONB WHERE Intents (E13)\n// ============================================================================\n\n/**\n * JSON containment filter: col @> value or col <@ value.\n * @example { kind: 'jsonContains', field: 'data', value: '{\"active\":true}', reversed: false }\n * → WHERE \"data\" @> $1\n */\nexport interface WhereJsonContainsIntent {\n\treadonly kind: 'jsonContains';\n\treadonly field: string;\n\treadonly value: unknown;\n\t/** false = @> (field contains value), true = <@ (field contained by value) */\n\treadonly reversed: boolean;\n}\n\n/**\n * JSON key existence filter: col ? 'key'.\n * @example { kind: 'jsonExists', field: 'data', key: 'email' }\n * → WHERE \"data\" ? $1\n */\nexport interface WhereJsonExistsIntent {\n\treadonly kind: 'jsonExists';\n\treadonly field: string;\n\treadonly key: string;\n}\n\n/** WHERE clause using a custom expression with comparison */\nexport interface WhereExpressionIntent {\n\treadonly kind: 'expression';\n\treadonly expr: ExpressionIntent;\n\treadonly operator: ComparisonOperator;\n\treadonly value: unknown;\n}\n\n/**\n * Where intent - filter conditions union type\n * Discriminated union using 'kind' field\n */\nexport type WhereIntent =\n\t| WhereComparisonIntent\n\t| WhereLikeIntent\n\t| WhereInIntent\n\t| WhereAnyIntent\n\t| WhereNullIntent\n\t| WhereRangeIntent\n\t| WhereAndIntent\n\t| WhereOrIntent\n\t| WhereNotIntent\n\t| WhereExistsIntent\n\t| WhereNotExistsIntent\n\t| WhereRawExistsIntent\n\t| WhereRawNotExistsIntent\n\t| WhereRelationFilterIntent\n\t| WhereSubqueryIntent\n\t| WhereJsonContainsIntent\n\t| WhereJsonExistsIntent\n\t| WhereExpressionIntent;\n","import type { ModelIR } from './model-ir.js';\n\n/**\n * Canonical shape of a `schema()` factory result as produced by\n * `createOrm({schema: ...})` callers and consumed by tooling\n * (cli, gui sidecar, mcp-server).\n *\n * ARCH-005: Schema type from schema() function.\n * Contains the definition, pre-computed ModelIR, and table names.\n */\nexport interface LoadedSchema {\n\treadonly definition: Record<string, unknown>;\n\treadonly model: ModelIR;\n\treadonly tableNames: string[];\n}\n\n/**\n * Runtime type guard for `LoadedSchema` — verifies the object has\n * `definition`, `model` (with nested `tables` + `relations`), and\n * `tableNames` as an array. Structural check only — does not validate\n * the inner values of any field.\n *\n * Type guard for ARCH-005 schema() output.\n */\nexport function isValidSchema(schema: unknown): schema is LoadedSchema {\n\tif (\n\t\ttypeof schema !== 'object' ||\n\t\tschema === null ||\n\t\t!('model' in schema) ||\n\t\t!('definition' in schema) ||\n\t\t!('tableNames' in schema)\n\t) {\n\t\treturn false;\n\t}\n\tconst s = schema as LoadedSchema;\n\tif (typeof s.model !== 'object' || s.model === null) return false;\n\tif (!('tables' in s.model) || !('relations' in s.model)) return false;\n\tif (!Array.isArray(s.tableNames)) return false;\n\treturn true;\n}\n"],"mappings":";AA8sBO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EAClD,YACU,SACA,SACA,SACR;AACD;AAAA,MACC,wBAAwB,OAAO,iBAAiB,OAAO,UAAU,OAAO;AAAA,IACzE;AANS;AACA;AACA;AAKT,SAAK,OAAO;AAAA,EACb;AAAA,EARU;AAAA,EACA;AAAA,EACA;AAOX;;;ACnrBO,SAAS,eAAe,MAAmC;AACjE,MAAI,KAAK,GAAI,QAAO,KAAK;AACzB,MAAI,KAAK,SAAS,SAAU,QAAO,KAAK;AACxC,MAAI,KAAK,SAAS,UAAW,QAAO;AAEpC,SAAO;AACR;;;ACoBO,SAAS,eAAe,QAAyC;AACvE,SACC,OAAO,WAAW,YAClB,WAAW,QACX,UAAU,UACT,OAAmC,SAAS;AAE/C;AAKO,SAAS,0BACf,IACuD;AACvD,SAAO,CAAC,OAAO,OAAO,SAAS,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,EAAE;AACxE;AAKO,SAAS,wBACf,IAC8B;AAC9B,SAAO,CAAC,cAAc,QAAQ,YAAY,EAAE,SAAS,EAAE;AACxD;AASO,SAAS,kBACf,OACiC;AACjC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,YAAY,OAA8C;AACzE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,gBACf,OAC+B;AAC/B,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,cAAc,OAA4C;AACzE,SACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAAkC,SAAS;AAE9C;AAKO,SAAS,UAAU,OAA4C;AACrE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,YAAY,OAA8C;AACzE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,aAAa,OAA+C;AAC3E,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,UAAU,OAA4C;AACrE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,WAAW,OAA6C;AACvE,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,cAAc,OAAgD;AAC7E,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,iBACf,OACgC;AAChC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,sBACf,OACqC;AACrC,SAAO,MAAM,SAAS;AACvB;AAKO,SAAS,qBACf,OAI4B;AAC5B,SACC,MAAM,SAAS,YACf,MAAM,SAAS,eACf,MAAM,SAAS;AAEjB;AAKO,SAAS,eACf,OAC2D;AAC3D,SAAO,MAAM,SAAS,SAAS,MAAM,SAAS,QAAQ,MAAM,SAAS;AACtE;AASO,SAAS,YAAY,QAAiD;AAC5E,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QAC+B;AAC/B,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,kBACf,QACkC;AAClC,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,wBACf,QACwC;AACxC,SAAO,OAAO,SAAS;AACxB;AASO,SAAS,qBACf,MACmC;AACnC,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,gBACf,MAC8B;AAC9B,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,wBACf,MAC4B;AAC5B,SAAO,KAAK,SAAS;AACtB;AAKO,SAAS,2BACf,MAC+B;AAC/B,SAAO,KAAK,SAAS;AACtB;AASO,SAAS,qBACf,WACkC;AAClC,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,qBACf,WACkC;AAClC,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,kBACf,WAC+B;AAC/B,SAAO,UAAU,SAAS;AAC3B;AAKO,SAAS,kBACf,QAC4B;AAC5B,SAAO,OAAO,SAAS;AACxB;AASO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,eACf,QACyB;AACzB,SAAO,OAAO,SAAS;AACxB;AAKO,SAAS,iBACf,QAC2B;AAC3B,SACC,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS,YAChB,OAAO,SAAS;AAElB;;;ACxWO,SAAS,WAAW,OAAmC;AAC7D,SACC,UAAU,QACV,OAAO,UAAU,YAChB,MAAkC,SAAS;AAE9C;;;ACvBO,SAAS,cAAc,QAAyC;AACtE,MACC,OAAO,WAAW,YAClB,WAAW,QACX,EAAE,WAAW,WACb,EAAE,gBAAgB,WAClB,EAAE,gBAAgB,SACjB;AACD,WAAO;AAAA,EACR;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,UAAU,YAAY,EAAE,UAAU,KAAM,QAAO;AAC5D,MAAI,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,OAAQ,QAAO;AAChE,MAAI,CAAC,MAAM,QAAQ,EAAE,UAAU,EAAG,QAAO;AACzC,SAAO;AACR;","names":[]}
|