@dbsp/types 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Olivier Orabona
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @dbsp/types
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@dbsp/types.svg)](https://www.npmjs.com/package/@dbsp/types)
4
+ [![license](https://img.shields.io/npm/l/@dbsp/types.svg)](LICENSE)
5
+
6
+ Shared TypeScript contract types for the `@dbsp` ecosystem — `ModelIR`, `IntentAST`, `PlanReport`, and the `Adapter` interface.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pnpm add @dbsp/types
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ // doctest: skip — illustrative data/type literal fragment (TypeScript type annotations and { ... } placeholder not executable code)
18
+ import type { ModelIR, IntentAST, PlanReport, Adapter } from '@dbsp/types';
19
+
20
+ // Type-check your adapter implementation
21
+ const myAdapter: Adapter = { ... };
22
+
23
+ // Annotate plan report handlers
24
+ function inspect(report: PlanReport): void {
25
+ for (const decision of report.decisions) {
26
+ console.log(decision.kind, decision.reason);
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Key types
32
+
33
+ - **`ModelIR`** — Schema representation: tables, columns, relations, constraints, RLS policies
34
+ - **`IntentAST`** — Declarative query intent: selections, filters, includes, ordering
35
+ - **`PlanReport`** — Planner output: decisions, warnings, simplified plan used by adapters
36
+ - **`Adapter`** — Port interface every adapter must implement (`compile`, `execute`, `withSchema`)
37
+ - **`DialectCapabilities`** — Feature flags negotiated between core and an adapter
38
+
39
+ ## Notes
40
+
41
+ `@dbsp/types` is a zero-dependency package with no runtime code — it is types-only. All `@dbsp/*` packages share this contract, which breaks the circular dependency between `core` and `adapter-pgsql`.
42
+
43
+ ## Documentation
44
+
45
+ See the [architecture overview](../../ARCHITECTURE.md) and [guides](https://oorabona.github.io/db-semantic-planner/guide/) for details.
46
+
47
+ ## License
48
+
49
+ MIT
@@ -0,0 +1,194 @@
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
+ // src/intent/recursive-intent.ts
18
+ function getNodeIdAlias(expr) {
19
+ if (expr.as) return expr.as;
20
+ if (expr.kind === "column") return expr.name;
21
+ if (expr.kind === "literal") return "node_id";
22
+ return "node_id";
23
+ }
24
+
25
+ // src/intent/type-guards.ts
26
+ function isWindowIntent(intent) {
27
+ return typeof intent === "object" && intent !== null && "kind" in intent && intent.kind === "window";
28
+ }
29
+ function isAggregateWindowFunction(fn) {
30
+ return ["sum", "avg", "count", "min", "max", "lag", "lead"].includes(fn);
31
+ }
32
+ function isRankingWindowFunction(fn) {
33
+ return ["row_number", "rank", "dense_rank"].includes(fn);
34
+ }
35
+ function isWhereComparison(where) {
36
+ return where.kind === "comparison";
37
+ }
38
+ function isWhereLike(where) {
39
+ return where.kind === "like";
40
+ }
41
+ function isWhereSubquery(where) {
42
+ return where.kind === "subquery";
43
+ }
44
+ function isSubqueryRef(value) {
45
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === "ref";
46
+ }
47
+ function isWhereIn(where) {
48
+ return where.kind === "in";
49
+ }
50
+ function isWhereAny(where) {
51
+ return where.kind === "any";
52
+ }
53
+ function isWhereNull(where) {
54
+ return where.kind === "null";
55
+ }
56
+ function isWhereRange(where) {
57
+ return where.kind === "range";
58
+ }
59
+ function isWhereAnd(where) {
60
+ return where.kind === "and";
61
+ }
62
+ function isWhereOr(where) {
63
+ return where.kind === "or";
64
+ }
65
+ function isWhereNot(where) {
66
+ return where.kind === "not";
67
+ }
68
+ function isWhereExists(where) {
69
+ return where.kind === "exists";
70
+ }
71
+ function isWhereNotExists(where) {
72
+ return where.kind === "notExists";
73
+ }
74
+ function isWhereRelationFilter(where) {
75
+ return where.kind === "relationFilter";
76
+ }
77
+ function isWhereRelationBased(where) {
78
+ return where.kind === "exists" || where.kind === "notExists" || where.kind === "relationFilter";
79
+ }
80
+ function isWhereLogical(where) {
81
+ return where.kind === "and" || where.kind === "or" || where.kind === "not";
82
+ }
83
+ function isSelectAll(select) {
84
+ return select.type === "all";
85
+ }
86
+ function isSelectFields(select) {
87
+ return select.type === "fields";
88
+ }
89
+ function isSelectAggregate(select) {
90
+ return select.type === "aggregate";
91
+ }
92
+ function isSelectWithExpressions(select) {
93
+ return select.type === "expressions";
94
+ }
95
+ function isCoalesceExpression(expr) {
96
+ return expr.kind === "coalesce";
97
+ }
98
+ function isRawExpression(expr) {
99
+ return expr.kind === "raw";
100
+ }
101
+ function isColumnAliasExpression(expr) {
102
+ return expr.kind === "columnAlias";
103
+ }
104
+ function isRelationColumnExpression(expr) {
105
+ return expr.kind === "relationColumn";
106
+ }
107
+ function isAdjacencyTraversal(traversal) {
108
+ return traversal.kind === "adjacency";
109
+ }
110
+ function isEdgeTableTraversal(traversal) {
111
+ return traversal.kind === "edge-table";
112
+ }
113
+ function isCustomTraversal(traversal) {
114
+ return traversal.kind === "custom";
115
+ }
116
+ function isRecursiveIntent(intent) {
117
+ return intent.type === "recursive";
118
+ }
119
+ function isInsertIntent(intent) {
120
+ return intent.type === "insert";
121
+ }
122
+ function isUpdateIntent(intent) {
123
+ return intent.type === "update";
124
+ }
125
+ function isDeleteIntent(intent) {
126
+ return intent.type === "delete";
127
+ }
128
+ function isUpsertIntent(intent) {
129
+ return intent.type === "upsert";
130
+ }
131
+ function isMutationIntent(intent) {
132
+ return intent.type === "insert" || intent.type === "update" || intent.type === "delete" || intent.type === "upsert";
133
+ }
134
+
135
+ // src/intent/where-intent.ts
136
+ function isFieldRef(value) {
137
+ return value !== null && typeof value === "object" && value.kind === "fieldRef";
138
+ }
139
+
140
+ // src/loaded-schema.ts
141
+ function isValidSchema(schema) {
142
+ if (typeof schema !== "object" || schema === null || !("model" in schema) || !("definition" in schema) || !("tableNames" in schema)) {
143
+ return false;
144
+ }
145
+ const s = schema;
146
+ if (typeof s.model !== "object" || s.model === null) return false;
147
+ if (!("tables" in s.model) || !("relations" in s.model)) return false;
148
+ if (!Array.isArray(s.tableNames)) return false;
149
+ return true;
150
+ }
151
+
152
+ export {
153
+ UnsupportedFeatureError,
154
+ getNodeIdAlias,
155
+ isWindowIntent,
156
+ isAggregateWindowFunction,
157
+ isRankingWindowFunction,
158
+ isWhereComparison,
159
+ isWhereLike,
160
+ isWhereSubquery,
161
+ isSubqueryRef,
162
+ isWhereIn,
163
+ isWhereAny,
164
+ isWhereNull,
165
+ isWhereRange,
166
+ isWhereAnd,
167
+ isWhereOr,
168
+ isWhereNot,
169
+ isWhereExists,
170
+ isWhereNotExists,
171
+ isWhereRelationFilter,
172
+ isWhereRelationBased,
173
+ isWhereLogical,
174
+ isSelectAll,
175
+ isSelectFields,
176
+ isSelectAggregate,
177
+ isSelectWithExpressions,
178
+ isCoalesceExpression,
179
+ isRawExpression,
180
+ isColumnAliasExpression,
181
+ isRelationColumnExpression,
182
+ isAdjacencyTraversal,
183
+ isEdgeTableTraversal,
184
+ isCustomTraversal,
185
+ isRecursiveIntent,
186
+ isInsertIntent,
187
+ isUpdateIntent,
188
+ isDeleteIntent,
189
+ isUpsertIntent,
190
+ isMutationIntent,
191
+ isFieldRef,
192
+ isValidSchema
193
+ };
194
+ //# sourceMappingURL=chunk-5L5N5N5J.js.map
@@ -0,0 +1 @@
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":[]}