@danceroutine/tango-orm 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PostgresAdapter } from "./PostgresAdapter-C9a1XJRx.js";
2
2
  import { SqliteAdapter } from "./SqliteAdapter-Dp6VRXmz.js";
3
3
  import { AdapterRegistry, connectDB, connection_exports, getDefaultAdapterRegistry } from "./connection-CVvycXus.js";
4
- import { QBuilder, QueryCompiler, QuerySet, query_exports } from "./query-wnl4h2o7.js";
4
+ import { QBuilder, QueryCompiler, QuerySet, query_exports } from "./query-Bc9kc1nI.js";
5
5
  import { ModelManager, TangoRuntime, getTangoRuntime, initializeTangoRuntime, resetTangoRuntime } from "./registerModelObjects-emX7Hja9.js";
6
6
  import { manager_exports } from "./manager-D6tU8xTO.js";
7
7
  import { runtime_exports } from "./runtime-7U5_XDad.js";
@@ -1,7 +1,7 @@
1
1
  import "../PostgresAdapter-C9a1XJRx.js";
2
2
  import "../SqliteAdapter-Dp6VRXmz.js";
3
3
  import "../connection-CVvycXus.js";
4
- import "../query-wnl4h2o7.js";
4
+ import "../query-Bc9kc1nI.js";
5
5
  import { ModelManager, registerModelObjects } from "../registerModelObjects-emX7Hja9.js";
6
6
  import "../manager-D6tU8xTO.js";
7
7
 
@@ -23,11 +23,19 @@ export interface QueryExecutor<T> {
23
23
  params: readonly unknown[];
24
24
  }): Promise<T[]>;
25
25
  }
26
+ type QueryShapeFunction<TInput, TOutput> = (row: TInput) => TOutput;
27
+ type QueryShapeParser<TInput, TOutput> = {
28
+ parse: (row: TInput) => TOutput;
29
+ };
30
+ type QueryShape<TInput> = QueryShapeFunction<TInput, unknown> | QueryShapeParser<TInput, unknown>;
31
+ type QueryShapeOutput<TInput, TShape> = TShape extends QueryShapeFunction<TInput, infer TOutput> ? TOutput : TShape extends QueryShapeParser<TInput, infer TOutput> ? TOutput : never;
32
+ type ProjectedResult<TModel extends Record<string, unknown>, TKeys extends readonly (keyof TModel)[]> = number extends TKeys['length'] ? TModel : [TKeys[number]] extends [never] ? TModel : Pick<TModel, TKeys[number]>;
26
33
  /**
27
34
  * Django-inspired query builder for constructing and executing database queries.
28
35
  * Provides a fluent API for filtering, ordering, pagination, and eager loading.
29
36
  *
30
- * @template T - The model type being queried
37
+ * @template TModel - The full model row type used for query composition
38
+ * @template TResult - The fetched row shape returned by execution methods
31
39
  *
32
40
  * @example
33
41
  * ```typescript
@@ -40,66 +48,80 @@ export interface QueryExecutor<T> {
40
48
  * .fetch();
41
49
  * ```
42
50
  */
43
- export declare class QuerySet<T extends Record<string, unknown>> {
51
+ export declare class QuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel> {
44
52
  private executor;
45
53
  private state;
46
54
  static readonly BRAND: "tango.orm.query_set";
47
55
  readonly __tangoBrand: typeof QuerySet.BRAND;
48
- constructor(executor: QueryExecutor<T>, state?: QuerySetState<T>);
56
+ constructor(executor: QueryExecutor<TModel>, state?: QuerySetState<TModel>);
49
57
  /**
50
58
  * Narrow an unknown value to `QuerySet`.
51
59
  */
52
- static isQuerySet<T extends Record<string, unknown>>(value: unknown): value is QuerySet<T>;
60
+ static isQuerySet<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel>(value: unknown): value is QuerySet<TModel, TResult>;
53
61
  /**
54
62
  * Add a filter expression to the query.
55
63
  *
56
64
  * Multiple `filter()` calls are composed with `AND`.
57
65
  */
58
- filter(q: FilterInput<T> | QNode<T>): QuerySet<T>;
66
+ filter(q: FilterInput<TModel> | QNode<TModel>): QuerySet<TModel, TResult>;
59
67
  /**
60
68
  * Add an exclusion expression to the query.
61
69
  *
62
70
  * Exclusions are translated to `NOT (...)` predicates.
63
71
  */
64
- exclude(q: FilterInput<T> | QNode<T>): QuerySet<T>;
72
+ exclude(q: FilterInput<TModel> | QNode<TModel>): QuerySet<TModel, TResult>;
65
73
  /**
66
74
  * Apply ordering tokens such as `'name'` or `'-createdAt'`.
67
75
  */
68
- orderBy(...tokens: OrderToken<T>[]): QuerySet<T>;
76
+ orderBy(...tokens: OrderToken<TModel>[]): QuerySet<TModel, TResult>;
69
77
  /**
70
78
  * Limit the maximum number of rows returned.
71
79
  */
72
- limit(n: number): QuerySet<T>;
80
+ limit(n: number): QuerySet<TModel, TResult>;
73
81
  /**
74
82
  * Skip the first `n` rows.
75
83
  */
76
- offset(n: number): QuerySet<T>;
84
+ offset(n: number): QuerySet<TModel, TResult>;
77
85
  /**
78
- * Restrict selected columns.
86
+ * Restrict selected columns and narrow the fetched row type when the
87
+ * selected keys are known precisely at the call site.
88
+ *
89
+ * Empty selections reset back to the full model row, and repeated
90
+ * `select(...)` calls replace the previous projection rather than
91
+ * intersecting it.
79
92
  */
80
- select(cols: (keyof T)[]): QuerySet<T>;
93
+ select<const TKeys extends readonly (keyof TModel)[]>(cols: TKeys): QuerySet<TModel, ProjectedResult<TModel, TKeys>>;
94
+ select(cols: readonly (keyof TModel)[]): QuerySet<TModel, TModel>;
81
95
  /**
82
96
  * Request SQL joins for related data when supported by relation metadata.
83
97
  */
84
- selectRelated(...rels: string[]): QuerySet<T>;
98
+ selectRelated(...rels: string[]): QuerySet<TModel, TResult>;
85
99
  /**
86
100
  * Register relation names for prefetch behavior.
87
101
  *
88
102
  * Prefetch orchestration is adapter-specific.
89
103
  */
90
- prefetchRelated(...rels: string[]): QuerySet<T>;
104
+ prefetchRelated(...rels: string[]): QuerySet<TModel, TResult>;
91
105
  /**
92
106
  * Execute the query and optionally shape each row.
107
+ *
108
+ * When the queryset has been narrowed by `select(...)`, rows passed to the
109
+ * shaping callback or parser use that narrowed fetched-row type.
93
110
  */
94
- fetch<Out = T>(shape?: ((r: T) => Out) | {
95
- parse: (r: T) => Out;
96
- }): Promise<QueryResult<Out>>;
111
+ fetch(): Promise<QueryResult<TResult>>;
112
+ fetch<Out>(shape: QueryShapeFunction<TResult, Out>): Promise<QueryResult<Out>>;
113
+ fetch<Out>(shape: QueryShapeParser<TResult, Out>): Promise<QueryResult<Out>>;
114
+ fetch<TShape extends QueryShape<TResult> | undefined>(shape: TShape): Promise<QueryResult<TResult | QueryShapeOutput<TResult, NonNullable<TShape>>>>;
97
115
  /**
98
116
  * Execute the query and return the first row, or `null`.
117
+ *
118
+ * As with `fetch(...)`, parser and function overloads receive the current
119
+ * fetched-row type after any `select(...)` projection narrowing.
99
120
  */
100
- fetchOne<Out = T>(shape?: ((r: T) => Out) | {
101
- parse: (r: T) => Out;
102
- }): Promise<Out | null>;
121
+ fetchOne(): Promise<TResult | null>;
122
+ fetchOne<Out>(shape: QueryShapeFunction<TResult, Out>): Promise<Out | null>;
123
+ fetchOne<Out>(shape: QueryShapeParser<TResult, Out>): Promise<Out | null>;
124
+ fetchOne<TShape extends QueryShape<TResult> | undefined>(shape: TShape): Promise<TResult | QueryShapeOutput<TResult, NonNullable<TShape>> | null>;
103
125
  /**
104
126
  * Execute a `COUNT(*)` query for the current filtered state.
105
127
  */
@@ -113,3 +135,4 @@ export declare class QuerySet<T extends Record<string, unknown>> {
113
135
  private normalizeSqliteBoolean;
114
136
  private normalizeBooleanColumns;
115
137
  }
138
+ export {};
@@ -1,3 +1,3 @@
1
- import { QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports } from "../query-wnl4h2o7.js";
1
+ import { QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports } from "../query-Bc9kc1nI.js";
2
2
 
3
3
  export { QBuilder as Q, QBuilder, QueryCompiler, QuerySet, compiler_exports as compiler, domain_exports as domain };
@@ -559,13 +559,10 @@ var QuerySet = class QuerySet {
559
559
  offset: n
560
560
  });
561
561
  }
562
- /**
563
- * Restrict selected columns.
564
- */
565
562
  select(cols) {
566
563
  return new QuerySet(this.executor, {
567
564
  ...this.state,
568
- select: cols
565
+ select: [...cols]
569
566
  });
570
567
  }
571
568
  /**
@@ -588,26 +585,21 @@ var QuerySet = class QuerySet {
588
585
  prefetchRelated: rels
589
586
  });
590
587
  }
591
- /**
592
- * Execute the query and optionally shape each row.
593
- */
594
588
  async fetch(shape) {
595
589
  const compiler = new QueryCompiler(this.executor.meta, this.executor.dialect);
596
590
  const compiled = compiler.compile(this.state);
597
591
  const rows = await this.executor.run(compiled);
598
592
  const normalizedRows = this.normalizeRowsForSchemaParsing(rows, shape);
599
- const results = !shape ? normalizedRows : typeof shape === "function" ? normalizedRows.map(shape) : normalizedRows.map((r) => shape.parse(r));
593
+ const projectedRows = normalizedRows;
594
+ const results = !shape ? projectedRows : typeof shape === "function" ? projectedRows.map(shape) : projectedRows.map((r) => shape.parse(r));
600
595
  return {
601
596
  results,
602
597
  nextCursor: null
603
598
  };
604
599
  }
605
- /**
606
- * Execute the query and return the first row, or `null`.
607
- */
608
600
  async fetchOne(shape) {
609
601
  const limited = this.limit(1);
610
- const result = await limited.fetch(shape);
602
+ const result = !shape ? await limited.fetch() : typeof shape === "function" ? await limited.fetch(shape) : await limited.fetch(shape);
611
603
  return result.results[0] ?? null;
612
604
  }
613
605
  /**
@@ -668,4 +660,4 @@ __export(query_exports, {
668
660
 
669
661
  //#endregion
670
662
  export { OrmSqlSafetyAdapter, QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports, query_exports };
671
- //# sourceMappingURL=query-wnl4h2o7.js.map
663
+ //# sourceMappingURL=query-Bc9kc1nI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-Bc9kc1nI.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[]","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","cols: readonly (keyof TModel)[]","shape?: QueryShapeFunction<TResult, Out> | QueryShapeParser<TResult, Out>","results: Array<TResult | Out>","rows: TModel[]","row: TModel","columns: readonly string[]","normalized: TModel | null"],"sources":["../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/index.ts","../src/query/domain/internal/InternalDirection.ts","../src/query/QBuilder.ts","../src/query/QuerySet.ts","../src/query/index.ts"],"sourcesContent":["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\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: 'targetPk', role: 'relationTargetPrimaryKey', value: relation.targetPk },\n ...(relation.foreignKey\n ? [{ key: 'foreignKey', role: 'relationForeignKey' as const, value: relation.foreignKey }]\n : []),\n ],\n });\n\n return {\n ...relation,\n table: validated.identifiers.table!.value,\n alias: validated.identifiers.alias!.value,\n targetPk: validated.identifiers.targetPk!.value,\n localKey: relation.localKey ? this.resolveColumn(meta, relation.localKey) : undefined,\n foreignKey: relation.foreignKey ? validated.identifiers.foreignKey!.value : undefined,\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 if (relation.kind === 'belongsTo' && !relation.localKey) {\n throw new Error(`Relation '${relationName}' for table '${meta.table}' requires a local key.`);\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 { 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 { 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 knownRelationNames = (state.selectRelated ?? []).filter(\n (relationName) => this.meta.relations?.[relationName] !== undefined\n );\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: knownRelationNames,\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 select = state.select?.length\n ? state.select.map((field) => validatedPlan.selectFields[String(field)]!).join(', ')\n : `${table}.*`;\n\n const joins = knownRelationNames\n .map((rel) => {\n const relation = validatedPlan.relations[rel];\n if (!relation || relation.kind !== 'belongsTo') {\n return '';\n }\n return `LEFT JOIN ${relation.table} ${relation.alias} ON ${relation.alias}.${relation.targetPk} = ${table}.${relation.localKey!}`;\n })\n .filter(Boolean)\n .join(' ');\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 { sql, params };\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","/**\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 { 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 { InternalQNodeType } from './domain/internal/InternalQNodeType';\nimport { InternalDirection } from './domain/internal/InternalDirection';\nimport { InternalDialect } from './domain/internal/InternalDialect';\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 T - The model type\n */\nexport interface QueryExecutor<T> {\n meta: TableMeta;\n client: DBClient;\n dialect: Dialect;\n run(compiled: { sql: string; params: readonly unknown[] }): Promise<T[]>;\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 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, and eager loading.\n *\n * @template TModel - The full model row type used for query composition\n * @template TResult - The fetched row shape returned by execution methods\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<TModel extends Record<string, unknown>, TResult extends Record<string, unknown> = TModel> {\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, TResult> {\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, TResult> {\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, TResult> {\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, TResult> {\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, TResult> {\n return new QuerySet(this.executor, { ...this.state, offset: n });\n }\n\n /**\n * Restrict selected columns 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 cols: TKeys\n ): QuerySet<TModel, ProjectedResult<TModel, TKeys>>;\n select(cols: readonly (keyof TModel)[]): QuerySet<TModel, TModel>;\n select(cols: readonly (keyof TModel)[]): QuerySet<TModel, TModel> {\n return new QuerySet(this.executor, { ...this.state, select: [...cols] as (keyof TModel)[] });\n }\n\n /**\n * Request SQL joins for related data when supported by relation metadata.\n */\n selectRelated(...rels: string[]): QuerySet<TModel, TResult> {\n return new QuerySet(this.executor, { ...this.state, selectRelated: rels });\n }\n\n /**\n * Register relation names for prefetch behavior.\n *\n * Prefetch orchestration is adapter-specific.\n */\n prefetchRelated(...rels: string[]): QuerySet<TModel, TResult> {\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<TResult>>;\n async fetch<Out>(shape: QueryShapeFunction<TResult, Out>): Promise<QueryResult<Out>>;\n async fetch<Out>(shape: QueryShapeParser<TResult, Out>): Promise<QueryResult<Out>>;\n async fetch<TShape extends QueryShape<TResult> | undefined>(\n shape: TShape\n ): Promise<QueryResult<TResult | QueryShapeOutput<TResult, NonNullable<TShape>>>>;\n async fetch<Out>(\n shape?: QueryShapeFunction<TResult, Out> | QueryShapeParser<TResult, Out>\n ): Promise<QueryResult<TResult | Out>> {\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 projectedRows = normalizedRows as unknown as TResult[];\n\n const results: Array<TResult | 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<TResult | null>;\n async fetchOne<Out>(shape: QueryShapeFunction<TResult, Out>): Promise<Out | null>;\n async fetchOne<Out>(shape: QueryShapeParser<TResult, Out>): Promise<Out | null>;\n async fetchOne<TShape extends QueryShape<TResult> | undefined>(\n shape: TShape\n ): Promise<TResult | QueryShapeOutput<TResult, NonNullable<TShape>> | null>;\n async fetchOne<Out>(\n shape?: QueryShapeFunction<TResult, Out> | QueryShapeParser<TResult, Out>\n ): Promise<TResult | 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 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?: QueryShapeFunction<TResult, Out> | QueryShapeParser<TResult, 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 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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"}
@@ -1,5 +1,5 @@
1
1
  import { connectDB } from "./connection-CVvycXus.js";
2
- import { OrmSqlSafetyAdapter, QuerySet } from "./query-wnl4h2o7.js";
2
+ import { OrmSqlSafetyAdapter, QuerySet } from "./query-Bc9kc1nI.js";
3
3
  import { NotFoundError } from "@danceroutine/tango-core";
4
4
  import { registerModelAugmentor } from "@danceroutine/tango-schema";
5
5
  import { loadConfig, loadConfigFromProjectRoot } from "@danceroutine/tango-config";
@@ -1,7 +1,7 @@
1
1
  import "../PostgresAdapter-C9a1XJRx.js";
2
2
  import "../SqliteAdapter-Dp6VRXmz.js";
3
3
  import "../connection-CVvycXus.js";
4
- import "../query-wnl4h2o7.js";
4
+ import "../query-Bc9kc1nI.js";
5
5
  import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, registerModelObjects, resetTangoRuntime } from "../registerModelObjects-emX7Hja9.js";
6
6
  import "../runtime-7U5_XDad.js";
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danceroutine/tango-orm",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Model-first querying, runtime-managed database access, and transactions for Tango",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,9 +49,9 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "zod": "^4.0.0",
52
- "@danceroutine/tango-config": "1.1.2",
53
- "@danceroutine/tango-core": "1.1.2",
54
- "@danceroutine/tango-schema": "1.1.2"
52
+ "@danceroutine/tango-core": "1.1.3",
53
+ "@danceroutine/tango-config": "1.1.3",
54
+ "@danceroutine/tango-schema": "1.1.3"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "pg": "^8.13.1",
@@ -74,8 +74,8 @@
74
74
  "tsdown": "^0.4.0",
75
75
  "typescript": "^5.6.3",
76
76
  "vitest": "^4.0.6",
77
- "@danceroutine/tango-testing": "1.1.2",
78
- "@danceroutine/tango-migrations": "1.1.2"
77
+ "@danceroutine/tango-migrations": "1.1.3",
78
+ "@danceroutine/tango-testing": "1.1.3"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "tsdown",
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-wnl4h2o7.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[]","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<T>","state: QuerySetState<T>","value: unknown","q: FilterInput<T> | QNode<T>","wrapped: QNode<T>","n: number","cols: (keyof T)[]","shape?: ((r: T) => Out) | { parse: (r: T) => Out }","results: Out[]","rows: T[]","row: T","columns: readonly string[]","normalized: T | null"],"sources":["../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/index.ts","../src/query/domain/internal/InternalDirection.ts","../src/query/QBuilder.ts","../src/query/QuerySet.ts","../src/query/index.ts"],"sourcesContent":["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\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: 'targetPk', role: 'relationTargetPrimaryKey', value: relation.targetPk },\n ...(relation.foreignKey\n ? [{ key: 'foreignKey', role: 'relationForeignKey' as const, value: relation.foreignKey }]\n : []),\n ],\n });\n\n return {\n ...relation,\n table: validated.identifiers.table!.value,\n alias: validated.identifiers.alias!.value,\n targetPk: validated.identifiers.targetPk!.value,\n localKey: relation.localKey ? this.resolveColumn(meta, relation.localKey) : undefined,\n foreignKey: relation.foreignKey ? validated.identifiers.foreignKey!.value : undefined,\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 if (relation.kind === 'belongsTo' && !relation.localKey) {\n throw new Error(`Relation '${relationName}' for table '${meta.table}' requires a local key.`);\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 { 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 { 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 knownRelationNames = (state.selectRelated ?? []).filter(\n (relationName) => this.meta.relations?.[relationName] !== undefined\n );\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: knownRelationNames,\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 select = state.select?.length\n ? state.select.map((field) => validatedPlan.selectFields[String(field)]!).join(', ')\n : `${table}.*`;\n\n const joins = knownRelationNames\n .map((rel) => {\n const relation = validatedPlan.relations[rel];\n if (!relation || relation.kind !== 'belongsTo') {\n return '';\n }\n return `LEFT JOIN ${relation.table} ${relation.alias} ON ${relation.alias}.${relation.targetPk} = ${table}.${relation.localKey!}`;\n })\n .filter(Boolean)\n .join(' ');\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 { sql, params };\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","/**\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 { 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 { InternalQNodeType } from './domain/internal/InternalQNodeType';\nimport { InternalDirection } from './domain/internal/InternalDirection';\nimport { InternalDialect } from './domain/internal/InternalDialect';\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 T - The model type\n */\nexport interface QueryExecutor<T> {\n meta: TableMeta;\n client: DBClient;\n dialect: Dialect;\n run(compiled: { sql: string; params: readonly unknown[] }): Promise<T[]>;\n}\n\n/**\n * Django-inspired query builder for constructing and executing database queries.\n * Provides a fluent API for filtering, ordering, pagination, and eager loading.\n *\n * @template T - The model type being queried\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<T extends Record<string, unknown>> {\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<T>,\n private state: QuerySetState<T> = {}\n ) {}\n\n /**\n * Narrow an unknown value to `QuerySet`.\n */\n static isQuerySet<T extends Record<string, unknown>>(value: unknown): value is QuerySet<T> {\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<T> | QNode<T>): QuerySet<T> {\n const wrapped: QNode<T> = (q as QNode<T>).kind\n ? (q as QNode<T>)\n : { kind: InternalQNodeType.ATOM, where: q as FilterInput<T> };\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<T> | QNode<T>): QuerySet<T> {\n const wrapped: QNode<T> = (q as QNode<T>).kind\n ? (q as QNode<T>)\n : { kind: InternalQNodeType.ATOM, where: q as FilterInput<T> };\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<T>[]): QuerySet<T> {\n const order = tokens.map((t) => {\n const str = String(t);\n if (str.startsWith('-')) {\n return { by: str.slice(1) as keyof T, dir: InternalDirection.DESC };\n }\n return { by: t as keyof T, 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<T> {\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<T> {\n return new QuerySet(this.executor, { ...this.state, offset: n });\n }\n\n /**\n * Restrict selected columns.\n */\n select(cols: (keyof T)[]): QuerySet<T> {\n return new QuerySet(this.executor, { ...this.state, select: cols });\n }\n\n /**\n * Request SQL joins for related data when supported by relation metadata.\n */\n selectRelated(...rels: string[]): QuerySet<T> {\n return new QuerySet(this.executor, { ...this.state, selectRelated: rels });\n }\n\n /**\n * Register relation names for prefetch behavior.\n *\n * Prefetch orchestration is adapter-specific.\n */\n prefetchRelated(...rels: string[]): QuerySet<T> {\n return new QuerySet(this.executor, { ...this.state, prefetchRelated: rels });\n }\n\n /**\n * Execute the query and optionally shape each row.\n */\n async fetch<Out = T>(shape?: ((r: T) => Out) | { parse: (r: T) => Out }): Promise<QueryResult<Out>> {\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\n const results: Out[] = !shape\n ? (normalizedRows as unknown as Out[])\n : typeof shape === 'function'\n ? normalizedRows.map(shape)\n : normalizedRows.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 async fetchOne<Out = T>(shape?: ((r: T) => Out) | { parse: (r: T) => Out }): Promise<Out | null> {\n const limited = this.limit(1);\n const result = 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 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>(rows: T[], shape?: ((r: T) => Out) | { parse: (r: T) => Out }): T[] {\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 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: T, columns: readonly string[]): T {\n let normalized: T | 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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"}