metal-orm 1.0.71 → 1.0.73
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.cjs +163 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +163 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/orm/entity-relations.ts +19 -19
- package/src/orm/entity.ts +74 -47
- package/src/orm/execute.ts +23 -19
- package/src/orm/relation-preload.ts +82 -0
- package/src/query-builder/relation-include-tree.ts +98 -0
- package/src/query-builder/select.ts +108 -64
|
@@ -29,8 +29,17 @@ import {
|
|
|
29
29
|
SelectQueryBuilderEnvironment
|
|
30
30
|
} from './select-query-builder-deps.js';
|
|
31
31
|
import { ColumnSelector } from './column-selector.js';
|
|
32
|
-
import { RelationIncludeOptions, RelationTargetColumns, TypedRelationIncludeOptions } from './relation-types.js';
|
|
33
|
-
import { RelationKinds } from '../schema/relation.js';
|
|
32
|
+
import { RelationIncludeOptions, RelationTargetColumns, TypedRelationIncludeOptions } from './relation-types.js';
|
|
33
|
+
import { RelationKinds } from '../schema/relation.js';
|
|
34
|
+
import {
|
|
35
|
+
RelationIncludeInput,
|
|
36
|
+
RelationIncludeNodeInput,
|
|
37
|
+
NormalizedRelationIncludeTree,
|
|
38
|
+
cloneRelationIncludeTree,
|
|
39
|
+
mergeRelationIncludeTrees,
|
|
40
|
+
normalizeRelationInclude,
|
|
41
|
+
normalizeRelationIncludeNode
|
|
42
|
+
} from './relation-include-tree.js';
|
|
34
43
|
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../core/sql/sql.js';
|
|
35
44
|
import { EntityInstance, RelationMap } from '../schema/types.js';
|
|
36
45
|
import type { ColumnToTs, InferRow } from '../schema/types.js';
|
|
@@ -104,10 +113,11 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
104
113
|
private readonly predicateFacet: SelectPredicateFacet;
|
|
105
114
|
private readonly cteFacet: SelectCTEFacet;
|
|
106
115
|
private readonly setOpFacet: SelectSetOpFacet;
|
|
107
|
-
private readonly relationFacet: SelectRelationFacet;
|
|
108
|
-
private readonly lazyRelations: Set<string>;
|
|
109
|
-
private readonly lazyRelationOptions: Map<string, RelationIncludeOptions>;
|
|
110
|
-
private readonly entityConstructor?: EntityConstructor;
|
|
116
|
+
private readonly relationFacet: SelectRelationFacet;
|
|
117
|
+
private readonly lazyRelations: Set<string>;
|
|
118
|
+
private readonly lazyRelationOptions: Map<string, RelationIncludeOptions>;
|
|
119
|
+
private readonly entityConstructor?: EntityConstructor;
|
|
120
|
+
private readonly includeTree: NormalizedRelationIncludeTree;
|
|
111
121
|
|
|
112
122
|
/**
|
|
113
123
|
* Creates a new SelectQueryBuilder instance
|
|
@@ -116,15 +126,16 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
116
126
|
* @param hydration - Optional hydration manager
|
|
117
127
|
* @param dependencies - Optional query builder dependencies
|
|
118
128
|
*/
|
|
119
|
-
constructor(
|
|
120
|
-
table: TTable,
|
|
121
|
-
state?: SelectQueryState,
|
|
122
|
-
hydration?: HydrationManager,
|
|
123
|
-
dependencies?: Partial<SelectQueryBuilderDependencies>,
|
|
124
|
-
lazyRelations?: Set<string>,
|
|
125
|
-
lazyRelationOptions?: Map<string, RelationIncludeOptions>,
|
|
126
|
-
entityConstructor?: EntityConstructor
|
|
127
|
-
|
|
129
|
+
constructor(
|
|
130
|
+
table: TTable,
|
|
131
|
+
state?: SelectQueryState,
|
|
132
|
+
hydration?: HydrationManager,
|
|
133
|
+
dependencies?: Partial<SelectQueryBuilderDependencies>,
|
|
134
|
+
lazyRelations?: Set<string>,
|
|
135
|
+
lazyRelationOptions?: Map<string, RelationIncludeOptions>,
|
|
136
|
+
entityConstructor?: EntityConstructor,
|
|
137
|
+
includeTree?: NormalizedRelationIncludeTree
|
|
138
|
+
) {
|
|
128
139
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
129
140
|
this.env = { table, deps };
|
|
130
141
|
const createAstService = (nextState: SelectQueryState) => deps.createQueryAstService(table, nextState);
|
|
@@ -134,10 +145,11 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
134
145
|
state: initialState,
|
|
135
146
|
hydration: initialHydration
|
|
136
147
|
};
|
|
137
|
-
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
138
|
-
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
139
|
-
this.entityConstructor = entityConstructor;
|
|
140
|
-
this.
|
|
148
|
+
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
149
|
+
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
150
|
+
this.entityConstructor = entityConstructor;
|
|
151
|
+
this.includeTree = includeTree ?? {};
|
|
152
|
+
this.columnSelector = deps.createColumnSelector(this.env);
|
|
141
153
|
const relationManager = deps.createRelationManager(this.env);
|
|
142
154
|
this.fromFacet = new SelectFromFacet(this.env, createAstService);
|
|
143
155
|
this.joinFacet = new SelectJoinFacet(this.env, createAstService);
|
|
@@ -154,21 +166,23 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
154
166
|
* @param lazyRelations - Updated lazy relations set
|
|
155
167
|
* @returns New SelectQueryBuilder instance
|
|
156
168
|
*/
|
|
157
|
-
private clone<TNext = T>(
|
|
158
|
-
context: SelectQueryBuilderContext = this.context,
|
|
159
|
-
lazyRelations = new Set(this.lazyRelations),
|
|
160
|
-
lazyRelationOptions = new Map(this.lazyRelationOptions)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
context.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
private clone<TNext = T>(
|
|
170
|
+
context: SelectQueryBuilderContext = this.context,
|
|
171
|
+
lazyRelations = new Set(this.lazyRelations),
|
|
172
|
+
lazyRelationOptions = new Map(this.lazyRelationOptions),
|
|
173
|
+
includeTree = this.includeTree
|
|
174
|
+
): SelectQueryBuilder<TNext, TTable> {
|
|
175
|
+
return new SelectQueryBuilder(
|
|
176
|
+
this.env.table as TTable,
|
|
177
|
+
context.state,
|
|
178
|
+
context.hydration,
|
|
179
|
+
this.env.deps,
|
|
180
|
+
lazyRelations,
|
|
181
|
+
lazyRelationOptions,
|
|
182
|
+
this.entityConstructor,
|
|
183
|
+
includeTree
|
|
184
|
+
) as SelectQueryBuilder<TNext, TTable>;
|
|
185
|
+
}
|
|
172
186
|
|
|
173
187
|
/**
|
|
174
188
|
* Applies an alias to the root FROM table.
|
|
@@ -548,19 +562,42 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
548
562
|
* qb.include('posts');
|
|
549
563
|
* @example
|
|
550
564
|
* qb.include('posts', { columns: ['id', 'title', 'published'] });
|
|
551
|
-
* @example
|
|
552
|
-
* qb.include('posts', {
|
|
553
|
-
* columns: ['id', 'title'],
|
|
554
|
-
* where: eq(postTable.columns.published, true)
|
|
555
|
-
* });
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
565
|
+
* @example
|
|
566
|
+
* qb.include('posts', {
|
|
567
|
+
* columns: ['id', 'title'],
|
|
568
|
+
* where: eq(postTable.columns.published, true)
|
|
569
|
+
* });
|
|
570
|
+
* @example
|
|
571
|
+
* qb.include({ posts: { include: { author: true } } });
|
|
572
|
+
*/
|
|
573
|
+
include<K extends keyof TTable['relations'] & string>(
|
|
574
|
+
relationName: K,
|
|
575
|
+
options?: RelationIncludeNodeInput<TTable['relations'][K]>
|
|
576
|
+
): SelectQueryBuilder<T, TTable>;
|
|
577
|
+
include(relations: RelationIncludeInput<TTable>): SelectQueryBuilder<T, TTable>;
|
|
578
|
+
include<K extends keyof TTable['relations'] & string>(
|
|
579
|
+
relationNameOrRelations: K | RelationIncludeInput<TTable>,
|
|
580
|
+
options?: RelationIncludeNodeInput<TTable['relations'][K]>
|
|
581
|
+
): SelectQueryBuilder<T, TTable> {
|
|
582
|
+
if (typeof relationNameOrRelations === 'object' && relationNameOrRelations !== null) {
|
|
583
|
+
const normalized = normalizeRelationInclude(relationNameOrRelations as RelationIncludeInput<TableDef>);
|
|
584
|
+
let nextContext = this.context;
|
|
585
|
+
for (const [relationName, node] of Object.entries(normalized)) {
|
|
586
|
+
nextContext = this.relationFacet.include(nextContext, relationName, node.options);
|
|
587
|
+
}
|
|
588
|
+
const nextTree = mergeRelationIncludeTrees(this.includeTree, normalized);
|
|
589
|
+
return this.clone(nextContext, undefined, undefined, nextTree);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const relationName = relationNameOrRelations as string;
|
|
593
|
+
const normalizedNode = normalizeRelationIncludeNode(options);
|
|
594
|
+
const nextContext = this.relationFacet.include(this.context, relationName, normalizedNode.options);
|
|
595
|
+
const shouldStore = Boolean(normalizedNode.include || normalizedNode.options);
|
|
596
|
+
const nextTree = shouldStore
|
|
597
|
+
? mergeRelationIncludeTrees(this.includeTree, { [relationName]: normalizedNode })
|
|
598
|
+
: this.includeTree;
|
|
599
|
+
return this.clone(nextContext, undefined, undefined, nextTree);
|
|
600
|
+
}
|
|
564
601
|
|
|
565
602
|
/**
|
|
566
603
|
* Includes a relation lazily in the query results
|
|
@@ -608,13 +645,13 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
608
645
|
* @example
|
|
609
646
|
* qb.includePick('posts', ['id', 'title', 'createdAt']);
|
|
610
647
|
*/
|
|
611
|
-
includePick<
|
|
612
|
-
K extends keyof TTable['relations'] & string,
|
|
613
|
-
C extends RelationTargetColumns<TTable['relations'][K]>
|
|
614
|
-
>(relationName: K, cols: C[]): SelectQueryBuilder<T, TTable> {
|
|
615
|
-
const options = { columns: cols as readonly C[] } as unknown as
|
|
616
|
-
return this.include(relationName, options);
|
|
617
|
-
}
|
|
648
|
+
includePick<
|
|
649
|
+
K extends keyof TTable['relations'] & string,
|
|
650
|
+
C extends RelationTargetColumns<TTable['relations'][K]>
|
|
651
|
+
>(relationName: K, cols: C[]): SelectQueryBuilder<T, TTable> {
|
|
652
|
+
const options = { columns: cols as readonly C[] } as unknown as RelationIncludeNodeInput<TTable['relations'][K]>;
|
|
653
|
+
return this.include(relationName, options);
|
|
654
|
+
}
|
|
618
655
|
|
|
619
656
|
/**
|
|
620
657
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -631,13 +668,13 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
631
668
|
let currBuilder: SelectQueryBuilder<T, TTable> = this;
|
|
632
669
|
|
|
633
670
|
for (const entry of config) {
|
|
634
|
-
if (entry.type === 'root') {
|
|
635
|
-
currBuilder = currBuilder.select(...entry.columns);
|
|
636
|
-
} else {
|
|
637
|
-
const options = { columns: entry.columns } as unknown as
|
|
638
|
-
currBuilder = currBuilder.include(entry.relationName, options);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
671
|
+
if (entry.type === 'root') {
|
|
672
|
+
currBuilder = currBuilder.select(...entry.columns);
|
|
673
|
+
} else {
|
|
674
|
+
const options = { columns: entry.columns } as unknown as RelationIncludeNodeInput<TTable['relations'][typeof entry.relationName]>;
|
|
675
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
641
678
|
|
|
642
679
|
return currBuilder;
|
|
643
680
|
}
|
|
@@ -654,9 +691,16 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
654
691
|
* Gets lazy relation include options
|
|
655
692
|
* @returns Map of relation names to include options
|
|
656
693
|
*/
|
|
657
|
-
getLazyRelationOptions(): Map<string, RelationIncludeOptions> {
|
|
658
|
-
return new Map(this.lazyRelationOptions);
|
|
659
|
-
}
|
|
694
|
+
getLazyRelationOptions(): Map<string, RelationIncludeOptions> {
|
|
695
|
+
return new Map(this.lazyRelationOptions);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Gets normalized nested include information for runtime preloading.
|
|
700
|
+
*/
|
|
701
|
+
getIncludeTree(): NormalizedRelationIncludeTree {
|
|
702
|
+
return cloneRelationIncludeTree(this.includeTree);
|
|
703
|
+
}
|
|
660
704
|
|
|
661
705
|
/**
|
|
662
706
|
* Gets the table definition for this query builder
|