@danceroutine/tango-orm 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PostgresAdapter-BFdo_nIt.js +4 -0
- package/dist/{PostgresAdapter-C9a1XJRx.js → PostgresAdapter-CMiEpHya.js} +4 -52
- package/dist/PostgresAdapter-CMiEpHya.js.map +1 -0
- package/dist/PostgresClient-BQJZfEOT.js +68 -0
- package/dist/PostgresClient-BQJZfEOT.js.map +1 -0
- package/dist/SqliteAdapter-A-P9zUhP.js +4 -0
- package/dist/SqliteAdapter-CeqhyrPC.js +44 -0
- package/dist/SqliteAdapter-CeqhyrPC.js.map +1 -0
- package/dist/{SqliteAdapter-Dp6VRXmz.js → SqliteClient-CjOK9-ki.js} +20 -41
- package/dist/SqliteClient-CjOK9-ki.js.map +1 -0
- package/dist/connection/clients/DBClient.d.ts +6 -0
- package/dist/connection/clients/dialects/PostgresClient.d.ts +21 -5
- package/dist/connection/clients/dialects/SqliteClient.d.ts +13 -1
- package/dist/connection/index.js +5 -3
- package/dist/{connection-CVvycXus.js → connection-B_K2ZAf7.js} +7 -5
- package/dist/{connection-CVvycXus.js.map → connection-B_K2ZAf7.js.map} +1 -1
- package/dist/defaultRuntime-BPK9kWEW.js +447 -0
- package/dist/defaultRuntime-BPK9kWEW.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +12 -9
- package/dist/manager/ManagerLike.d.ts +8 -8
- package/dist/manager/ModelManager.d.ts +15 -13
- package/dist/manager/index.js +6 -6
- package/dist/manager/internal/RuntimeBoundClient.d.ts +5 -1
- package/dist/{manager-CKUy1CIt.js → manager-C6oJ2tAF.js} +2 -2
- package/dist/{manager-CKUy1CIt.js.map → manager-C6oJ2tAF.js.map} +1 -1
- package/dist/query/QuerySet.d.ts +45 -30
- package/dist/query/compiler/QueryCompiler.d.ts +11 -1
- package/dist/query/domain/CompiledQuery.d.ts +21 -0
- package/dist/query/domain/RelationMeta.d.ts +3 -3
- package/dist/query/domain/RelationTyping.d.ts +74 -0
- package/dist/query/domain/index.d.ts +2 -0
- package/dist/query/index.js +1 -1
- package/dist/{query-BKt2nKIt.js → query-CWZ1cfjo.js} +221 -28
- package/dist/query-CWZ1cfjo.js.map +1 -0
- package/dist/{registerModelObjects-vsX6GzCN.js → registerModelObjects-Bva_f-Qh.js} +34 -134
- package/dist/registerModelObjects-Bva_f-Qh.js.map +1 -0
- package/dist/runtime/TangoRuntime.d.ts +17 -4
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +6 -6
- package/dist/runtime/internal/DBClientProvider.d.ts +12 -0
- package/dist/runtime/internal/PostgresDBClientProvider.d.ts +12 -0
- package/dist/runtime/internal/SqliteDBClientProvider.d.ts +16 -0
- package/dist/runtime/internal/createDBClientProvider.d.ts +5 -0
- package/dist/{runtime-BUpil272.js → runtime-ByXbpVBS.js} +3 -2
- package/dist/runtime-ByXbpVBS.js.map +1 -0
- package/dist/transaction/AtomicTransaction.d.ts +32 -0
- package/dist/transaction/UnitOfWork.d.ts +3 -0
- package/dist/transaction/atomic.d.ts +2 -0
- package/dist/transaction/index.d.ts +2 -0
- package/dist/transaction/index.js +5 -2
- package/dist/transaction/internal/context/AsyncLocalTransactionEngine.d.ts +21 -0
- package/dist/transaction/internal/context/CallbackRecord.d.ts +5 -0
- package/dist/transaction/internal/context/FrameBoundTransaction.d.ts +20 -0
- package/dist/transaction/internal/context/FrameTransactionHandle.d.ts +4 -0
- package/dist/transaction/internal/context/TransactionEngine.d.ts +16 -0
- package/dist/transaction/internal/context/TransactionFrame.d.ts +7 -0
- package/dist/transaction/internal/context/TransactionState.d.ts +10 -0
- package/dist/transaction/internal/context/index.d.ts +1 -0
- package/dist/{transaction-DooTMuAl.js → transaction-Cs0Z9tbW.js} +15 -3
- package/dist/transaction-Cs0Z9tbW.js.map +1 -0
- package/dist/validation/SQLValidationEngine.d.ts +3 -3
- package/package.json +6 -6
- package/dist/PostgresAdapter-C9a1XJRx.js.map +0 -1
- package/dist/PostgresAdapter-CBc1u8eT.js +0 -3
- package/dist/SqliteAdapter-BJKNxCvS.js +0 -3
- package/dist/SqliteAdapter-Dp6VRXmz.js.map +0 -1
- package/dist/query-BKt2nKIt.js.map +0 -1
- package/dist/registerModelObjects-vsX6GzCN.js.map +0 -1
- package/dist/runtime-BUpil272.js.map +0 -1
- package/dist/transaction-DooTMuAl.js.map +0 -1
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { __export } from "./chunk-DLY2FNSh.js";
|
|
2
2
|
import { SqlSafetyEngine } from "@danceroutine/tango-core";
|
|
3
3
|
|
|
4
|
+
//#region src/query/domain/internal/InternalRelationKind.ts
|
|
5
|
+
const InternalRelationKind = {
|
|
6
|
+
HAS_MANY: "hasMany",
|
|
7
|
+
BELONGS_TO: "belongsTo",
|
|
8
|
+
HAS_ONE: "hasOne",
|
|
9
|
+
MANY_TO_MANY: "manyToMany"
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
4
13
|
//#region src/query/domain/internal/InternalDialect.ts
|
|
5
14
|
const InternalDialect = {
|
|
6
15
|
POSTGRES: "postgres",
|
|
@@ -110,6 +119,7 @@ var OrmSqlSafetyAdapter = class OrmSqlSafetyAdapter {
|
|
|
110
119
|
validateRelationMeta(meta, relationName, relations) {
|
|
111
120
|
const relation = relations?.[relationName];
|
|
112
121
|
if (!relation) throw new Error(`Unknown relation '${relationName}' for table '${meta.table}'.`);
|
|
122
|
+
if (!(relation.targetKey in relation.targetColumns)) throw new Error(`Unknown relation target key '${relation.targetKey}' for relation '${relationName}'.`);
|
|
113
123
|
const validated = this.engine.validate({ identifiers: [
|
|
114
124
|
{
|
|
115
125
|
key: "table",
|
|
@@ -122,23 +132,23 @@ var OrmSqlSafetyAdapter = class OrmSqlSafetyAdapter {
|
|
|
122
132
|
value: relation.alias
|
|
123
133
|
},
|
|
124
134
|
{
|
|
125
|
-
key: "
|
|
135
|
+
key: "targetKey",
|
|
126
136
|
role: "relationTargetPrimaryKey",
|
|
127
|
-
value: relation.
|
|
137
|
+
value: relation.targetKey
|
|
128
138
|
},
|
|
129
|
-
...relation.
|
|
130
|
-
key:
|
|
131
|
-
role: "
|
|
132
|
-
value:
|
|
133
|
-
}
|
|
139
|
+
...Object.keys(relation.targetColumns).map((column) => ({
|
|
140
|
+
key: `targetColumn:${column}`,
|
|
141
|
+
role: "column",
|
|
142
|
+
value: column
|
|
143
|
+
}))
|
|
134
144
|
] });
|
|
135
145
|
return {
|
|
136
146
|
...relation,
|
|
137
147
|
table: validated.identifiers.table.value,
|
|
138
148
|
alias: validated.identifiers.alias.value,
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
149
|
+
sourceKey: this.resolveColumn(meta, relation.sourceKey),
|
|
150
|
+
targetKey: validated.identifiers.targetKey.value,
|
|
151
|
+
targetColumns: Object.fromEntries(Object.keys(relation.targetColumns).map((column) => [validated.identifiers[`targetColumn:${column}`].value, relation.targetColumns[column]]))
|
|
142
152
|
};
|
|
143
153
|
}
|
|
144
154
|
validateFilterKey(meta, rawKey) {
|
|
@@ -165,7 +175,6 @@ var OrmSqlSafetyAdapter = class OrmSqlSafetyAdapter {
|
|
|
165
175
|
resolveRelation(meta, relationName) {
|
|
166
176
|
const relation = meta.relations?.[relationName];
|
|
167
177
|
if (!relation) throw new Error(`Unknown relation '${relationName}' for table '${meta.table}'.`);
|
|
168
|
-
if (relation.kind === "belongsTo" && !relation.localKey) throw new Error(`Relation '${relationName}' for table '${meta.table}' requires a local key.`);
|
|
169
178
|
return relation;
|
|
170
179
|
}
|
|
171
180
|
};
|
|
@@ -193,14 +202,16 @@ var QueryCompiler = class QueryCompiler {
|
|
|
193
202
|
* Compile a query state tree into a SQL statement and bound parameters.
|
|
194
203
|
*/
|
|
195
204
|
compile(state) {
|
|
196
|
-
const
|
|
205
|
+
const selectRelationNames = state.selectRelated ?? [];
|
|
206
|
+
const prefetchRelationNames = state.prefetchRelated ?? [];
|
|
207
|
+
const relationNames = [...new Set([...selectRelationNames, ...prefetchRelationNames])];
|
|
197
208
|
const validatedPlan = sqlSafetyAdapter.validate({
|
|
198
209
|
kind: "select",
|
|
199
210
|
meta: this.meta,
|
|
200
211
|
selectFields: state.select?.map(String),
|
|
201
212
|
filterKeys: this.collectStateFilterKeys(state),
|
|
202
213
|
orderFields: state.order?.map((order) => String(order.by)),
|
|
203
|
-
relationNames
|
|
214
|
+
relationNames
|
|
204
215
|
});
|
|
205
216
|
const table = validatedPlan.meta.table;
|
|
206
217
|
const whereParts = [];
|
|
@@ -222,12 +233,26 @@ var QueryCompiler = class QueryCompiler {
|
|
|
222
233
|
params.push(...result.params);
|
|
223
234
|
}
|
|
224
235
|
});
|
|
225
|
-
const
|
|
226
|
-
const
|
|
236
|
+
const baseSelect = state.select?.length ? state.select.map((field) => validatedPlan.selectFields[String(field)]).join(", ") : `${table}.*`;
|
|
237
|
+
const relationSelects = selectRelationNames.flatMap((relationName) => {
|
|
238
|
+
const relation = validatedPlan.relations[relationName];
|
|
239
|
+
return Object.keys(relation.targetColumns).map((column) => `${relation.alias}.${column} AS ${this.buildHydrationColumnAlias(relation.alias, column)}`);
|
|
240
|
+
});
|
|
241
|
+
const prefetchSourceSelects = state.select?.length && prefetchRelationNames.length ? prefetchRelationNames.map((relationName) => validatedPlan.relations[relationName]).filter((relation) => !state.select.map(String).includes(relation.sourceKey)).map((relation) => `${table}.${relation.sourceKey} AS ${this.buildPrefetchSourceAlias(relation.sourceKey)}`) : [];
|
|
242
|
+
const select = [
|
|
243
|
+
baseSelect,
|
|
244
|
+
...relationSelects,
|
|
245
|
+
...prefetchSourceSelects
|
|
246
|
+
].join(", ");
|
|
247
|
+
const joins = selectRelationNames.map((rel) => {
|
|
227
248
|
const relation = validatedPlan.relations[rel];
|
|
228
|
-
if (
|
|
229
|
-
return `LEFT JOIN ${relation.table} ${relation.alias} ON ${relation.alias}.${relation.
|
|
249
|
+
if (relation.kind !== InternalRelationKind.BELONGS_TO && relation.kind !== InternalRelationKind.HAS_ONE) throw new Error(`Relation '${rel}' cannot be loaded with selectRelated(...).`);
|
|
250
|
+
return `LEFT JOIN ${relation.table} ${relation.alias} ON ${relation.alias}.${relation.targetKey} = ${table}.${relation.sourceKey}`;
|
|
230
251
|
}).filter(Boolean).join(" ");
|
|
252
|
+
for (const rel of prefetchRelationNames) {
|
|
253
|
+
const relation = validatedPlan.relations[rel];
|
|
254
|
+
if (relation?.kind !== InternalRelationKind.HAS_MANY) throw new Error(`Relation '${rel}' cannot be loaded with prefetchRelated(...).`);
|
|
255
|
+
}
|
|
231
256
|
const whereSQL = whereParts.length ? ` WHERE ${whereParts.join(" AND ")}` : "";
|
|
232
257
|
const orderSQL = ` ORDER BY ${state.order?.length ? state.order.map((order) => `${validatedPlan.orderFields[String(order.by)]} ${order.dir.toUpperCase()}`).join(", ") : `${table}.${validatedPlan.meta.pk} ASC`}`;
|
|
233
258
|
const limitSQL = state.limit ? ` LIMIT ${state.limit}` : "";
|
|
@@ -235,9 +260,65 @@ var QueryCompiler = class QueryCompiler {
|
|
|
235
260
|
const sql = `SELECT ${select} FROM ${table}${joins ? ` ${joins}` : ""}${whereSQL}${orderSQL}${limitSQL}${offsetSQL}`;
|
|
236
261
|
return {
|
|
237
262
|
sql,
|
|
238
|
-
params
|
|
263
|
+
params,
|
|
264
|
+
hydrations: selectRelationNames.map((relationName) => {
|
|
265
|
+
const relation = validatedPlan.relations[relationName];
|
|
266
|
+
return {
|
|
267
|
+
relationName,
|
|
268
|
+
alias: relation.alias,
|
|
269
|
+
columns: Object.fromEntries(Object.keys(relation.targetColumns).map((column) => [column, this.buildHydrationColumnAlias(relation.alias, column)]))
|
|
270
|
+
};
|
|
271
|
+
}),
|
|
272
|
+
prefetches: prefetchRelationNames.map((relationName) => {
|
|
273
|
+
const relation = validatedPlan.relations[relationName];
|
|
274
|
+
const needsAlias = !!state.select?.length && !state.select.map(String).includes(relation.sourceKey);
|
|
275
|
+
return {
|
|
276
|
+
relationName,
|
|
277
|
+
sourceKey: relation.sourceKey,
|
|
278
|
+
sourceKeyAlias: needsAlias ? this.buildPrefetchSourceAlias(relation.sourceKey) : undefined,
|
|
279
|
+
table: relation.table,
|
|
280
|
+
targetKey: relation.targetKey,
|
|
281
|
+
targetColumns: relation.targetColumns
|
|
282
|
+
};
|
|
283
|
+
})
|
|
239
284
|
};
|
|
240
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Compile the follow-up query used by `prefetchRelated(...)`.
|
|
288
|
+
*
|
|
289
|
+
* The base query cannot bind source values until after it has returned rows,
|
|
290
|
+
* but SQL rendering and validation still belong to the compiler.
|
|
291
|
+
*/
|
|
292
|
+
compilePrefetch(prefetch, sourceValues) {
|
|
293
|
+
const validatedPlan = sqlSafetyAdapter.validate({
|
|
294
|
+
kind: "select",
|
|
295
|
+
meta: this.meta,
|
|
296
|
+
relationNames: [prefetch.relationName]
|
|
297
|
+
});
|
|
298
|
+
const relation = validatedPlan.relations[prefetch.relationName];
|
|
299
|
+
const compiledTargetColumns = Object.keys(prefetch.targetColumns).sort();
|
|
300
|
+
const validatedTargetColumns = Object.keys(relation.targetColumns).sort();
|
|
301
|
+
const compiledMatchesValidated = prefetch.sourceKey === relation.sourceKey && prefetch.table === relation.table && prefetch.targetKey === relation.targetKey && compiledTargetColumns.length === validatedTargetColumns.length && compiledTargetColumns.every((column, index) => column === validatedTargetColumns[index] && prefetch.targetColumns[column] === relation.targetColumns[column]);
|
|
302
|
+
if (!compiledMatchesValidated) throw new Error(`Compiled prefetch metadata for relation '${prefetch.relationName}' failed validation.`);
|
|
303
|
+
const columns = Object.keys(relation.targetColumns);
|
|
304
|
+
const placeholders = this.dialect === InternalDialect.POSTGRES ? sourceValues.map((_, index) => `$${index + 1}`).join(", ") : sourceValues.map(() => "?").join(", ");
|
|
305
|
+
return {
|
|
306
|
+
sql: `SELECT ${columns.join(", ")} FROM ${relation.table} WHERE ${relation.targetKey} IN (${placeholders}) ORDER BY ${relation.targetKey} ASC`,
|
|
307
|
+
params: sourceValues,
|
|
308
|
+
targetKey: relation.targetKey,
|
|
309
|
+
targetColumns: relation.targetColumns
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
buildHydrationColumnAlias(alias, column) {
|
|
313
|
+
return this.assertInternalAliasDoesNotCollide(`__tango_hydrate_${alias}_${column}`);
|
|
314
|
+
}
|
|
315
|
+
buildPrefetchSourceAlias(sourceKey) {
|
|
316
|
+
return this.assertInternalAliasDoesNotCollide(`__tango_prefetch_${sourceKey}`);
|
|
317
|
+
}
|
|
318
|
+
assertInternalAliasDoesNotCollide(alias) {
|
|
319
|
+
if (alias in this.meta.columns) throw new Error(`Internal query alias '${alias}' collides with a field on table '${this.meta.table}'.`);
|
|
320
|
+
return alias;
|
|
321
|
+
}
|
|
241
322
|
compileQNode(node, paramIndex, filterKeys) {
|
|
242
323
|
switch (node.kind) {
|
|
243
324
|
case InternalQNodeType.ATOM: return this.compileAtom(node.where || {}, paramIndex, filterKeys);
|
|
@@ -416,9 +497,17 @@ var QueryCompiler = class QueryCompiler {
|
|
|
416
497
|
var compiler_exports = {};
|
|
417
498
|
__export(compiler_exports, { QueryCompiler: () => QueryCompiler });
|
|
418
499
|
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/query/domain/RelationTyping.ts
|
|
502
|
+
const InternalRelationHydrationCardinality = {
|
|
503
|
+
SINGLE: "single",
|
|
504
|
+
MANY: "many"
|
|
505
|
+
};
|
|
506
|
+
|
|
419
507
|
//#endregion
|
|
420
508
|
//#region src/query/domain/index.ts
|
|
421
509
|
var domain_exports = {};
|
|
510
|
+
__export(domain_exports, { InternalRelationHydrationCardinality: () => InternalRelationHydrationCardinality });
|
|
422
511
|
|
|
423
512
|
//#endregion
|
|
424
513
|
//#region src/query/domain/internal/InternalDirection.ts
|
|
@@ -559,38 +648,46 @@ var QuerySet = class QuerySet {
|
|
|
559
648
|
offset: n
|
|
560
649
|
});
|
|
561
650
|
}
|
|
562
|
-
select(
|
|
651
|
+
select(fields) {
|
|
563
652
|
return new QuerySet(this.executor, {
|
|
564
653
|
...this.state,
|
|
565
|
-
select: [...
|
|
654
|
+
select: [...fields]
|
|
566
655
|
});
|
|
567
656
|
}
|
|
568
657
|
/**
|
|
569
|
-
*
|
|
658
|
+
* Hydrate single-valued relations through SQL joins.
|
|
659
|
+
*
|
|
660
|
+
* Forward `belongsTo` relations can be inferred from the source model's
|
|
661
|
+
* field-authored relation metadata. Reverse `hasOne` relations can be
|
|
662
|
+
* selected with a target model generic when the target model points back to
|
|
663
|
+
* the source model.
|
|
570
664
|
*/
|
|
571
665
|
selectRelated(...rels) {
|
|
572
666
|
return new QuerySet(this.executor, {
|
|
573
667
|
...this.state,
|
|
574
|
-
selectRelated: rels
|
|
668
|
+
selectRelated: [...rels]
|
|
575
669
|
});
|
|
576
670
|
}
|
|
577
671
|
/**
|
|
578
|
-
*
|
|
672
|
+
* Hydrate collection relations with a follow-up query.
|
|
579
673
|
*
|
|
580
|
-
*
|
|
674
|
+
* Reverse `hasMany` relations can be prefetched with a target model generic
|
|
675
|
+
* when the target model points back to the source model.
|
|
581
676
|
*/
|
|
582
677
|
prefetchRelated(...rels) {
|
|
583
678
|
return new QuerySet(this.executor, {
|
|
584
679
|
...this.state,
|
|
585
|
-
prefetchRelated: rels
|
|
680
|
+
prefetchRelated: [...rels]
|
|
586
681
|
});
|
|
587
682
|
}
|
|
588
683
|
async fetch(shape) {
|
|
684
|
+
this.validateHydrationState();
|
|
589
685
|
const compiler = new QueryCompiler(this.executor.meta, this.executor.dialect);
|
|
590
686
|
const compiled = compiler.compile(this.state);
|
|
591
687
|
const rows = await this.executor.run(compiled);
|
|
592
688
|
const normalizedRows = this.normalizeRowsForSchemaParsing(rows, shape);
|
|
593
|
-
const
|
|
689
|
+
const hydratedRows = await this.hydrateRows(normalizedRows, compiled);
|
|
690
|
+
const projectedRows = hydratedRows;
|
|
594
691
|
const results = !shape ? projectedRows : typeof shape === "function" ? projectedRows.map(shape) : projectedRows.map((r) => shape.parse(r));
|
|
595
692
|
return {
|
|
596
693
|
results,
|
|
@@ -606,6 +703,7 @@ var QuerySet = class QuerySet {
|
|
|
606
703
|
* Execute a `COUNT(*)` query for the current filtered state.
|
|
607
704
|
*/
|
|
608
705
|
async count() {
|
|
706
|
+
this.validateHydrationState();
|
|
609
707
|
const compiler = new QueryCompiler(this.executor.meta, this.executor.dialect);
|
|
610
708
|
const compiled = compiler.compile(this.state);
|
|
611
709
|
const countQuery = `SELECT COUNT(*) as count FROM (${compiled.sql}) AS tango_count_subquery`;
|
|
@@ -625,6 +723,101 @@ var QuerySet = class QuerySet {
|
|
|
625
723
|
if (booleanColumns.length === 0) return rows;
|
|
626
724
|
return rows.map((row) => this.normalizeBooleanColumns(row, booleanColumns));
|
|
627
725
|
}
|
|
726
|
+
validateHydrationState() {
|
|
727
|
+
const seen = new Set();
|
|
728
|
+
for (const relationName of [...this.state.selectRelated ?? [], ...this.state.prefetchRelated ?? []]) {
|
|
729
|
+
if (seen.has(relationName)) throw new Error(`Relation '${relationName}' was requested more than once.`);
|
|
730
|
+
seen.add(relationName);
|
|
731
|
+
const relation = this.executor.meta.relations?.[relationName];
|
|
732
|
+
if (!relation) throw new Error(`Unknown relation '${relationName}' for table '${this.executor.meta.table}'.`);
|
|
733
|
+
if (relation.kind === InternalRelationKind.MANY_TO_MANY) throw new Error(`Relation '${relationName}' is many-to-many and cannot be hydrated yet.`);
|
|
734
|
+
if (relationName in this.executor.meta.columns && !(relation.kind === InternalRelationKind.BELONGS_TO && relationName === relation.sourceKey)) throw new Error(`Relation '${relationName}' on table '${this.executor.meta.table}' collides with an existing field.`);
|
|
735
|
+
}
|
|
736
|
+
for (const relationName of this.state.selectRelated ?? []) {
|
|
737
|
+
const relation = this.executor.meta.relations[relationName];
|
|
738
|
+
if (relation.kind !== InternalRelationKind.BELONGS_TO && relation.kind !== InternalRelationKind.HAS_ONE) throw new Error(`Relation '${relationName}' cannot be loaded with selectRelated(...).`);
|
|
739
|
+
}
|
|
740
|
+
for (const relationName of this.state.prefetchRelated ?? []) {
|
|
741
|
+
const relation = this.executor.meta.relations[relationName];
|
|
742
|
+
if (relation.kind !== InternalRelationKind.HAS_MANY) throw new Error(`Relation '${relationName}' cannot be loaded with prefetchRelated(...).`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
async hydrateRows(rows, compiled) {
|
|
746
|
+
const selectedRows = this.hydrateSelectedRows(rows, compiled);
|
|
747
|
+
return this.hydratePrefetchedRows(selectedRows, compiled);
|
|
748
|
+
}
|
|
749
|
+
hydrateSelectedRows(rows, compiled) {
|
|
750
|
+
const hydrations = compiled.hydrations;
|
|
751
|
+
if (!hydrations?.length) return rows;
|
|
752
|
+
return rows.map((row) => {
|
|
753
|
+
const next = { ...row };
|
|
754
|
+
for (const hydration of hydrations) {
|
|
755
|
+
const target = {};
|
|
756
|
+
let hasTargetValue = false;
|
|
757
|
+
for (const [column, alias] of Object.entries(hydration.columns)) {
|
|
758
|
+
const value = next[alias];
|
|
759
|
+
delete next[alias];
|
|
760
|
+
target[column] = this.normalizeTargetValue(hydration.relationName, column, value);
|
|
761
|
+
if (value !== null && value !== undefined) hasTargetValue = true;
|
|
762
|
+
}
|
|
763
|
+
next[hydration.relationName] = hasTargetValue ? target : null;
|
|
764
|
+
}
|
|
765
|
+
return next;
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async hydratePrefetchedRows(rows, compiled) {
|
|
769
|
+
if (!compiled.prefetches?.length || rows.length === 0) return rows;
|
|
770
|
+
const prefetchGroups = await Promise.all(compiled.prefetches.map(async (prefetch) => {
|
|
771
|
+
const sourceValues = rows.map((row) => row[prefetch.sourceKeyAlias ?? prefetch.sourceKey]).filter((value) => typeof value === "string" || typeof value === "number");
|
|
772
|
+
const uniqueSourceValues = [...new Set(sourceValues)];
|
|
773
|
+
return {
|
|
774
|
+
prefetch,
|
|
775
|
+
grouped: await this.fetchPrefetchGroup(prefetch, uniqueSourceValues)
|
|
776
|
+
};
|
|
777
|
+
}));
|
|
778
|
+
const hiddenSourceAliases = new Set(compiled.prefetches.map((prefetch) => prefetch.sourceKeyAlias).filter((alias) => typeof alias === "string"));
|
|
779
|
+
return rows.map((row) => {
|
|
780
|
+
const next = { ...row };
|
|
781
|
+
for (const { prefetch, grouped } of prefetchGroups) {
|
|
782
|
+
const sourceValue = row[prefetch.sourceKeyAlias ?? prefetch.sourceKey];
|
|
783
|
+
next[prefetch.relationName] = typeof sourceValue === "string" || typeof sourceValue === "number" ? grouped.get(sourceValue) ?? [] : [];
|
|
784
|
+
}
|
|
785
|
+
for (const alias of hiddenSourceAliases) delete next[alias];
|
|
786
|
+
return next;
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
async fetchPrefetchGroup(prefetch, sourceValues) {
|
|
790
|
+
const compiledPrefetch = new QueryCompiler(this.executor.meta, this.executor.dialect).compilePrefetch(prefetch, sourceValues);
|
|
791
|
+
const grouped = new Map();
|
|
792
|
+
if (sourceValues.length === 0) return grouped;
|
|
793
|
+
const result = await this.executor.client.query(compiledPrefetch.sql, compiledPrefetch.params);
|
|
794
|
+
for (const row of result.rows) {
|
|
795
|
+
const normalized = this.normalizeTargetRow(compiledPrefetch, row);
|
|
796
|
+
const key = normalized[compiledPrefetch.targetKey];
|
|
797
|
+
if (typeof key !== "string" && typeof key !== "number") continue;
|
|
798
|
+
const bucket = grouped.get(key) ?? [];
|
|
799
|
+
bucket.push(normalized);
|
|
800
|
+
grouped.set(key, bucket);
|
|
801
|
+
}
|
|
802
|
+
return grouped;
|
|
803
|
+
}
|
|
804
|
+
normalizeTargetRow(prefetch, row) {
|
|
805
|
+
if (this.executor.dialect !== InternalDialect.SQLITE) return row;
|
|
806
|
+
let normalized = null;
|
|
807
|
+
for (const [column, type] of Object.entries(prefetch.targetColumns)) {
|
|
808
|
+
if (!this.isBooleanColumnType(type)) continue;
|
|
809
|
+
const next = this.normalizeSqliteBoolean(row[column]);
|
|
810
|
+
if (next === row[column]) continue;
|
|
811
|
+
normalized ??= { ...row };
|
|
812
|
+
normalized[column] = next;
|
|
813
|
+
}
|
|
814
|
+
return normalized ?? row;
|
|
815
|
+
}
|
|
816
|
+
normalizeTargetValue(relationName, column, value) {
|
|
817
|
+
if (this.executor.dialect !== InternalDialect.SQLITE) return value;
|
|
818
|
+
const relation = this.executor.meta.relations[relationName];
|
|
819
|
+
return this.isBooleanColumnType(relation.targetColumns[column]) ? this.normalizeSqliteBoolean(value) : value;
|
|
820
|
+
}
|
|
628
821
|
isBooleanColumnType(value) {
|
|
629
822
|
return typeof value === "string" && ["bool", "boolean"].includes(value.trim().toLowerCase());
|
|
630
823
|
}
|
|
@@ -659,5 +852,5 @@ __export(query_exports, {
|
|
|
659
852
|
});
|
|
660
853
|
|
|
661
854
|
//#endregion
|
|
662
|
-
export { OrmSqlSafetyAdapter, QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports, query_exports };
|
|
663
|
-
//# sourceMappingURL=query-
|
|
855
|
+
export { InternalRelationKind, OrmSqlSafetyAdapter, QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports, query_exports };
|
|
856
|
+
//# sourceMappingURL=query-CWZ1cfjo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-CWZ1cfjo.js","names":["engine: SqlSafetyEngine","plan: SqlValidationPlan","meta: TableMeta","relationNames: readonly string[]","validatedMeta: ValidatedTableMeta","meta: ValidatedTableMeta","relationName: string","relations: TableMeta['relations']","rawKey: string","field: string","meta: TableMeta","dialect: Dialect","value: unknown","state: QuerySetState<T>","whereParts: string[]","params: unknown[]","prefetch: CompiledPrefetchHydration","sourceValues: readonly (string | number)[]","alias: string","column: string","sourceKey: string","node: QNode<T>","paramIndex: number","filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>","where: FilterInput<T>","nodes: QNode<T>[]","col: string","lookup: LookupType","filterKeys: Set<string>","value: unknown","node: FilterInput<T> | QNode<T>","input: FilterInput<T> | QNode<T>","executor: QueryExecutor<TModel>","state: QuerySetState<TModel>","value: unknown","q: FilterInput<TModel> | QNode<TModel>","wrapped: QNode<TModel>","n: number","fields: readonly (keyof TModel)[]","shape?:\n | QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n | QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>","results: Array<HydratedQueryResult<TBaseResult, THydrated> | Out>","rows: TModel[]","rows: Record<string, unknown>[]","compiled: CompiledQuery","target: Record<string, unknown>","prefetch: CompiledPrefetchHydration","sourceValues: readonly (string | number)[]","prefetch: TargetColumnMetadata","row: Record<string, unknown>","normalized: Record<string, unknown> | null","relationName: string","column: string","row: TModel","columns: readonly string[]","normalized: TModel | null"],"sources":["../src/query/domain/internal/InternalRelationKind.ts","../src/query/domain/internal/InternalDialect.ts","../src/query/domain/internal/InternalQNodeType.ts","../src/query/domain/internal/InternalLookupType.ts","../src/validation/OrmSqlSafetyAdapter.ts","../src/query/compiler/QueryCompiler.ts","../src/query/compiler/index.ts","../src/query/domain/RelationTyping.ts","../src/query/domain/index.ts","../src/query/domain/internal/InternalDirection.ts","../src/query/QBuilder.ts","../src/query/QuerySet.ts","../src/query/index.ts"],"sourcesContent":["export const InternalRelationKind = {\n HAS_MANY: 'hasMany',\n BELONGS_TO: 'belongsTo',\n HAS_ONE: 'hasOne',\n MANY_TO_MANY: 'manyToMany',\n} as const;\n","export const InternalDialect = {\n POSTGRES: 'postgres',\n SQLITE: 'sqlite',\n} as const;\n","export const InternalQNodeType = {\n ATOM: 'atom',\n AND: 'and',\n OR: 'or',\n NOT: 'not',\n} as const;\n","export const InternalLookupType = {\n EXACT: 'exact',\n LT: 'lt',\n LTE: 'lte',\n GT: 'gt',\n GTE: 'gte',\n IN: 'in',\n ISNULL: 'isnull',\n CONTAINS: 'contains',\n ICONTAINS: 'icontains',\n STARTSWITH: 'startswith',\n ISTARTSWITH: 'istartswith',\n ENDSWITH: 'endswith',\n IENDSWITH: 'iendswith',\n} as const;\n","import { SqlSafetyEngine, type SqlIdentifierRequest } from '@danceroutine/tango-core';\nimport type { LookupType } from '../query/domain/LookupType';\nimport type { TableMeta } from '../query/domain/TableMeta';\nimport { InternalLookupType } from '../query/domain/internal/InternalLookupType';\nimport type {\n SQLValidationEngine,\n ValidatedDeleteSqlPlan,\n ValidatedFilterDescriptor,\n ValidatedInsertSqlPlan,\n ValidatedRelationMeta,\n ValidatedTableMeta,\n ValidatedSelectSqlPlan,\n ValidatedSqlPlan,\n ValidatedUpdateSqlPlan,\n} from './SQLValidationEngine';\nimport type {\n DeleteSqlValidationPlan,\n InsertSqlValidationPlan,\n SelectSqlValidationPlan,\n SqlValidationPlan,\n UpdateSqlValidationPlan,\n} from './SqlValidationPlan';\n\nconst ALLOWED_LOOKUPS = Object.values(InternalLookupType) as readonly string[];\n\n/**\n * ORM-local adapter that translates query validation plans into the\n * shared Tango SQL safety engine.\n */\nexport class OrmSqlSafetyAdapter implements SQLValidationEngine {\n static readonly BRAND = 'tango.orm.orm_sql_safety_adapter' as const;\n readonly __tangoBrand: typeof OrmSqlSafetyAdapter.BRAND = OrmSqlSafetyAdapter.BRAND;\n\n constructor(private readonly engine: SqlSafetyEngine = new SqlSafetyEngine()) {}\n\n validate(plan: SelectSqlValidationPlan): ValidatedSelectSqlPlan;\n validate(plan: InsertSqlValidationPlan): ValidatedInsertSqlPlan;\n validate(plan: UpdateSqlValidationPlan): ValidatedUpdateSqlPlan;\n validate(plan: DeleteSqlValidationPlan): ValidatedDeleteSqlPlan;\n validate(plan: SqlValidationPlan): ValidatedSqlPlan {\n switch (plan.kind) {\n case 'select': {\n const meta = this.validateTableMeta(plan.meta, plan.relationNames ?? []);\n return {\n kind: 'select',\n meta,\n selectFields: Object.fromEntries(\n (plan.selectFields ?? []).map((field) => [\n field,\n `${meta.table}.${this.resolveColumn(meta, field)}`,\n ])\n ),\n filterKeys: Object.fromEntries(\n (plan.filterKeys ?? []).map((rawKey) => [rawKey, this.validateFilterKey(meta, rawKey)])\n ),\n orderFields: Object.fromEntries(\n (plan.orderFields ?? []).map((field) => [\n field,\n `${meta.table}.${this.resolveColumn(meta, field)}`,\n ])\n ),\n relations: Object.fromEntries(\n (plan.relationNames ?? []).map((relationName) => [\n relationName,\n this.resolveRelation(meta, relationName),\n ])\n ),\n };\n }\n case 'insert': {\n const meta = this.validateTableMeta(plan.meta);\n return {\n kind: 'insert',\n meta,\n writeKeys: plan.writeKeys.map((key) => this.resolveColumn(meta, key)),\n };\n }\n case 'update': {\n const meta = this.validateTableMeta(plan.meta);\n return {\n kind: 'update',\n meta,\n writeKeys: plan.writeKeys.map((key) => this.resolveColumn(meta, key)),\n };\n }\n case 'delete': {\n return {\n kind: 'delete',\n meta: this.validateTableMeta(plan.meta),\n };\n }\n }\n }\n\n private validateTableMeta(meta: TableMeta, relationNames: readonly string[] = []): ValidatedTableMeta {\n const columnNames = Object.keys(meta.columns);\n const validated = this.engine.validate({\n identifiers: [\n { key: 'table', role: 'table', value: meta.table },\n { key: 'pk', role: 'primaryKey', value: meta.pk, allowlist: columnNames },\n ...columnNames.map<SqlIdentifierRequest>((column) => ({\n key: `column:${column}`,\n role: 'column',\n value: column,\n })),\n ],\n });\n\n const validatedMeta: ValidatedTableMeta = {\n table: validated.identifiers.table!.value,\n pk: validated.identifiers.pk!.value,\n columns: Object.fromEntries(\n columnNames.map((column) => [validated.identifiers[`column:${column}`]!.value, meta.columns[column]!])\n ),\n };\n\n if (!(validatedMeta.pk in validatedMeta.columns)) {\n throw new Error(`Unknown column '${validatedMeta.pk}' for table '${validatedMeta.table}'.`);\n }\n\n if (relationNames.length > 0) {\n validatedMeta.relations = Object.fromEntries(\n relationNames.map((relationName) => [\n relationName,\n this.validateRelationMeta(validatedMeta, relationName, meta.relations),\n ])\n );\n }\n\n return validatedMeta;\n }\n\n private validateRelationMeta(\n meta: ValidatedTableMeta,\n relationName: string,\n relations: TableMeta['relations']\n ): ValidatedRelationMeta {\n const relation = relations?.[relationName];\n if (!relation) {\n throw new Error(`Unknown relation '${relationName}' for table '${meta.table}'.`);\n }\n if (!(relation.targetKey in relation.targetColumns)) {\n throw new Error(`Unknown relation target key '${relation.targetKey}' for relation '${relationName}'.`);\n }\n\n const validated = this.engine.validate({\n identifiers: [\n { key: 'table', role: 'relationTable', value: relation.table },\n { key: 'alias', role: 'alias', value: relation.alias },\n { key: 'targetKey', role: 'relationTargetPrimaryKey', value: relation.targetKey },\n ...Object.keys(relation.targetColumns).map<SqlIdentifierRequest>((column) => ({\n key: `targetColumn:${column}`,\n role: 'column',\n value: column,\n })),\n ],\n });\n\n return {\n ...relation,\n table: validated.identifiers.table!.value,\n alias: validated.identifiers.alias!.value,\n sourceKey: this.resolveColumn(meta, relation.sourceKey),\n targetKey: validated.identifiers.targetKey!.value,\n targetColumns: Object.fromEntries(\n Object.keys(relation.targetColumns).map((column) => [\n validated.identifiers[`targetColumn:${column}`]!.value,\n relation.targetColumns[column]!,\n ])\n ),\n };\n }\n\n private validateFilterKey(meta: ValidatedTableMeta, rawKey: string): ValidatedFilterDescriptor {\n const segments = rawKey.split('__');\n if (segments.length > 2) {\n throw new Error(`Invalid SQL lookup key: '${rawKey}'.`);\n }\n\n const field = segments[0]!;\n const lookup = (segments[1] ?? InternalLookupType.EXACT) as LookupType;\n const validated = this.engine.validate({\n lookupTokens: [{ key: rawKey, lookup, allowed: ALLOWED_LOOKUPS }],\n });\n\n return {\n rawKey,\n field,\n lookup: validated.lookupTokens[rawKey]!.lookup as LookupType,\n qualifiedColumn: `${meta.table}.${this.resolveColumn(meta, field)}`,\n };\n }\n\n private resolveColumn(meta: ValidatedTableMeta, field: string): string {\n if (!(field in meta.columns)) {\n throw new Error(`Unknown column '${field}' for table '${meta.table}'.`);\n }\n\n return field;\n }\n\n private resolveRelation(meta: ValidatedTableMeta, relationName: string): ValidatedRelationMeta {\n const relation = meta.relations?.[relationName];\n if (!relation) {\n throw new Error(`Unknown relation '${relationName}' for table '${meta.table}'.`);\n }\n\n return relation;\n }\n}\n","import type { LookupType } from '../domain/LookupType';\nimport type { QuerySetState } from '../domain/QuerySetState';\nimport type { TableMeta } from '../domain/TableMeta';\nimport type { QNode } from '../domain/QNode';\nimport type { CompiledPrefetchHydration, CompiledPrefetchQuery, CompiledQuery } from '../domain/CompiledQuery';\nimport type { WhereClause } from '../domain/WhereClause';\nimport type { FilterInput } from '../domain/FilterInput';\nimport type { Dialect } from '../domain/Dialect';\nimport { InternalDialect } from '../domain/internal/InternalDialect';\nimport { InternalQNodeType } from '../domain/internal/InternalQNodeType';\nimport { InternalLookupType } from '../domain/internal/InternalLookupType';\nimport { InternalRelationKind } from '../domain/internal/InternalRelationKind';\nimport { OrmSqlSafetyAdapter } from '../../validation';\n\n// The adapter is stateless, so a shared module instance keeps compiler construction cheap.\nconst sqlSafetyAdapter = new OrmSqlSafetyAdapter();\n\n/**\n * Compiles immutable `QuerySet` state into parameterized SQL.\n *\n * The compiler is intentionally stateless with respect to execution and only\n * produces SQL + params artifacts that can be executed by a `DBClient`.\n */\nexport class QueryCompiler {\n static readonly BRAND = 'tango.orm.query_compiler' as const;\n readonly __tangoBrand: typeof QueryCompiler.BRAND = QueryCompiler.BRAND;\n\n /**\n * Build a compiler for the given repository metadata and SQL dialect.\n */\n constructor(\n private meta: TableMeta,\n private dialect: Dialect = InternalDialect.POSTGRES\n ) {}\n\n /**\n * Narrow an unknown value to `QueryCompiler`.\n */\n static isQueryCompiler(value: unknown): value is QueryCompiler {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === QueryCompiler.BRAND\n );\n }\n\n /**\n * Compile a query state tree into a SQL statement and bound parameters.\n */\n compile<T>(state: QuerySetState<T>): CompiledQuery {\n const selectRelationNames = state.selectRelated ?? [];\n const prefetchRelationNames = state.prefetchRelated ?? [];\n const relationNames = [...new Set([...selectRelationNames, ...prefetchRelationNames])];\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'select',\n meta: this.meta,\n selectFields: state.select?.map(String),\n filterKeys: this.collectStateFilterKeys(state),\n orderFields: state.order?.map((order) => String(order.by)),\n relationNames,\n });\n const table = validatedPlan.meta.table;\n const whereParts: string[] = [];\n const params: unknown[] = [];\n\n if (state.q) {\n const result = this.compileQNode(state.q, params.length + 1, validatedPlan.filterKeys);\n if (result.sql) {\n whereParts.push(result.sql);\n params.push(...result.params);\n }\n }\n\n state.excludes?.forEach((exclude) => {\n const result = this.compileQNode(\n { kind: InternalQNodeType.NOT, node: exclude },\n params.length + 1,\n validatedPlan.filterKeys\n );\n if (result.sql) {\n whereParts.push(result.sql);\n params.push(...result.params);\n }\n });\n\n const baseSelect = state.select?.length\n ? state.select.map((field) => validatedPlan.selectFields[String(field)]!).join(', ')\n : `${table}.*`;\n const relationSelects = selectRelationNames.flatMap((relationName) => {\n const relation = validatedPlan.relations[relationName]!;\n return Object.keys(relation.targetColumns).map(\n (column) => `${relation.alias}.${column} AS ${this.buildHydrationColumnAlias(relation.alias, column)}`\n );\n });\n const prefetchSourceSelects =\n state.select?.length && prefetchRelationNames.length\n ? prefetchRelationNames\n .map((relationName) => validatedPlan.relations[relationName]!)\n .filter((relation) => !state.select!.map(String).includes(relation.sourceKey))\n .map(\n (relation) =>\n `${table}.${relation.sourceKey} AS ${this.buildPrefetchSourceAlias(relation.sourceKey)}`\n )\n : [];\n const select = [baseSelect, ...relationSelects, ...prefetchSourceSelects].join(', ');\n\n const joins = selectRelationNames\n .map((rel) => {\n const relation = validatedPlan.relations[rel]!;\n if (\n relation.kind !== InternalRelationKind.BELONGS_TO &&\n relation.kind !== InternalRelationKind.HAS_ONE\n ) {\n throw new Error(`Relation '${rel}' cannot be loaded with selectRelated(...).`);\n }\n return `LEFT JOIN ${relation.table} ${relation.alias} ON ${relation.alias}.${relation.targetKey} = ${table}.${relation.sourceKey}`;\n })\n .filter(Boolean)\n .join(' ');\n\n for (const rel of prefetchRelationNames) {\n const relation = validatedPlan.relations[rel];\n if (relation?.kind !== InternalRelationKind.HAS_MANY) {\n throw new Error(`Relation '${rel}' cannot be loaded with prefetchRelated(...).`);\n }\n }\n\n const whereSQL = whereParts.length ? ` WHERE ${whereParts.join(' AND ')}` : '';\n const orderSQL = ` ORDER BY ${\n state.order?.length\n ? state.order\n .map((order) => `${validatedPlan.orderFields[String(order.by)]!} ${order.dir.toUpperCase()}`)\n .join(', ')\n : `${table}.${validatedPlan.meta.pk} ASC`\n }`;\n const limitSQL = state.limit ? ` LIMIT ${state.limit}` : '';\n const offsetSQL = state.offset ? ` OFFSET ${state.offset}` : '';\n const sql = `SELECT ${select} FROM ${table}${joins ? ` ${joins}` : ''}${whereSQL}${orderSQL}${limitSQL}${offsetSQL}`;\n\n return {\n sql,\n params,\n hydrations: selectRelationNames.map((relationName) => {\n const relation = validatedPlan.relations[relationName]!;\n return {\n relationName,\n alias: relation.alias,\n columns: Object.fromEntries(\n Object.keys(relation.targetColumns).map((column) => [\n column,\n this.buildHydrationColumnAlias(relation.alias, column),\n ])\n ),\n };\n }),\n prefetches: prefetchRelationNames.map((relationName) => {\n const relation = validatedPlan.relations[relationName]!;\n const needsAlias = !!state.select?.length && !state.select.map(String).includes(relation.sourceKey);\n return {\n relationName,\n sourceKey: relation.sourceKey,\n sourceKeyAlias: needsAlias ? this.buildPrefetchSourceAlias(relation.sourceKey) : undefined,\n table: relation.table,\n targetKey: relation.targetKey,\n targetColumns: relation.targetColumns,\n };\n }),\n };\n }\n\n /**\n * Compile the follow-up query used by `prefetchRelated(...)`.\n *\n * The base query cannot bind source values until after it has returned rows,\n * but SQL rendering and validation still belong to the compiler.\n */\n compilePrefetch(\n prefetch: CompiledPrefetchHydration,\n sourceValues: readonly (string | number)[]\n ): CompiledPrefetchQuery {\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'select',\n meta: this.meta,\n relationNames: [prefetch.relationName],\n });\n const relation = validatedPlan.relations[prefetch.relationName]!;\n\n const compiledTargetColumns = Object.keys(prefetch.targetColumns).sort();\n const validatedTargetColumns = Object.keys(relation.targetColumns).sort();\n const compiledMatchesValidated =\n prefetch.sourceKey === relation.sourceKey &&\n prefetch.table === relation.table &&\n prefetch.targetKey === relation.targetKey &&\n compiledTargetColumns.length === validatedTargetColumns.length &&\n compiledTargetColumns.every(\n (column, index) =>\n column === validatedTargetColumns[index] &&\n prefetch.targetColumns[column] === relation.targetColumns[column]\n );\n if (!compiledMatchesValidated) {\n throw new Error(`Compiled prefetch metadata for relation '${prefetch.relationName}' failed validation.`);\n }\n\n const columns = Object.keys(relation.targetColumns);\n const placeholders =\n this.dialect === InternalDialect.POSTGRES\n ? sourceValues.map((_, index) => `$${index + 1}`).join(', ')\n : sourceValues.map(() => '?').join(', ');\n\n return {\n sql: `SELECT ${columns.join(', ')} FROM ${relation.table} WHERE ${relation.targetKey} IN (${placeholders}) ORDER BY ${relation.targetKey} ASC`,\n params: sourceValues,\n targetKey: relation.targetKey,\n targetColumns: relation.targetColumns,\n };\n }\n\n private buildHydrationColumnAlias(alias: string, column: string): string {\n return this.assertInternalAliasDoesNotCollide(`__tango_hydrate_${alias}_${column}`);\n }\n\n private buildPrefetchSourceAlias(sourceKey: string): string {\n return this.assertInternalAliasDoesNotCollide(`__tango_prefetch_${sourceKey}`);\n }\n\n private assertInternalAliasDoesNotCollide(alias: string): string {\n if (alias in this.meta.columns) {\n throw new Error(`Internal query alias '${alias}' collides with a field on table '${this.meta.table}'.`);\n }\n return alias;\n }\n\n private compileQNode<T>(\n node: QNode<T>,\n paramIndex: number,\n filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>\n ): WhereClause {\n switch (node.kind) {\n case InternalQNodeType.ATOM:\n return this.compileAtom(node.where || {}, paramIndex, filterKeys);\n case InternalQNodeType.AND:\n return this.compileAnd(node.nodes || [], paramIndex, filterKeys);\n case InternalQNodeType.OR:\n return this.compileOr(node.nodes || [], paramIndex, filterKeys);\n case InternalQNodeType.NOT:\n return this.compileNot(node.node!, paramIndex, filterKeys);\n default:\n return { sql: '', params: [] };\n }\n }\n\n private compileAtom<T>(\n where: FilterInput<T>,\n paramIndex: number,\n filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>\n ): WhereClause {\n const entries = Object.entries(where).filter(([, value]) => value !== undefined);\n\n const { parts, params } = entries.reduce<{ parts: string[]; params: unknown[] }>(\n (accumulator, [key, value]) => {\n const descriptor = filterKeys[String(key)]!;\n const idx = paramIndex + accumulator.params.length;\n const clause = this.lookupToSQL(descriptor.qualifiedColumn, descriptor.lookup, value, idx);\n accumulator.parts.push(clause.sql);\n accumulator.params.push(...clause.params);\n return accumulator;\n },\n { parts: [], params: [] }\n );\n\n return {\n sql: parts.length ? `(${parts.join(' AND ')})` : '',\n params,\n };\n }\n\n private compileAnd<T>(\n nodes: QNode<T>[],\n paramIndex: number,\n filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>\n ): WhereClause {\n const { parts, params } = nodes.reduce<{ parts: string[]; params: unknown[] }>(\n (accumulator, node) => {\n const result = this.compileQNode(node, paramIndex + accumulator.params.length, filterKeys);\n if (result.sql) {\n accumulator.parts.push(result.sql);\n accumulator.params.push(...result.params);\n }\n return accumulator;\n },\n { parts: [], params: [] }\n );\n\n return {\n sql: parts.length ? `(${parts.join(' AND ')})` : '',\n params,\n };\n }\n\n private compileOr<T>(\n nodes: QNode<T>[],\n paramIndex: number,\n filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>\n ): WhereClause {\n const { parts, params } = nodes.reduce<{ parts: string[]; params: unknown[] }>(\n (accumulator, node) => {\n const result = this.compileQNode(node, paramIndex + accumulator.params.length, filterKeys);\n if (result.sql) {\n accumulator.parts.push(result.sql);\n accumulator.params.push(...result.params);\n }\n return accumulator;\n },\n { parts: [], params: [] }\n );\n\n return {\n sql: parts.length ? `(${parts.join(' OR ')})` : '',\n params,\n };\n }\n\n private compileNot<T>(\n node: QNode<T>,\n paramIndex: number,\n filterKeys: Record<string, { lookup: LookupType; qualifiedColumn: string }>\n ): WhereClause {\n const result = this.compileQNode(node, paramIndex, filterKeys);\n if (!result.sql) {\n return { sql: '', params: [] };\n }\n\n return {\n sql: `(NOT ${result.sql})`,\n params: result.params,\n };\n }\n\n private lookupToSQL(col: string, lookup: LookupType, value: unknown, paramIndex: number): WhereClause {\n const placeholder = this.dialect === InternalDialect.POSTGRES ? `$${paramIndex}` : '?';\n const normalized = this.normalizeParam(value);\n\n switch (lookup) {\n case InternalLookupType.EXACT:\n if (value === null) {\n return { sql: `${col} IS NULL`, params: [] };\n }\n return { sql: `${col} = ${placeholder}`, params: [normalized] };\n case InternalLookupType.LT:\n return { sql: `${col} < ${placeholder}`, params: [normalized] };\n case InternalLookupType.LTE:\n return { sql: `${col} <= ${placeholder}`, params: [normalized] };\n case InternalLookupType.GT:\n return { sql: `${col} > ${placeholder}`, params: [normalized] };\n case InternalLookupType.GTE:\n return { sql: `${col} >= ${placeholder}`, params: [normalized] };\n case InternalLookupType.IN: {\n const entries = (Array.isArray(value) ? value : [value]).map((entry) => this.normalizeParam(entry));\n if (entries.length === 0) {\n return { sql: '1=0', params: [] };\n }\n const placeholders =\n this.dialect === InternalDialect.POSTGRES\n ? entries.map((_, index) => `$${paramIndex + index}`).join(', ')\n : entries.map(() => '?').join(', ');\n return { sql: `${col} IN (${placeholders})`, params: entries };\n }\n case InternalLookupType.ISNULL:\n return { sql: value ? `${col} IS NULL` : `${col} IS NOT NULL`, params: [] };\n case InternalLookupType.CONTAINS:\n return { sql: `${col} LIKE ${placeholder}`, params: [`%${value}%`] };\n case InternalLookupType.ICONTAINS: {\n const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;\n return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`%${String(value).toLowerCase()}%`] };\n }\n case InternalLookupType.STARTSWITH:\n return { sql: `${col} LIKE ${placeholder}`, params: [`${value}%`] };\n case InternalLookupType.ISTARTSWITH: {\n const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;\n return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`${String(value).toLowerCase()}%`] };\n }\n case InternalLookupType.ENDSWITH:\n return { sql: `${col} LIKE ${placeholder}`, params: [`%${value}`] };\n case InternalLookupType.IENDSWITH: {\n const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;\n return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`%${String(value).toLowerCase()}`] };\n }\n default:\n throw new Error(`Unknown lookup: ${lookup}`);\n }\n }\n\n private normalizeParam(value: unknown): unknown {\n if (this.dialect === InternalDialect.SQLITE && typeof value === 'boolean') {\n return value ? 1 : 0;\n }\n return value;\n }\n\n private collectStateFilterKeys<T>(state: QuerySetState<T>): string[] {\n const filterKeys = new Set<string>();\n if (state.q) {\n this.collectNodeFilterKeys(state.q, filterKeys);\n }\n\n state.excludes?.forEach((exclude) => this.collectNodeFilterKeys(exclude, filterKeys));\n return [...filterKeys];\n }\n\n private collectNodeFilterKeys<T>(node: QNode<T>, filterKeys: Set<string>): void {\n Object.keys(node.where ?? {}).forEach((key) => filterKeys.add(key));\n node.nodes?.forEach((child) => this.collectNodeFilterKeys(child, filterKeys));\n if (node.node) {\n this.collectNodeFilterKeys(node.node, filterKeys);\n }\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { QueryCompiler } from './QueryCompiler';\n","import type { z } from 'zod';\nimport type { Model, PersistedModelOutput } from '@danceroutine/tango-schema/domain';\nimport type {\n DecoratedFieldKind,\n InternalDecoratedFieldKind,\n RelationDecoratedSchema,\n} from '@danceroutine/tango-schema/model';\n\nexport const InternalRelationHydrationCardinality = {\n SINGLE: 'single',\n MANY: 'many',\n} as const;\n\nexport type RelationHydrationCardinality =\n (typeof InternalRelationHydrationCardinality)[keyof typeof InternalRelationHydrationCardinality];\nexport type SingleRelationHydrationCardinality = typeof InternalRelationHydrationCardinality.SINGLE;\nexport type ManyRelationHydrationCardinality = typeof InternalRelationHydrationCardinality.MANY;\n\nexport type HydratedQueryResult<TBase extends Record<string, unknown>, THydrated extends Record<string, unknown>> =\n // No relation hydration requested: keep the base projection exactly as-is.\n [keyof THydrated] extends [never] ? TBase : Omit<TBase, keyof THydrated> & THydrated;\n\n// A model's own schema is the only source TypeScript can inspect without codegen or an ambient registry.\n// These helpers progressively peel that schema apart into field definitions and persisted row shapes.\n// \"AnyModel\" is a structural upper bound for model values when the exact schema/key is not important.\ntype AnyModel = Model<z.ZodObject<z.ZodRawShape>, string>;\n// If the caller gave us a Tango Model type, infer the Zod schema type stored inside it.\ntype ModelSchema<TModel> =\n TModel extends Model<infer TSchema extends z.ZodObject<z.ZodRawShape>, string> ? TSchema : never;\n// If we have a Zod object schema, infer its raw object shape so we can inspect individual fields.\ntype ModelShape<TModel> = ModelSchema<TModel> extends z.ZodObject<infer TShape> ? TShape : never;\n// Convert the inferred model schema back into the persisted row shape applications receive from the ORM.\ntype ModelRow<TModel> =\n TModel extends Model<infer TSchema extends z.ZodObject<z.ZodRawShape>, string>\n ? PersistedModelOutput<TSchema>\n : never;\n\n// Relation typing only works when model keys remain literal. Once a model key widens to plain string,\n// TypeScript can no longer prove that one relation target matches another model.\n// This conditional rejects widened strings while accepting literal keys such as \"blog/User\".\ntype IsLiteralString<TValue> = TValue extends string ? (string extends TValue ? false : true) : false;\n// A model has strict relation typing only when its model key is still a literal type.\ntype HasStrictModelKey<TModel> =\n TModel extends Model<z.ZodObject<z.ZodRawShape>, infer TKey> ? IsLiteralString<TKey> : false;\n\nexport type HasStrictRelationTyping<TSourceModel> = HasStrictModelKey<TSourceModel>;\n\n// Reverse relation typing compares the literal model key carried by the target field against the source model key.\ntype ModelKeysMatch<TCandidate, TExpected> =\n TCandidate extends Model<z.ZodObject<z.ZodRawShape>, infer TCandidateKey>\n ? // The candidate relation target is a Tango model. Now check whether the expected source is also a model.\n TExpected extends Model<z.ZodObject<z.ZodRawShape>, infer TExpectedKey>\n ? // Both sides must keep literal keys, otherwise a plain string could accidentally match anything.\n IsLiteralString<TCandidateKey> extends true\n ? IsLiteralString<TExpectedKey> extends true\n ? // Tuple wrapping avoids distributive conditional behavior and compares the keys as whole values.\n [TCandidateKey] extends [TExpectedKey]\n ? true\n : false\n : false\n : false\n : false\n : false;\n\n// Keep this in sync with RelationDescriptorNormalizer.deriveNamingHint(...), which currently recognizes\n// camelCase \"Id\" and snake_case \"_id\" suffixes but does not treat lowercase \"id\" as a relation suffix.\ntype FieldNamingHint<TKey extends string> = TKey extends `${infer TBase}Id`\n ? // Convert authorId -> author for relation names when the decorator did not configure name explicitly.\n TBase\n : TKey extends `${infer TBase}_id`\n ? // Convert author_id -> author for snake_case field names.\n TBase\n : // Otherwise the field key is already the best available relation-name hint.\n TKey;\n\n// Prefer an explicitly configured forward relation name. Fall back to the field-name heuristic.\ntype RelationName<TKey extends string, TName> = TName extends string ? TName : FieldNamingHint<TKey>;\n// Reverse relations cannot be inferred without an explicit relatedName, so missing names become never.\ntype RelatedName<TName> = TName extends string ? TName : never;\n\n// Relation decorators brand their Zod field with type-only metadata. The next group extracts that metadata:\n// relation target, configured forward name, configured reverse name, and relation kind.\ntype RelationTarget<TField> =\n TField extends RelationDecoratedSchema<\n z.ZodTypeAny,\n DecoratedFieldKind,\n infer TTarget,\n string | undefined,\n string | undefined\n >\n ? // infer TTarget captures the typed model target carried by direct refs, callbacks, or t.modelRef<TModel>(...).\n TTarget\n : never;\n\ntype RelationConfiguredName<TField> =\n TField extends RelationDecoratedSchema<z.ZodTypeAny, DecoratedFieldKind, AnyModel, infer TName, string | undefined>\n ? // infer TName captures config.name when the decorator call used a literal string.\n TName\n : undefined;\n\ntype RelationConfiguredRelatedName<TField> =\n TField extends RelationDecoratedSchema<\n z.ZodTypeAny,\n DecoratedFieldKind,\n AnyModel,\n string | undefined,\n infer TRelatedName\n >\n ? // infer TRelatedName captures config.relatedName when the decorator call used a literal string.\n TRelatedName\n : undefined;\n\ntype RelationKindOf<TField> =\n TField extends RelationDecoratedSchema<z.ZodTypeAny, infer TKind, AnyModel, string | undefined, string | undefined>\n ? // infer TKind tells us whether the field was branded by foreignKey, oneToOne, or manyToMany.\n TKind\n : never;\n\n// Forward relations live on the source model's own schema. A foreign key and a one-to-one field are both\n// single-valued from the source model's point of view, so both hydrate through selectRelated(...).\nexport type ForwardSingleRelations<TSourceModel> =\n HasStrictModelKey<TSourceModel> extends true\n ? // Strict source model: inspect its own schema and emit only fields that are forward single relations.\n {\n [TKey in keyof ModelShape<TSourceModel> as TKey extends string\n ? // Non-relation fields have no decorator brand and therefore map to never.\n [RelationKindOf<ModelShape<TSourceModel>[TKey]>] extends [never]\n ? never\n : // foreignKey and oneToOne are both single-valued when loaded from the source model.\n RelationKindOf<ModelShape<TSourceModel>[TKey]> extends\n | typeof InternalDecoratedFieldKind.FOREIGN_KEY\n | typeof InternalDecoratedFieldKind.ONE_TO_ONE\n ? // The relation must carry a typed model target; plain string refs cannot hydrate a typed result.\n RelationTarget<ModelShape<TSourceModel>[TKey]> extends AnyModel\n ? // The mapped-type key is the public relation name accepted by selectRelated(...).\n RelationName<TKey, RelationConfiguredName<ModelShape<TSourceModel>[TKey]>>\n : never\n : never\n : never]: {\n kind: typeof InternalDecoratedFieldKind.FOREIGN_KEY;\n target: RelationTarget<ModelShape<TSourceModel>[TKey]>;\n };\n }\n : // Weak source model: allow runtime strings but do not add precise hydrated result properties.\n Record<string, { kind: typeof InternalDecoratedFieldKind.FOREIGN_KEY; target: AnyModel }>;\n\n// A reverse single relation is only visible when the caller supplies the target model generic. We inspect that\n// target model for a one-to-one field pointing back to the source model and use its relatedName.\nexport type ReverseSingleRelations<TSourceModel, TTargetModel> =\n HasStrictModelKey<TSourceModel> extends true\n ? // Reverse typing needs both the current source model and the away/target model to keep literal keys.\n HasStrictModelKey<TTargetModel> extends true\n ? {\n [TKey in keyof ModelShape<TTargetModel> as [RelationKindOf<ModelShape<TTargetModel>[TKey]>] extends [\n never,\n ]\n ? // Ignore ordinary fields on the away model.\n never\n : // Only oneToOne creates a single-valued reverse relation.\n RelationKindOf<\n ModelShape<TTargetModel>[TKey]\n > extends typeof InternalDecoratedFieldKind.ONE_TO_ONE\n ? // The away model's oneToOne target must point back at the current source model.\n ModelKeysMatch<RelationTarget<ModelShape<TTargetModel>[TKey]>, TSourceModel> extends true\n ? // The reverse call-site key is the away field's configured relatedName.\n RelatedName<RelationConfiguredRelatedName<ModelShape<TTargetModel>[TKey]>>\n : never\n : never]: {\n kind: typeof InternalDecoratedFieldKind.ONE_TO_ONE;\n target: TTargetModel;\n };\n }\n : // A widened target model cannot prove reverse relation names.\n // oxlint-disable-next-line typescript/ban-types, typescript/no-empty-object-type\n {}\n : // Weak source model: allow runtime strings but do not add precise hydrated result properties.\n Record<string, { kind: typeof InternalDecoratedFieldKind.ONE_TO_ONE; target: AnyModel }>;\n\n// A reverse collection relation follows the same target-model inspection path, but only foreign keys produce hasMany.\nexport type ReverseCollectionRelations<TSourceModel, TTargetModel> =\n HasStrictModelKey<TSourceModel> extends true\n ? // Reverse collection typing also needs both model keys to remain literal.\n HasStrictModelKey<TTargetModel> extends true\n ? {\n [TKey in keyof ModelShape<TTargetModel> as [RelationKindOf<ModelShape<TTargetModel>[TKey]>] extends [\n never,\n ]\n ? // Ignore ordinary fields on the away model.\n never\n : // A foreign key on the away model creates a hasMany collection from the source model.\n RelationKindOf<\n ModelShape<TTargetModel>[TKey]\n > extends typeof InternalDecoratedFieldKind.FOREIGN_KEY\n ? // The away model's foreign key must point back at the current source model.\n ModelKeysMatch<RelationTarget<ModelShape<TTargetModel>[TKey]>, TSourceModel> extends true\n ? // The reverse call-site key is the away field's configured relatedName.\n RelatedName<RelationConfiguredRelatedName<ModelShape<TTargetModel>[TKey]>>\n : never\n : never]: {\n kind: typeof InternalDecoratedFieldKind.FOREIGN_KEY;\n target: TTargetModel;\n };\n }\n : // A widened target model cannot prove reverse relation names.\n // oxlint-disable-next-line typescript/ban-types, typescript/no-empty-object-type\n {}\n : // Weak source model: allow runtime strings but do not add precise hydrated result properties.\n Record<string, { kind: typeof InternalDecoratedFieldKind.FOREIGN_KEY; target: AnyModel }>;\n\nexport type SelectRelatedRelations<TSourceModel, TTargetModel> = [TTargetModel] extends [undefined]\n ? // No target generic: selectRelated(...) can only use forward relations from the source schema.\n ForwardSingleRelations<TSourceModel>\n : // Target generic supplied: include reverse hasOne relations discovered on that target model.\n ForwardSingleRelations<TSourceModel> & ReverseSingleRelations<TSourceModel, TTargetModel>;\n\n// prefetchRelated(...) only loads collection relations in this pass, so it only accepts reverse hasMany metadata.\nexport type PrefetchRelatedRelations<TSourceModel, TTargetModel> = ReverseCollectionRelations<\n TSourceModel,\n TTargetModel\n>;\n\n// QuerySet method parameters need a string union of accepted relation names.\nexport type RelationKeys<TRelations> = Extract<keyof TRelations, string>;\n\n// Convert a selected relation-key union into the result object that fetch(...) exposes.\nexport type HydratedRelationMap<TRelations, TKeys extends string, TCardinality extends RelationHydrationCardinality> = {\n [TKey in TKeys]: TKey extends keyof TRelations\n ? // The relation map value carries the target model; infer that target so we can derive its row type.\n TRelations[TKey] extends { target: infer TTarget }\n ? // Single-valued relation hydration returns the target model or null when the join finds no row.\n TCardinality extends typeof InternalRelationHydrationCardinality.SINGLE\n ? ModelRow<TTarget> | null\n : // Collection relation hydration returns zero or more target model rows.\n ModelRow<TTarget>[]\n : never\n : never;\n};\n\nexport type MaybeHydratedRelationMap<\n TSourceModel,\n TRelations,\n TKeys extends string,\n TCardinality extends RelationHydrationCardinality,\n> =\n HasStrictModelKey<TSourceModel> extends true\n ? // Strict source model: materialize the requested hydrated relation properties into the fetched result type.\n HydratedRelationMap<TRelations, TKeys, TCardinality>\n : // Weak source model: preserve runtime support, but avoid pretending we know the hydrated result shape.\n Record<never, never>;\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { CompiledQuery } from './CompiledQuery';\nexport type { Dialect } from './Dialect';\nexport type { Direction } from './Direction';\nexport type { FilterInput } from './FilterInput';\nexport type { FilterKey } from './FilterKey';\nexport type { FilterValue } from './FilterValue';\nexport type { LookupType } from './LookupType';\nexport type { OrderSpec } from './OrderSpec';\nexport type { OrderToken } from './OrderToken';\nexport type { QNode } from './QNode';\nexport type { QueryResult } from './QueryResult';\nexport type { QuerySetState } from './QuerySetState';\nexport type { RelationMeta } from './RelationMeta';\nexport type {\n ForwardSingleRelations,\n HydratedQueryResult,\n HydratedRelationMap,\n ManyRelationHydrationCardinality,\n MaybeHydratedRelationMap,\n PrefetchRelatedRelations,\n RelationKeys,\n RelationHydrationCardinality,\n ReverseCollectionRelations,\n ReverseSingleRelations,\n SelectRelatedRelations,\n SingleRelationHydrationCardinality,\n} from './RelationTyping';\nexport { InternalRelationHydrationCardinality } from './RelationTyping';\nexport type { TableMeta } from './TableMeta';\nexport type { WhereClause } from './WhereClause';\n","export const InternalDirection = {\n ASC: 'asc',\n DESC: 'desc',\n} as const;\n","import type { QNode } from './domain/QNode';\nimport type { FilterInput } from './domain/FilterInput';\nimport { InternalQNodeType } from './domain/internal/InternalQNodeType';\n\n/**\n * Static builder for composing boolean query expressions.\n *\n * This mirrors Django's `Q(...)` composition patterns and is intended\n * for ergonomic construction of nested `AND`/`OR`/`NOT` trees.\n */\nexport class QBuilder {\n static readonly BRAND = 'tango.orm.q_builder' as const;\n readonly __tangoBrand: typeof QBuilder.BRAND = QBuilder.BRAND;\n\n /**\n * Narrow an unknown value to `QBuilder`.\n */\n static isQBuilder(value: unknown): value is QBuilder {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === QBuilder.BRAND\n );\n }\n\n /**\n * Combine multiple filter fragments using logical `AND`.\n */\n static and<T>(...nodes: Array<FilterInput<T> | QNode<T>>): QNode<T> {\n return {\n kind: InternalQNodeType.AND,\n nodes: nodes.map(QBuilder.wrapNode),\n };\n }\n\n /**\n * Combine multiple filter fragments using logical `OR`.\n */\n static or<T>(...nodes: Array<FilterInput<T> | QNode<T>>): QNode<T> {\n return {\n kind: InternalQNodeType.OR,\n nodes: nodes.map(QBuilder.wrapNode),\n };\n }\n\n /**\n * Negate a filter fragment using logical `NOT`.\n */\n static not<T>(node: FilterInput<T> | QNode<T>): QNode<T> {\n return {\n kind: InternalQNodeType.NOT,\n node: QBuilder.wrapNode(node),\n };\n }\n\n private static wrapNode<T>(input: FilterInput<T> | QNode<T>): QNode<T> {\n if ((input as QNode<T>).kind) {\n return input as QNode<T>;\n }\n return {\n kind: InternalQNodeType.ATOM,\n where: input as FilterInput<T>,\n };\n }\n}\n","import type { DBClient } from '../connection/clients/DBClient';\nimport type { Dialect } from './domain/Dialect';\nimport type { QuerySetState } from './domain/QuerySetState';\nimport type { TableMeta } from './domain/TableMeta';\nimport type { QNode } from './domain/QNode';\nimport type { QueryResult } from './domain/QueryResult';\nimport type { OrderToken } from './domain/OrderToken';\nimport type { FilterInput } from './domain/FilterInput';\nimport type { CompiledQuery } from './domain/CompiledQuery';\nimport type { CompiledPrefetchHydration } from './domain/CompiledQuery';\nimport type {\n HydratedQueryResult,\n ManyRelationHydrationCardinality,\n MaybeHydratedRelationMap,\n PrefetchRelatedRelations,\n RelationKeys,\n SelectRelatedRelations,\n SingleRelationHydrationCardinality,\n} from './domain/RelationTyping';\nimport { InternalQNodeType } from './domain/internal/InternalQNodeType';\nimport { InternalDirection } from './domain/internal/InternalDirection';\nimport { InternalDialect } from './domain/internal/InternalDialect';\nimport { InternalRelationKind } from './domain/internal/InternalRelationKind';\nimport { QBuilder as Q } from './QBuilder';\nimport { QueryCompiler } from './compiler';\n\n/**\n * Query execution seam consumed by `QuerySet`.\n *\n * Application code usually reaches this through `Model.objects` or testing\n * fixtures rather than implementing it directly.\n *\n * @template TModel - The model row type returned by the database client\n */\nexport interface QueryExecutor<TModel> {\n meta: TableMeta;\n client: DBClient;\n dialect: Dialect;\n run(compiled: CompiledQuery): Promise<TModel[]>;\n}\n\ntype QueryShapeFunction<TInput, TOutput> = (row: TInput) => TOutput;\n\ntype QueryShapeParser<TInput, TOutput> = {\n parse: (row: TInput) => TOutput;\n};\n\ntype QueryShape<TInput> = QueryShapeFunction<TInput, unknown> | QueryShapeParser<TInput, unknown>;\n\ntype QueryShapeOutput<TInput, TShape> =\n TShape extends QueryShapeFunction<TInput, infer TOutput>\n ? TOutput\n : TShape extends QueryShapeParser<TInput, infer TOutput>\n ? TOutput\n : never;\n\ntype TargetColumnMetadata = {\n targetColumns: Record<string, string>;\n};\n\ntype ProjectedResult<\n TModel extends Record<string, unknown>,\n TKeys extends readonly (keyof TModel)[],\n> = number extends TKeys['length'] ? TModel : [TKeys[number]] extends [never] ? TModel : Pick<TModel, TKeys[number]>;\n\n/**\n * Django-inspired query builder for constructing and executing database queries.\n * Provides a fluent API for filtering, ordering, pagination, projection, and\n * one-level relation hydration.\n *\n * @template TModel - The full model row type used for query composition\n * @template TBaseResult - The selected base-row shape returned by execution methods\n * @template TSourceModel - The source Tango model used for typed relation metadata\n * @template THydrated - Relation properties accumulated by eager-loading calls\n *\n * @example\n * ```typescript\n * const users = await TodoModel.objects\n * .query()\n * .filter({ active: true })\n * .filter(Q.or({ role: 'admin' }, { role: 'moderator' }))\n * .orderBy('-createdAt')\n * .limit(10)\n * .fetch();\n * ```\n */\nexport class QuerySet<\n TModel extends Record<string, unknown>,\n TBaseResult extends Record<string, unknown> = TModel,\n TSourceModel = unknown,\n THydrated extends Record<string, unknown> = Record<never, never>,\n> {\n static readonly BRAND = 'tango.orm.query_set' as const;\n readonly __tangoBrand: typeof QuerySet.BRAND = QuerySet.BRAND;\n\n constructor(\n private executor: QueryExecutor<TModel>,\n private state: QuerySetState<TModel> = {}\n ) {}\n\n /**\n * Narrow an unknown value to `QuerySet`.\n */\n static isQuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel>(\n value: unknown\n ): value is QuerySet<TModel, TResult> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === QuerySet.BRAND\n );\n }\n\n /**\n * Add a filter expression to the query.\n *\n * Multiple `filter()` calls are composed with `AND`.\n */\n filter(q: FilterInput<TModel> | QNode<TModel>): QuerySet<TModel, TBaseResult, TSourceModel, THydrated> {\n const wrapped: QNode<TModel> = (q as QNode<TModel>).kind\n ? (q as QNode<TModel>)\n : { kind: InternalQNodeType.ATOM, where: q as FilterInput<TModel> };\n const merged = this.state.q ? Q.and(this.state.q, wrapped) : wrapped;\n return new QuerySet(this.executor, { ...this.state, q: merged });\n }\n\n /**\n * Add an exclusion expression to the query.\n *\n * Exclusions are translated to `NOT (...)` predicates.\n */\n exclude(q: FilterInput<TModel> | QNode<TModel>): QuerySet<TModel, TBaseResult, TSourceModel, THydrated> {\n const wrapped: QNode<TModel> = (q as QNode<TModel>).kind\n ? (q as QNode<TModel>)\n : { kind: InternalQNodeType.ATOM, where: q as FilterInput<TModel> };\n const excludes = [...(this.state.excludes ?? []), wrapped];\n return new QuerySet(this.executor, { ...this.state, excludes });\n }\n\n /**\n * Apply ordering tokens such as `'name'` or `'-createdAt'`.\n */\n orderBy(...tokens: OrderToken<TModel>[]): QuerySet<TModel, TBaseResult, TSourceModel, THydrated> {\n const order = tokens.map((t) => {\n const str = String(t);\n if (str.startsWith('-')) {\n return { by: str.slice(1) as keyof TModel, dir: InternalDirection.DESC };\n }\n return { by: t as keyof TModel, dir: InternalDirection.ASC };\n });\n return new QuerySet(this.executor, { ...this.state, order });\n }\n\n /**\n * Limit the maximum number of rows returned.\n */\n limit(n: number): QuerySet<TModel, TBaseResult, TSourceModel, THydrated> {\n return new QuerySet(this.executor, { ...this.state, limit: n });\n }\n\n /**\n * Skip the first `n` rows.\n */\n offset(n: number): QuerySet<TModel, TBaseResult, TSourceModel, THydrated> {\n return new QuerySet(this.executor, { ...this.state, offset: n });\n }\n\n /**\n * Restrict selected fields and narrow the fetched row type when the\n * selected keys are known precisely at the call site.\n *\n * Empty selections reset back to the full model row, and repeated\n * `select(...)` calls replace the previous projection rather than\n * intersecting it.\n */\n select<const TKeys extends readonly (keyof TModel)[]>(\n fields: TKeys\n ): QuerySet<TModel, ProjectedResult<TModel, TKeys>, TSourceModel, THydrated>;\n select(\n fields: readonly (keyof TModel)[]\n ): QuerySet<TModel, ProjectedResult<TModel, readonly (keyof TModel)[]>, TSourceModel, THydrated>;\n select(\n fields: readonly (keyof TModel)[]\n ): QuerySet<TModel, ProjectedResult<TModel, readonly (keyof TModel)[]>, TSourceModel, THydrated> {\n return new QuerySet(this.executor, { ...this.state, select: [...fields] as (keyof TModel)[] });\n }\n\n /**\n * Hydrate single-valued relations through SQL joins.\n *\n * Forward `belongsTo` relations can be inferred from the source model's\n * field-authored relation metadata. Reverse `hasOne` relations can be\n * selected with a target model generic when the target model points back to\n * the source model.\n */\n selectRelated<\n TTargetModel = undefined,\n const TRelationName extends RelationKeys<\n SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>\n > = RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>,\n >(\n ...rels: readonly TRelationName[]\n ): QuerySet<\n TModel,\n TBaseResult,\n TSourceModel,\n THydrated &\n MaybeHydratedRelationMap<\n TSourceModel,\n SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>,\n TRelationName,\n SingleRelationHydrationCardinality\n >\n > {\n return new QuerySet(this.executor, { ...this.state, selectRelated: [...rels] });\n }\n\n /**\n * Hydrate collection relations with a follow-up query.\n *\n * Reverse `hasMany` relations can be prefetched with a target model generic\n * when the target model points back to the source model.\n */\n prefetchRelated<\n TTargetModel = undefined,\n const TRelationName extends RelationKeys<\n PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>\n > = RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>,\n >(\n ...rels: readonly TRelationName[]\n ): QuerySet<\n TModel,\n TBaseResult,\n TSourceModel,\n THydrated &\n MaybeHydratedRelationMap<\n TSourceModel,\n PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>,\n TRelationName,\n ManyRelationHydrationCardinality\n >\n > {\n return new QuerySet(this.executor, { ...this.state, prefetchRelated: [...rels] });\n }\n\n /**\n * Execute the query and optionally shape each row.\n *\n * When the queryset has been narrowed by `select(...)`, rows passed to the\n * shaping callback or parser use that narrowed fetched-row type.\n */\n async fetch(): Promise<QueryResult<HydratedQueryResult<TBaseResult, THydrated>>>;\n async fetch<Out>(\n shape: QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): Promise<QueryResult<Out>>;\n async fetch<Out>(\n shape: QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): Promise<QueryResult<Out>>;\n async fetch<TShape extends QueryShape<HydratedQueryResult<TBaseResult, THydrated>> | undefined>(\n shape: TShape\n ): Promise<\n QueryResult<\n | HydratedQueryResult<TBaseResult, THydrated>\n | QueryShapeOutput<HydratedQueryResult<TBaseResult, THydrated>, NonNullable<TShape>>\n >\n >;\n async fetch<Out>(\n shape?:\n | QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n | QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): Promise<QueryResult<HydratedQueryResult<TBaseResult, THydrated> | Out>> {\n this.validateHydrationState();\n const compiler = new QueryCompiler(this.executor.meta, this.executor.dialect);\n const compiled = compiler.compile(this.state);\n const rows = await this.executor.run(compiled);\n const normalizedRows = this.normalizeRowsForSchemaParsing(rows, shape);\n const hydratedRows = await this.hydrateRows(normalizedRows as unknown as Record<string, unknown>[], compiled);\n const projectedRows = hydratedRows as Array<HydratedQueryResult<TBaseResult, THydrated>>;\n\n const results: Array<HydratedQueryResult<TBaseResult, THydrated> | Out> = !shape\n ? projectedRows\n : typeof shape === 'function'\n ? projectedRows.map(shape)\n : projectedRows.map((r) => shape.parse(r));\n\n return {\n results,\n nextCursor: null,\n };\n }\n\n /**\n * Execute the query and return the first row, or `null`.\n *\n * As with `fetch(...)`, parser and function overloads receive the current\n * fetched-row type after any `select(...)` projection narrowing.\n */\n async fetchOne(): Promise<HydratedQueryResult<TBaseResult, THydrated> | null>;\n async fetchOne<Out>(\n shape: QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): Promise<Out | null>;\n async fetchOne<Out>(shape: QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>): Promise<Out | null>;\n async fetchOne<TShape extends QueryShape<HydratedQueryResult<TBaseResult, THydrated>> | undefined>(\n shape: TShape\n ): Promise<\n | HydratedQueryResult<TBaseResult, THydrated>\n | QueryShapeOutput<HydratedQueryResult<TBaseResult, THydrated>, NonNullable<TShape>>\n | null\n >;\n async fetchOne<Out>(\n shape?:\n | QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n | QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): Promise<HydratedQueryResult<TBaseResult, THydrated> | Out | null> {\n const limited = this.limit(1);\n const result = !shape\n ? await limited.fetch()\n : typeof shape === 'function'\n ? await limited.fetch(shape)\n : await limited.fetch(shape);\n return result.results[0] ?? null;\n }\n\n /**\n * Execute a `COUNT(*)` query for the current filtered state.\n */\n async count(): Promise<number> {\n this.validateHydrationState();\n const compiler = new QueryCompiler(this.executor.meta, this.executor.dialect);\n const compiled = compiler.compile(this.state);\n const countQuery = `SELECT COUNT(*) as count FROM (${compiled.sql}) AS tango_count_subquery`;\n const rows = await this.executor.client.query<{ count: number }>(countQuery, compiled.params);\n return Number(rows.rows[0]?.count ?? 0);\n }\n\n /**\n * Return whether at least one row matches the current query state.\n */\n async exists(): Promise<boolean> {\n const count = await this.count();\n return count > 0;\n }\n\n private normalizeRowsForSchemaParsing<Out>(\n rows: TModel[],\n shape?:\n | QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>\n | QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>\n ): TModel[] {\n if (!shape || typeof shape === 'function' || this.executor.dialect !== InternalDialect.SQLITE) {\n return rows;\n }\n\n const booleanColumns = Object.entries(this.executor.meta.columns)\n .filter(([, value]) => this.isBooleanColumnType(value))\n .map(([column]) => column);\n\n if (booleanColumns.length === 0) {\n return rows;\n }\n\n return rows.map((row) => this.normalizeBooleanColumns(row, booleanColumns));\n }\n\n private validateHydrationState(): void {\n const seen = new Set<string>();\n for (const relationName of [...(this.state.selectRelated ?? []), ...(this.state.prefetchRelated ?? [])]) {\n if (seen.has(relationName)) {\n throw new Error(`Relation '${relationName}' was requested more than once.`);\n }\n seen.add(relationName);\n\n const relation = this.executor.meta.relations?.[relationName];\n if (!relation) {\n throw new Error(`Unknown relation '${relationName}' for table '${this.executor.meta.table}'.`);\n }\n if (relation.kind === InternalRelationKind.MANY_TO_MANY) {\n throw new Error(`Relation '${relationName}' is many-to-many and cannot be hydrated yet.`);\n }\n if (\n relationName in this.executor.meta.columns &&\n !(relation.kind === InternalRelationKind.BELONGS_TO && relationName === relation.sourceKey)\n ) {\n throw new Error(\n `Relation '${relationName}' on table '${this.executor.meta.table}' collides with an existing field.`\n );\n }\n }\n\n for (const relationName of this.state.selectRelated ?? []) {\n const relation = this.executor.meta.relations![relationName]!;\n if (relation.kind !== InternalRelationKind.BELONGS_TO && relation.kind !== InternalRelationKind.HAS_ONE) {\n throw new Error(`Relation '${relationName}' cannot be loaded with selectRelated(...).`);\n }\n }\n\n for (const relationName of this.state.prefetchRelated ?? []) {\n const relation = this.executor.meta.relations![relationName]!;\n if (relation.kind !== InternalRelationKind.HAS_MANY) {\n throw new Error(`Relation '${relationName}' cannot be loaded with prefetchRelated(...).`);\n }\n }\n }\n\n private async hydrateRows(\n rows: Record<string, unknown>[],\n compiled: CompiledQuery\n ): Promise<Record<string, unknown>[]> {\n const selectedRows = this.hydrateSelectedRows(rows, compiled);\n return this.hydratePrefetchedRows(selectedRows, compiled);\n }\n\n private hydrateSelectedRows(rows: Record<string, unknown>[], compiled: CompiledQuery): Record<string, unknown>[] {\n const hydrations = compiled.hydrations;\n if (!hydrations?.length) {\n return rows;\n }\n\n return rows.map((row) => {\n const next = { ...row };\n for (const hydration of hydrations) {\n const target: Record<string, unknown> = {};\n let hasTargetValue = false;\n\n for (const [column, alias] of Object.entries(hydration.columns)) {\n const value = next[alias];\n delete next[alias];\n target[column] = this.normalizeTargetValue(hydration.relationName, column, value);\n if (value !== null && value !== undefined) {\n hasTargetValue = true;\n }\n }\n\n next[hydration.relationName] = hasTargetValue ? target : null;\n }\n return next;\n });\n }\n\n private async hydratePrefetchedRows(\n rows: Record<string, unknown>[],\n compiled: CompiledQuery\n ): Promise<Record<string, unknown>[]> {\n if (!compiled.prefetches?.length || rows.length === 0) {\n return rows;\n }\n\n const prefetchGroups = await Promise.all(\n compiled.prefetches.map(async (prefetch) => {\n const sourceValues = rows\n .map((row) => row[prefetch.sourceKeyAlias ?? prefetch.sourceKey])\n .filter(\n (value): value is string | number => typeof value === 'string' || typeof value === 'number'\n );\n const uniqueSourceValues = [...new Set(sourceValues)];\n // TODO: A future prefetch planner can batch compatible relation fetches into fewer database\n // round trips. For now, prefetch is bounded by requested relation count, and each relation fetch is\n // issued concurrently instead of once per base row.\n return {\n prefetch,\n grouped: await this.fetchPrefetchGroup(prefetch, uniqueSourceValues),\n };\n })\n );\n\n const hiddenSourceAliases = new Set(\n compiled.prefetches\n .map((prefetch) => prefetch.sourceKeyAlias)\n .filter((alias): alias is string => typeof alias === 'string')\n );\n\n return rows.map((row) => {\n const next = { ...row };\n\n for (const { prefetch, grouped } of prefetchGroups) {\n const sourceValue = row[prefetch.sourceKeyAlias ?? prefetch.sourceKey];\n next[prefetch.relationName] =\n typeof sourceValue === 'string' || typeof sourceValue === 'number'\n ? (grouped.get(sourceValue) ?? [])\n : [];\n }\n\n for (const alias of hiddenSourceAliases) {\n delete next[alias];\n }\n\n return next;\n });\n }\n\n private async fetchPrefetchGroup(\n prefetch: CompiledPrefetchHydration,\n sourceValues: readonly (string | number)[]\n ): Promise<Map<string | number, Record<string, unknown>[]>> {\n const compiledPrefetch = new QueryCompiler(this.executor.meta, this.executor.dialect).compilePrefetch(\n prefetch,\n sourceValues\n );\n const grouped = new Map<string | number, Record<string, unknown>[]>();\n if (sourceValues.length === 0) {\n return grouped;\n }\n\n const result = await this.executor.client.query<Record<string, unknown>>(\n compiledPrefetch.sql,\n compiledPrefetch.params\n );\n\n for (const row of result.rows) {\n const normalized = this.normalizeTargetRow(compiledPrefetch, row);\n const key = normalized[compiledPrefetch.targetKey];\n if (typeof key !== 'string' && typeof key !== 'number') {\n continue;\n }\n const bucket = grouped.get(key) ?? [];\n bucket.push(normalized);\n grouped.set(key, bucket);\n }\n\n return grouped;\n }\n\n private normalizeTargetRow(prefetch: TargetColumnMetadata, row: Record<string, unknown>): Record<string, unknown> {\n if (this.executor.dialect !== InternalDialect.SQLITE) {\n return row;\n }\n\n let normalized: Record<string, unknown> | null = null;\n for (const [column, type] of Object.entries(prefetch.targetColumns)) {\n if (!this.isBooleanColumnType(type)) {\n continue;\n }\n const next = this.normalizeSqliteBoolean(row[column]);\n if (next === row[column]) {\n continue;\n }\n normalized ??= { ...row };\n normalized[column] = next;\n }\n return normalized ?? row;\n }\n\n private normalizeTargetValue(relationName: string, column: string, value: unknown): unknown {\n if (this.executor.dialect !== InternalDialect.SQLITE) {\n return value;\n }\n const relation = this.executor.meta.relations![relationName]!;\n return this.isBooleanColumnType(relation.targetColumns[column]) ? this.normalizeSqliteBoolean(value) : value;\n }\n\n private isBooleanColumnType(value: unknown): boolean {\n return typeof value === 'string' && ['bool', 'boolean'].includes(value.trim().toLowerCase());\n }\n\n private normalizeSqliteBoolean(value: unknown): unknown {\n if (value === 0 || value === '0') {\n return false;\n }\n if (value === 1 || value === '1') {\n return true;\n }\n return value;\n }\n\n private normalizeBooleanColumns(row: TModel, columns: readonly string[]): TModel {\n let normalized: TModel | null = null;\n\n for (const column of columns) {\n const current = (row as Record<string, unknown>)[column];\n const next = this.normalizeSqliteBoolean(current);\n if (next === current) {\n continue;\n }\n if (!normalized) {\n normalized = { ...row };\n }\n (normalized as Record<string, unknown>)[column] = next;\n }\n\n return normalized ?? row;\n }\n}\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as compiler from './compiler/index';\nexport * as domain from './domain/index';\n\nexport type * from './domain/index';\nexport type { TableMeta } from './domain/index';\nexport { QuerySet } from './QuerySet';\nexport type { QueryExecutor } from './QuerySet';\nexport { QBuilder, QBuilder as Q } from './QBuilder';\nexport { QueryCompiler } from './compiler/index';\n"],"mappings":"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"}
|