@danceroutine/tango-orm 1.4.0 → 1.6.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/index.d.ts CHANGED
@@ -14,9 +14,9 @@ export type { Adapter, AdapterConfig, DBClient } from './connection/index';
14
14
  export { PostgresAdapter, SqliteAdapter } from './connection/index';
15
15
  export { ModelManager } from './manager/index';
16
16
  export type { ManagerLike } from './manager/index';
17
- export { Q, QBuilder, QueryCompiler, QuerySet } from './query/index';
17
+ export { Q, QBuilder, QueryCompiler, QueryResult, QuerySet } from './query/index';
18
18
  export type { QueryExecutor } from './query/index';
19
- export type { CompiledQuery, Dialect, Direction, FilterInput, FilterKey, FilterValue, LookupType, OrderSpec, OrderToken, QNode, QueryResult, QuerySetState, RelationMeta, TableMeta, WhereClause, } from './query/domain/index';
19
+ export type { CompiledQuery, Dialect, Direction, FilterInput, FilterKey, FilterValue, LookupType, OrderSpec, OrderToken, QNode, QuerySetState, RelationMeta, TableMeta, WhereClause, } from './query/domain/index';
20
20
  export { getTangoRuntime, initializeTangoRuntime, resetTangoRuntime, TangoRuntime } from './runtime/index';
21
21
  export { atomic, UnitOfWork } from './transaction/index';
22
22
  export type { AtomicTransaction, OnCommitOptions, SavepointOptions, SavepointResult } from './transaction/index';
package/dist/index.js CHANGED
@@ -3,11 +3,11 @@ import { PostgresAdapter } from "./PostgresAdapter-CMiEpHya.js";
3
3
  import "./SqliteClient-CjOK9-ki.js";
4
4
  import { SqliteAdapter } from "./SqliteAdapter-CeqhyrPC.js";
5
5
  import { AdapterRegistry, connectDB, connection_exports, getDefaultAdapterRegistry } from "./connection-B_K2ZAf7.js";
6
- import { QBuilder, QueryCompiler, QuerySet, query_exports } from "./query-CWZ1cfjo.js";
6
+ import { QBuilder, QueryCompiler, QueryResult, QuerySet, query_exports } from "./query-C6So1r6H.js";
7
7
  import { TangoRuntime, getTangoRuntime, initializeTangoRuntime, resetTangoRuntime } from "./defaultRuntime-BPK9kWEW.js";
8
- import { ModelManager } from "./registerModelObjects-Bva_f-Qh.js";
8
+ import { ModelManager } from "./registerModelObjects-BKMpfc4Z.js";
9
9
  import { manager_exports } from "./manager-C6oJ2tAF.js";
10
10
  import { runtime_exports } from "./runtime-ByXbpVBS.js";
11
11
  import { UnitOfWork, atomic, transaction_exports } from "./transaction-Cs0Z9tbW.js";
12
12
 
13
- export { AdapterRegistry, ModelManager, PostgresAdapter, QBuilder as Q, QBuilder, QueryCompiler, QuerySet, SqliteAdapter, TangoRuntime, UnitOfWork, atomic, connectDB, connection_exports as connection, getDefaultAdapterRegistry, getTangoRuntime, initializeTangoRuntime, manager_exports as manager, query_exports as query, resetTangoRuntime, runtime_exports as runtime, transaction_exports as transaction };
13
+ export { AdapterRegistry, ModelManager, PostgresAdapter, QBuilder as Q, QBuilder, QueryCompiler, QueryResult, QuerySet, SqliteAdapter, TangoRuntime, UnitOfWork, atomic, connectDB, connection_exports as connection, getDefaultAdapterRegistry, getTangoRuntime, initializeTangoRuntime, manager_exports as manager, query_exports as query, resetTangoRuntime, runtime_exports as runtime, transaction_exports as transaction };
@@ -1,20 +1,20 @@
1
- import { type ModelWriteHooks } from '@danceroutine/tango-schema';
1
+ import type { ModelWriteHooks } from '@danceroutine/tango-schema';
2
+ import type { Model as SchemaModel } from '@danceroutine/tango-schema/domain';
2
3
  import type { TableMeta } from '../query/domain/index';
3
4
  import type { QuerySet } from '../query/index';
4
5
  import type { TangoRuntime } from '../runtime/TangoRuntime';
5
6
  import type { ManagerLike } from './ManagerLike';
6
- type FieldLike = {
7
- name: string;
8
- type: string;
9
- primaryKey?: boolean;
7
+ type ModelMetadataLike = Omit<SchemaModel['metadata'], 'key' | 'namespace' | 'fields'> & {
8
+ key?: string;
9
+ namespace?: string;
10
+ fields: Array<{
11
+ name: string;
12
+ type: string;
13
+ primaryKey?: boolean;
14
+ }>;
10
15
  };
11
16
  type ModelLike<TModelRow extends Record<string, unknown>> = {
12
- metadata: {
13
- key?: string;
14
- name: string;
15
- table: string;
16
- fields: FieldLike[];
17
- };
17
+ metadata: ModelMetadataLike;
18
18
  schema: {
19
19
  parse(input: unknown): TModelRow;
20
20
  };
@@ -1,8 +1,8 @@
1
1
  import "../PostgresClient-BQJZfEOT.js";
2
2
  import "../SqliteClient-CjOK9-ki.js";
3
- import "../query-CWZ1cfjo.js";
3
+ import "../query-C6So1r6H.js";
4
4
  import "../defaultRuntime-BPK9kWEW.js";
5
- import { ModelManager, registerModelObjects } from "../registerModelObjects-Bva_f-Qh.js";
5
+ import { ModelManager, registerModelObjects } from "../registerModelObjects-BKMpfc4Z.js";
6
6
  import "../manager-C6oJ2tAF.js";
7
7
 
8
8
  export { ModelManager, registerModelObjects };
@@ -1,5 +1,5 @@
1
1
  import { __export } from "./chunk-DLY2FNSh.js";
2
- import { ModelManager, registerModelObjects } from "./registerModelObjects-Bva_f-Qh.js";
2
+ import { ModelManager, registerModelObjects } from "./registerModelObjects-BKMpfc4Z.js";
3
3
 
4
4
  //#region src/manager/index.ts
5
5
  var manager_exports = {};
@@ -3,11 +3,11 @@ import type { Dialect } from './domain/Dialect';
3
3
  import type { QuerySetState } from './domain/QuerySetState';
4
4
  import type { TableMeta } from './domain/TableMeta';
5
5
  import type { QNode } from './domain/QNode';
6
- import type { QueryResult } from './domain/QueryResult';
7
6
  import type { OrderToken } from './domain/OrderToken';
8
7
  import type { FilterInput } from './domain/FilterInput';
9
8
  import type { CompiledQuery } from './domain/CompiledQuery';
10
- import type { HydratedQueryResult, ManyRelationHydrationCardinality, MaybeHydratedRelationMap, PrefetchRelatedRelations, RelationKeys, SelectRelatedRelations, SingleRelationHydrationCardinality } from './domain/RelationTyping';
9
+ import { QueryResult } from './domain/QueryResult';
10
+ import type { GeneratedHydratedRelationMap, GeneratedPrefetchRelatedPathKeys, GeneratedSelectRelatedPathKeys, HydratedQueryResult, ManyRelationHydrationCardinality, MaybeHydratedRelationMap, PrefetchRelatedRelations, RelationKeys, SelectRelatedRelations, SingleRelationHydrationCardinality } from './domain/RelationTyping';
11
11
  /**
12
12
  * Query execution seam consumed by `QuerySet`.
13
13
  *
@@ -32,7 +32,13 @@ type ProjectedResult<TModel extends Record<string, unknown>, TKeys extends reado
32
32
  /**
33
33
  * Django-inspired query builder for constructing and executing database queries.
34
34
  * Provides a fluent API for filtering, ordering, pagination, projection, and
35
- * one-level relation hydration.
35
+ * nested relation hydration.
36
+ *
37
+ * Refinements such as `filter`, `orderBy`, `select`, and relation loaders build
38
+ * query state only. SQL runs when you call an evaluation method (`fetch`,
39
+ * `fetchOne`, `count`, `exists`, or `for await` over this queryset). After the
40
+ * first row-returning evaluation, this queryset instance reuses its cached
41
+ * materialized result on later `fetch()` or async-iteration calls.
36
42
  *
37
43
  * @template TModel - The full model row type used for query composition
38
44
  * @template TBaseResult - The selected base-row shape returned by execution methods
@@ -50,11 +56,13 @@ type ProjectedResult<TModel extends Record<string, unknown>, TKeys extends reado
50
56
  * .fetch();
51
57
  * ```
52
58
  */
53
- export declare class QuerySet<TModel extends Record<string, unknown>, TBaseResult extends Record<string, unknown> = TModel, TSourceModel = unknown, THydrated extends Record<string, unknown> = Record<never, never>> {
59
+ export declare class QuerySet<TModel extends Record<string, unknown>, TBaseResult extends Record<string, unknown> = TModel, TSourceModel = unknown, THydrated extends Record<string, unknown> = Record<never, never>> implements AsyncIterable<HydratedQueryResult<TBaseResult, THydrated>> {
60
+ [Symbol.asyncIterator]: () => AsyncIterator<HydratedQueryResult<TBaseResult, THydrated>>;
54
61
  private executor;
55
62
  private state;
56
63
  static readonly BRAND: "tango.orm.query_set";
57
64
  readonly __tangoBrand: typeof QuerySet.BRAND;
65
+ private evaluationCache?;
58
66
  constructor(executor: QueryExecutor<TModel>, state?: QuerySetState<TModel>);
59
67
  /**
60
68
  * Narrow an unknown value to `QuerySet`.
@@ -95,21 +103,24 @@ export declare class QuerySet<TModel extends Record<string, unknown>, TBaseResul
95
103
  select<const TKeys extends readonly (keyof TModel)[]>(fields: TKeys): QuerySet<TModel, ProjectedResult<TModel, TKeys>, TSourceModel, THydrated>;
96
104
  select(fields: readonly (keyof TModel)[]): QuerySet<TModel, ProjectedResult<TModel, readonly (keyof TModel)[]>, TSourceModel, THydrated>;
97
105
  /**
98
- * Hydrate single-valued relations through SQL joins.
106
+ * Hydrate single-valued relation paths through SQL joins.
99
107
  *
100
108
  * Forward `belongsTo` relations can be inferred from the source model's
101
109
  * field-authored relation metadata. Reverse `hasOne` relations can be
102
110
  * selected with a target model generic when the target model points back to
103
- * the source model.
111
+ * the source model. Generated relation typing also enables nested `__`
112
+ * path keys for applications that keep the app-local registry current.
104
113
  */
105
- selectRelated<TTargetModel = undefined, const TRelationName extends RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> = RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>>(...rels: readonly TRelationName[]): QuerySet<TModel, TBaseResult, TSourceModel, THydrated & MaybeHydratedRelationMap<TSourceModel, SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>, TRelationName, SingleRelationHydrationCardinality>>;
114
+ selectRelated<TTargetModel = undefined, const TRelationName extends RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> | GeneratedSelectRelatedPathKeys<TSourceModel> = RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> | GeneratedSelectRelatedPathKeys<TSourceModel>>(...rels: readonly TRelationName[]): QuerySet<TModel, TBaseResult, TSourceModel, THydrated & MaybeHydratedRelationMap<TSourceModel, SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>, Extract<TRelationName, RelationKeys<SelectRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>>, SingleRelationHydrationCardinality> & GeneratedHydratedRelationMap<TSourceModel, Extract<TRelationName, GeneratedSelectRelatedPathKeys<TSourceModel>>>>;
106
115
  /**
107
- * Hydrate collection relations with a follow-up query.
116
+ * Hydrate collection-rooted relation paths with follow-up queries.
108
117
  *
109
118
  * Reverse `hasMany` relations can be prefetched with a target model generic
110
- * when the target model points back to the source model.
119
+ * when the target model points back to the source model. Generated relation
120
+ * typing also enables nested `__` path keys for applications that keep the
121
+ * app-local registry current.
111
122
  */
112
- prefetchRelated<TTargetModel = undefined, const TRelationName extends RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> = RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>>(...rels: readonly TRelationName[]): QuerySet<TModel, TBaseResult, TSourceModel, THydrated & MaybeHydratedRelationMap<TSourceModel, PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>, TRelationName, ManyRelationHydrationCardinality>>;
123
+ prefetchRelated<TTargetModel = undefined, const TRelationName extends RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> | GeneratedPrefetchRelatedPathKeys<TSourceModel> = RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>> | GeneratedPrefetchRelatedPathKeys<TSourceModel>>(...rels: readonly TRelationName[]): QuerySet<TModel, TBaseResult, TSourceModel, THydrated & MaybeHydratedRelationMap<TSourceModel, PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>, Extract<TRelationName, RelationKeys<PrefetchRelatedRelations<TSourceModel, NoInfer<TTargetModel>>>>, ManyRelationHydrationCardinality> & GeneratedHydratedRelationMap<TSourceModel, Extract<TRelationName, GeneratedPrefetchRelatedPathKeys<TSourceModel>>>>;
113
124
  /**
114
125
  * Execute the query and optionally shape each row.
115
126
  *
@@ -120,6 +131,14 @@ export declare class QuerySet<TModel extends Record<string, unknown>, TBaseResul
120
131
  fetch<Out>(shape: QueryShapeFunction<HydratedQueryResult<TBaseResult, THydrated>, Out>): Promise<QueryResult<Out>>;
121
132
  fetch<Out>(shape: QueryShapeParser<HydratedQueryResult<TBaseResult, THydrated>, Out>): Promise<QueryResult<Out>>;
122
133
  fetch<TShape extends QueryShape<HydratedQueryResult<TBaseResult, THydrated>> | undefined>(shape: TShape): Promise<QueryResult<HydratedQueryResult<TBaseResult, THydrated> | QueryShapeOutput<HydratedQueryResult<TBaseResult, THydrated>, NonNullable<TShape>>>>;
134
+ /**
135
+ * Async iterable surface for `for await (... of queryset)`.
136
+ *
137
+ * Evaluates this queryset on first use by awaiting {@link QuerySet.fetch} without arguments, then
138
+ * yields each element from that {@link QueryResult}. Later async iterations over the same queryset
139
+ * instance reuse the cached materialized result instead of issuing another database round-trip.
140
+ */
141
+ [Symbol.asyncIterator](): AsyncIterator<HydratedQueryResult<TBaseResult, THydrated>>;
123
142
  /**
124
143
  * Execute the query and return the first row, or `null`.
125
144
  *
@@ -138,16 +157,19 @@ export declare class QuerySet<TModel extends Record<string, unknown>, TBaseResul
138
157
  * Return whether at least one row matches the current query state.
139
158
  */
140
159
  exists(): Promise<boolean>;
141
- private normalizeRowsForSchemaParsing;
142
- private validateHydrationState;
160
+ private getOrCreateEvaluationCache;
161
+ private evaluateRows;
162
+ private normalizeHydratedRowsForParserShape;
143
163
  private hydrateRows;
144
- private hydrateSelectedRows;
145
- private hydratePrefetchedRows;
146
- private fetchPrefetchGroup;
164
+ private hydrateJoinNodesForOwner;
165
+ private hydratePrefetchNode;
166
+ private groupOwnersByAccessor;
167
+ private canonicalizeEntity;
147
168
  private normalizeTargetRow;
148
- private normalizeTargetValue;
169
+ private normalizeColumnValue;
149
170
  private isBooleanColumnType;
150
171
  private normalizeSqliteBoolean;
151
172
  private normalizeBooleanColumns;
173
+ private withoutHydrationState;
152
174
  }
153
175
  export {};
@@ -1,39 +1,32 @@
1
1
  import type { QuerySetState } from '../domain/QuerySetState';
2
2
  import type { TableMeta } from '../domain/TableMeta';
3
- import type { CompiledPrefetchHydration, CompiledPrefetchQuery, CompiledQuery } from '../domain/CompiledQuery';
3
+ import type { CompiledHydrationNode, CompiledPrefetchQuery, CompiledQuery } from '../domain/CompiledQuery';
4
4
  import type { Dialect } from '../domain/Dialect';
5
5
  /**
6
- * Compiles immutable `QuerySet` state into parameterized SQL.
7
- *
8
- * The compiler is intentionally stateless with respect to execution and only
9
- * produces SQL + params artifacts that can be executed by a `DBClient`.
6
+ * Compiles immutable `QuerySet` state into parameterized SQL and recursive
7
+ * hydration execution artifacts.
10
8
  */
11
9
  export declare class QueryCompiler {
12
10
  private meta;
13
11
  private dialect;
14
12
  static readonly BRAND: "tango.orm.query_compiler";
15
13
  readonly __tangoBrand: typeof QueryCompiler.BRAND;
16
- /**
17
- * Build a compiler for the given repository metadata and SQL dialect.
18
- */
19
14
  constructor(meta: TableMeta, dialect?: Dialect);
20
- /**
21
- * Narrow an unknown value to `QueryCompiler`.
22
- */
23
15
  static isQueryCompiler(value: unknown): value is QueryCompiler;
24
- /**
25
- * Compile a query state tree into a SQL statement and bound parameters.
26
- */
27
16
  compile<T>(state: QuerySetState<T>): CompiledQuery;
28
- /**
29
- * Compile the follow-up query used by `prefetchRelated(...)`.
30
- *
31
- * The base query cannot bind source values until after it has returned rows,
32
- * but SQL rendering and validation still belong to the compiler.
33
- */
34
- compilePrefetch(prefetch: CompiledPrefetchHydration, sourceValues: readonly (string | number)[]): CompiledPrefetchQuery;
17
+ compilePrefetch(node: CompiledHydrationNode, sourceValues: readonly (string | number)[]): CompiledPrefetchQuery;
18
+ private compileHydrationNode;
19
+ private validateHydrationRelation;
20
+ private buildRootHiddenSelects;
21
+ private validatePrefetchTarget;
22
+ private collectNestedJoinSql;
23
+ private validatePrefetchJoinTarget;
24
+ private validateInternalAlias;
25
+ private buildJoinAlias;
26
+ private buildPrefetchBaseAlias;
35
27
  private buildHydrationColumnAlias;
36
28
  private buildPrefetchSourceAlias;
29
+ private sanitizeRelationPath;
37
30
  private assertInternalAliasDoesNotCollide;
38
31
  private compileQNode;
39
32
  private compileAtom;
@@ -1,21 +1,38 @@
1
+ import type { RelationHydrationLoadMode } from './RelationMeta';
2
+ import type { RelationHydrationCardinality } from './RelationTyping';
1
3
  export interface CompiledQuery {
2
4
  sql: string;
3
5
  params: readonly unknown[];
4
- hydrations?: readonly CompiledRelationHydration[];
5
- prefetches?: readonly CompiledPrefetchHydration[];
6
+ hydrationPlan?: CompiledHydrationPlanRoot;
6
7
  }
7
- export interface CompiledRelationHydration {
8
- relationName: string;
9
- alias: string;
10
- columns: Record<string, string>;
8
+ export interface CompiledHydrationPlanRoot {
9
+ requestedPaths: readonly string[];
10
+ hiddenRootAliases: readonly string[];
11
+ joinNodes: readonly CompiledHydrationNode[];
12
+ prefetchNodes: readonly CompiledHydrationNode[];
11
13
  }
12
- export interface CompiledPrefetchHydration {
14
+ export interface CompiledHydrationNode {
15
+ nodeId: string;
13
16
  relationName: string;
17
+ relationPath: string;
18
+ ownerModelKey: string;
19
+ targetModelKey: string;
20
+ loadMode: RelationHydrationLoadMode;
21
+ cardinality: RelationHydrationCardinality;
14
22
  sourceKey: string;
15
- sourceKeyAlias?: string;
16
- table: string;
23
+ ownerSourceAccessor: string;
17
24
  targetKey: string;
25
+ targetTable: string;
26
+ targetPrimaryKey: string;
18
27
  targetColumns: Record<string, string>;
28
+ provenance: readonly string[];
29
+ joinChildren: readonly CompiledHydrationNode[];
30
+ prefetchChildren: readonly CompiledHydrationNode[];
31
+ join?: CompiledJoinHydrationDescriptor;
32
+ }
33
+ export interface CompiledJoinHydrationDescriptor {
34
+ alias: string;
35
+ columns: Record<string, string>;
19
36
  }
20
37
  export interface CompiledPrefetchQuery {
21
38
  sql: string;
@@ -1,4 +1,35 @@
1
- export interface QueryResult<T> {
2
- results: T[];
3
- nextCursor?: string | null;
1
+ /**
2
+ * Values materialized by {@link QuerySet.fetch}, iterable like an array plus `length`, `map`, `at`, and `toArray`.
3
+ *
4
+ * Prefer iteration or `items` over the deprecated `results` getter, which warns once per process when accessed.
5
+ */
6
+ export declare class QueryResult<T> implements Iterable<T> {
7
+ /**
8
+ * Sync iteration over materialized rows.
9
+ */
10
+ [Symbol.iterator]: () => Iterator<T>;
11
+ static readonly BRAND: "tango.orm.query_result";
12
+ readonly __tangoBrand: typeof QueryResult.BRAND;
13
+ readonly items: readonly T[];
14
+ constructor(items: readonly T[]);
15
+ /**
16
+ * Runtime narrowing for values that may be a plain array or a `QueryResult` instance.
17
+ */
18
+ static isQueryResult<T>(value: unknown): value is QueryResult<T>;
19
+ /**
20
+ * Sync iteration over materialized rows.
21
+ */
22
+ [Symbol.iterator](): Iterator<T>;
23
+ /** Number of materialized rows. */
24
+ get length(): number;
25
+ /** Same as `Array#map` on the materialized rows. */
26
+ map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: unknown): U[];
27
+ /** Indexed read with support for negative indices, like `Array#at`. */
28
+ at(index: number): T | undefined;
29
+ /** Returns a shallow copy of the materialized rows as a plain array. */
30
+ toArray(): T[];
31
+ /**
32
+ * @deprecated Use iteration, `length`, `map`, or `toArray()` instead.
33
+ */
34
+ get results(): readonly T[];
4
35
  }
@@ -1,10 +1,47 @@
1
1
  import type { InternalRelationKind } from './internal/InternalRelationKind';
2
+ import type { RelationHydrationCardinality } from './RelationTyping';
3
+ import type { TableMeta } from './TableMeta';
2
4
  export type RelationKind = (typeof InternalRelationKind)[keyof typeof InternalRelationKind];
5
+ export declare const InternalRelationHydrationLoadMode: {
6
+ readonly JOIN: "join";
7
+ readonly PREFETCH: "prefetch";
8
+ };
9
+ export type RelationHydrationLoadMode = (typeof InternalRelationHydrationLoadMode)[keyof typeof InternalRelationHydrationLoadMode];
10
+ export interface RelationHydrationCapabilities {
11
+ queryable: boolean;
12
+ hydratable: boolean;
13
+ joinable: boolean;
14
+ prefetchable: boolean;
15
+ }
16
+ /**
17
+ * Runtime relation metadata consumed by validation, planning, compilation, and
18
+ * hydration.
19
+ */
3
20
  export interface RelationMeta {
21
+ /** Stable edge identity from the resolved relation graph. */
22
+ edgeId: string;
23
+ /** Model key that owns the public relation name. */
24
+ sourceModelKey: string;
25
+ /** Model key reached by traversing this relation. */
26
+ targetModelKey: string;
27
+ /** Public relation kind such as belongsTo or hasMany. */
4
28
  kind: RelationKind;
29
+ /** Hydration cardinality used by eager-loading APIs. */
30
+ cardinality: RelationHydrationCardinality;
31
+ /** Capability flags distilled from the resolved relation graph. */
32
+ capabilities: RelationHydrationCapabilities;
33
+ /** Physical table storing the target model rows. */
5
34
  table: string;
35
+ /** Owner-side column used to attach or query related rows. */
6
36
  sourceKey: string;
37
+ /** Target-side column matched against the source key. */
7
38
  targetKey: string;
39
+ /** Primary key column for the target model. */
40
+ targetPrimaryKey: string;
41
+ /** Target model columns and their storage types. */
8
42
  targetColumns: Record<string, string>;
43
+ /** Deterministic alias base used by join compilation. */
9
44
  alias: string;
45
+ /** Recursive target metadata used for nested planning. */
46
+ targetMeta?: TableMeta;
10
47
  }
@@ -11,12 +11,54 @@ export type ManyRelationHydrationCardinality = typeof InternalRelationHydrationC
11
11
  export type HydratedQueryResult<TBase extends Record<string, unknown>, THydrated extends Record<string, unknown>> = [
12
12
  keyof THydrated
13
13
  ] extends [never] ? TBase : Omit<TBase, keyof THydrated> & THydrated;
14
+ declare global {
15
+ interface TangoGeneratedRelationRegistry {
16
+ }
17
+ }
14
18
  type AnyModel = Model<z.ZodObject<z.ZodRawShape>, string>;
15
19
  type ModelSchema<TModel> = TModel extends Model<infer TSchema extends z.ZodObject<z.ZodRawShape>, string> ? TSchema : never;
16
20
  type ModelShape<TModel> = ModelSchema<TModel> extends z.ZodObject<infer TShape> ? TShape : never;
17
21
  type ModelRow<TModel> = TModel extends Model<infer TSchema extends z.ZodObject<z.ZodRawShape>, string> ? PersistedModelOutput<TSchema> : never;
18
22
  type IsLiteralString<TValue> = TValue extends string ? (string extends TValue ? false : true) : false;
19
23
  type HasStrictModelKey<TModel> = TModel extends Model<z.ZodObject<z.ZodRawShape>, infer TKey> ? IsLiteralString<TKey> : false;
24
+ type ModelKey<TModel> = TModel extends Model<z.ZodObject<z.ZodRawShape>, infer TKey extends string> ? TKey : never;
25
+ type UnionToIntersection<TValue> = (TValue extends unknown ? (value: TValue) => void : never) extends (value: infer TIntersection) => void ? TIntersection : never;
26
+ type JoinPathSegments<TSegments extends readonly string[]> = TSegments extends readonly [
27
+ infer THead extends string,
28
+ ...infer TRest extends string[]
29
+ ] ? TRest['length'] extends 0 ? THead : `${THead}__${JoinPathSegments<TRest>}` : never;
30
+ type SplitPath<TPath extends string> = TPath extends `${infer THead}__${infer TRest}` ? [THead, ...SplitPath<TRest>] : [TPath];
31
+ type TailTuple<TTuple extends readonly unknown[]> = TTuple extends readonly [unknown, ...infer TRest] ? TRest : [];
32
+ type DefaultGeneratedCycleBudget = readonly [1, 1, 1, 1];
33
+ type GeneratedRelationRegistry = TangoGeneratedRelationRegistry;
34
+ type GeneratedRelationKeys<TSourceModel> = Extract<keyof GeneratedRelations<TSourceModel>, string>;
35
+ type GeneratedRelations<TSourceModel> = HasStrictModelKey<TSourceModel> extends true ? ModelKey<TSourceModel> extends keyof GeneratedRelationRegistry ? GeneratedRelationRegistry[ModelKey<TSourceModel>] : {} : {};
36
+ type NextSeenModels<TSeen extends readonly string[], TTargetModel> = ModelKey<TTargetModel> extends string ? [...TSeen, ModelKey<TTargetModel>] : TSeen;
37
+ type CanTraverseGeneratedTarget<TTargetModel, TSeen extends readonly string[], TCycleBudget extends readonly unknown[]> = ModelKey<TTargetModel> extends TSeen[number] ? (TCycleBudget extends [] ? false : true) : true;
38
+ type NextGeneratedCycleBudget<TTargetModel, TSeen extends readonly string[], TCycleBudget extends readonly unknown[]> = ModelKey<TTargetModel> extends TSeen[number] ? TailTuple<TCycleBudget> : TCycleBudget;
39
+ type GeneratedCardinalityIncludesMany<TCardinality extends RelationHydrationCardinality> = TCardinality extends typeof InternalRelationHydrationCardinality.MANY ? true : false;
40
+ export type GeneratedSelectRelatedPathKeys<TSourceModel, TSeen extends readonly string[] = [ModelKey<TSourceModel>], TCycleBudget extends readonly unknown[] = DefaultGeneratedCycleBudget> = {
41
+ [TKey in GeneratedRelationKeys<TSourceModel>]: GeneratedRelations<TSourceModel>[TKey] extends {
42
+ target: infer TTarget extends AnyModel;
43
+ cardinality: typeof InternalRelationHydrationCardinality.SINGLE;
44
+ } ? TKey | (CanTraverseGeneratedTarget<TTarget, TSeen, TCycleBudget> extends true ? `${TKey}__${GeneratedSelectRelatedPathKeys<TTarget, NextSeenModels<TSeen, TTarget>, NextGeneratedCycleBudget<TTarget, TSeen, TCycleBudget>>}` : never) : never;
45
+ }[GeneratedRelationKeys<TSourceModel>];
46
+ export type GeneratedPrefetchRelatedPathKeys<TSourceModel, THasMany extends boolean = false, TSeen extends readonly string[] = [ModelKey<TSourceModel>], TCycleBudget extends readonly unknown[] = DefaultGeneratedCycleBudget> = {
47
+ [TKey in GeneratedRelationKeys<TSourceModel>]: GeneratedRelations<TSourceModel>[TKey] extends {
48
+ target: infer TTarget extends AnyModel;
49
+ cardinality: infer TCardinality extends RelationHydrationCardinality;
50
+ } ? (THasMany extends true ? TKey : GeneratedCardinalityIncludesMany<TCardinality> extends true ? TKey : never) | (CanTraverseGeneratedTarget<TTarget, TSeen, TCycleBudget> extends true ? `${TKey}__${GeneratedPrefetchRelatedPathKeys<TTarget, THasMany extends true ? true : GeneratedCardinalityIncludesMany<TCardinality>, NextSeenModels<TSeen, TTarget>, NextGeneratedCycleBudget<TTarget, TSeen, TCycleBudget>>}` : never) : never;
51
+ }[GeneratedRelationKeys<TSourceModel>];
52
+ type GeneratedHydratedTarget<TDescriptor, TPath extends string | never> = TDescriptor extends {
53
+ target: infer TTarget extends AnyModel;
54
+ } ? [TPath] extends [never] ? ModelRow<TTarget> : HydratedQueryResult<ModelRow<TTarget>, GeneratedHydratedRelationMap<TTarget, TPath>> : never;
55
+ type GeneratedHydratedValue<TDescriptor, TPath extends string | never> = TDescriptor extends {
56
+ cardinality: infer TCardinality extends RelationHydrationCardinality;
57
+ } ? TCardinality extends typeof InternalRelationHydrationCardinality.SINGLE ? GeneratedHydratedTarget<TDescriptor, TPath> | null : GeneratedHydratedTarget<TDescriptor, TPath>[] : never;
58
+ type GeneratedHydrationForPath<TSourceModel, TPath extends string> = SplitPath<TPath> extends [infer THead extends string, ...infer TRest extends string[]] ? THead extends GeneratedRelationKeys<TSourceModel> ? {
59
+ [TKey in THead]: GeneratedHydratedValue<GeneratedRelations<TSourceModel>[THead], JoinPathSegments<TRest>>;
60
+ } : {} : {};
61
+ export type GeneratedHydratedRelationMap<TSourceModel, TPaths extends string | never> = ([TPaths] extends [never] ? Record<never, never> : UnionToIntersection<TPaths extends string ? GeneratedHydrationForPath<TSourceModel, TPaths> : never>) & Record<never, never>;
20
62
  export type HasStrictRelationTyping<TSourceModel> = HasStrictModelKey<TSourceModel>;
21
63
  type ModelKeysMatch<TCandidate, TExpected> = TCandidate extends Model<z.ZodObject<z.ZodRawShape>, infer TCandidateKey> ? TExpected extends Model<z.ZodObject<z.ZodRawShape>, infer TExpectedKey> ? IsLiteralString<TCandidateKey> extends true ? IsLiteralString<TExpectedKey> extends true ? [
22
64
  TCandidateKey
@@ -1,7 +1,16 @@
1
1
  import type { RelationMeta } from './RelationMeta';
2
+ /**
3
+ * SQL-facing model metadata visible to the ORM layer.
4
+ */
2
5
  export interface TableMeta {
6
+ /** Stable model key when the table comes from a registered Tango model. */
7
+ modelKey?: string;
8
+ /** Physical table name used in compiled SQL. */
3
9
  table: string;
10
+ /** Primary key column name. */
4
11
  pk: string;
12
+ /** Base columns and their storage types. */
5
13
  columns: Record<string, string>;
14
+ /** Relation metadata keyed by public relation name. */
6
15
  relations?: Record<string, RelationMeta>;
7
16
  }
@@ -0,0 +1,23 @@
1
+ import type { Model as SchemaModel } from '@danceroutine/tango-schema/domain';
2
+ import type { TableMeta } from './TableMeta';
3
+ type ModelMetadataLike = Omit<SchemaModel['metadata'], 'key' | 'namespace' | 'fields'> & {
4
+ key?: string;
5
+ namespace?: string;
6
+ fields: Array<{
7
+ name: string;
8
+ type: string;
9
+ primaryKey?: boolean;
10
+ }>;
11
+ };
12
+ type TableMetaModel = {
13
+ metadata: ModelMetadataLike;
14
+ };
15
+ /**
16
+ * Build registry-backed recursive table metadata for query planning and
17
+ * hydration execution.
18
+ */
19
+ export declare class TableMetaFactory {
20
+ static create(model: TableMetaModel): TableMeta;
21
+ private static createWithCache;
22
+ }
23
+ export {};
@@ -11,10 +11,11 @@ export type { LookupType } from './LookupType';
11
11
  export type { OrderSpec } from './OrderSpec';
12
12
  export type { OrderToken } from './OrderToken';
13
13
  export type { QNode } from './QNode';
14
- export type { QueryResult } from './QueryResult';
14
+ export { QueryResult } from './QueryResult';
15
15
  export type { QuerySetState } from './QuerySetState';
16
16
  export type { RelationMeta } from './RelationMeta';
17
- export type { ForwardSingleRelations, HydratedQueryResult, HydratedRelationMap, ManyRelationHydrationCardinality, MaybeHydratedRelationMap, PrefetchRelatedRelations, RelationKeys, RelationHydrationCardinality, ReverseCollectionRelations, ReverseSingleRelations, SelectRelatedRelations, SingleRelationHydrationCardinality, } from './RelationTyping';
17
+ export type { ForwardSingleRelations, GeneratedHydratedRelationMap, GeneratedPrefetchRelatedPathKeys, GeneratedSelectRelatedPathKeys, HydratedQueryResult, HydratedRelationMap, ManyRelationHydrationCardinality, MaybeHydratedRelationMap, PrefetchRelatedRelations, RelationKeys, RelationHydrationCardinality, ReverseCollectionRelations, ReverseSingleRelations, SelectRelatedRelations, SingleRelationHydrationCardinality, } from './RelationTyping';
18
18
  export { InternalRelationHydrationCardinality } from './RelationTyping';
19
19
  export type { TableMeta } from './TableMeta';
20
+ export { TableMetaFactory } from './TableMetaFactory';
20
21
  export type { WhereClause } from './WhereClause';
@@ -6,6 +6,7 @@ export * as compiler from './compiler/index';
6
6
  export * as domain from './domain/index';
7
7
  export type * from './domain/index';
8
8
  export type { TableMeta } from './domain/index';
9
+ export { QueryResult } from './domain/index';
9
10
  export { QuerySet } from './QuerySet';
10
11
  export type { QueryExecutor } from './QuerySet';
11
12
  export { QBuilder, QBuilder as Q } from './QBuilder';
@@ -1,3 +1,3 @@
1
- import { QBuilder, QueryCompiler, QuerySet, compiler_exports, domain_exports } from "../query-CWZ1cfjo.js";
1
+ import { QBuilder, QueryCompiler, QueryResult, QuerySet, compiler_exports, domain_exports } from "../query-C6So1r6H.js";
2
2
 
3
- export { QBuilder as Q, QBuilder, QueryCompiler, QuerySet, compiler_exports as compiler, domain_exports as domain };
3
+ export { QBuilder as Q, QBuilder, QueryCompiler, QueryResult, QuerySet, compiler_exports as compiler, domain_exports as domain };
@@ -0,0 +1,16 @@
1
+ import type { QuerySetState } from '../domain/QuerySetState';
2
+ import type { TableMeta } from '../domain/TableMeta';
3
+ import type { QueryHydrationPlanRoot } from './domain/QueryHydrationPlan';
4
+ /**
5
+ * Parse, validate, normalize, and plan recursive relation hydration paths.
6
+ */
7
+ export declare class QueryPlanner {
8
+ private readonly meta;
9
+ static readonly BRAND: "tango.orm.query_planner";
10
+ readonly __tangoBrand: typeof QueryPlanner.BRAND;
11
+ constructor(meta: TableMeta);
12
+ static isQueryPlanner(value: unknown): value is QueryPlanner;
13
+ plan<T>(state: QuerySetState<T>): QueryHydrationPlanRoot;
14
+ private addPath;
15
+ private buildPlannedChildren;
16
+ }
@@ -0,0 +1,20 @@
1
+ import type { RelationHydrationLoadMode, RelationMeta } from '../../domain/RelationMeta';
2
+ export type QueryHydrationLoadMode = RelationHydrationLoadMode;
3
+ export interface QueryHydrationPlanRoot {
4
+ joinNodes: readonly QueryHydrationPlanNode[];
5
+ prefetchNodes: readonly QueryHydrationPlanNode[];
6
+ requestedPaths: readonly string[];
7
+ }
8
+ export interface QueryHydrationPlanNode {
9
+ nodeId: string;
10
+ relationName: string;
11
+ relationPath: string;
12
+ ownerModelKey: string;
13
+ relationEdge: RelationMeta;
14
+ targetModelKey: string;
15
+ loadMode: QueryHydrationLoadMode;
16
+ cardinality: RelationMeta['cardinality'];
17
+ provenance: readonly string[];
18
+ joinChildren: readonly QueryHydrationPlanNode[];
19
+ prefetchChildren: readonly QueryHydrationPlanNode[];
20
+ }
@@ -0,0 +1,2 @@
1
+ export { QueryPlanner } from './QueryPlanner';
2
+ export type { QueryHydrationPlanNode, QueryHydrationPlanRoot, QueryHydrationLoadMode, } from './domain/QueryHydrationPlan';