metal-orm 1.0.77 → 1.0.79
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 +5 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +5 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/inflection/pt-br.mjs +51 -14
- package/src/query-builder/select/select-operations.ts +149 -144
- package/src/query-builder/select.ts +113 -111
|
@@ -29,17 +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';
|
|
34
|
-
import {
|
|
35
|
-
RelationIncludeInput,
|
|
36
|
-
RelationIncludeNodeInput,
|
|
37
|
-
NormalizedRelationIncludeTree,
|
|
38
|
-
cloneRelationIncludeTree,
|
|
39
|
-
mergeRelationIncludeTrees,
|
|
40
|
-
normalizeRelationInclude,
|
|
41
|
-
normalizeRelationIncludeNode
|
|
42
|
-
} from './relation-include-tree.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';
|
|
43
43
|
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../core/sql/sql.js';
|
|
44
44
|
import { EntityInstance, RelationMap } from '../schema/types.js';
|
|
45
45
|
import type { ColumnToTs, InferRow } from '../schema/types.js';
|
|
@@ -55,9 +55,11 @@ import {
|
|
|
55
55
|
buildWhereHasPredicate,
|
|
56
56
|
executeCount,
|
|
57
57
|
executePagedQuery,
|
|
58
|
+
PaginatedResult,
|
|
58
59
|
RelationCallback,
|
|
59
60
|
WhereHasOptions
|
|
60
61
|
} from './select/select-operations.js';
|
|
62
|
+
export type { PaginatedResult };
|
|
61
63
|
import { SelectFromFacet } from './select/from-facet.js';
|
|
62
64
|
import { SelectJoinFacet } from './select/join-facet.js';
|
|
63
65
|
import { SelectProjectionFacet } from './select/projection-facet.js';
|
|
@@ -113,11 +115,11 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
113
115
|
private readonly predicateFacet: SelectPredicateFacet;
|
|
114
116
|
private readonly cteFacet: SelectCTEFacet;
|
|
115
117
|
private readonly setOpFacet: SelectSetOpFacet;
|
|
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;
|
|
118
|
+
private readonly relationFacet: SelectRelationFacet;
|
|
119
|
+
private readonly lazyRelations: Set<string>;
|
|
120
|
+
private readonly lazyRelationOptions: Map<string, RelationIncludeOptions>;
|
|
121
|
+
private readonly entityConstructor?: EntityConstructor;
|
|
122
|
+
private readonly includeTree: NormalizedRelationIncludeTree;
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* Creates a new SelectQueryBuilder instance
|
|
@@ -126,16 +128,16 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
126
128
|
* @param hydration - Optional hydration manager
|
|
127
129
|
* @param dependencies - Optional query builder dependencies
|
|
128
130
|
*/
|
|
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
|
-
) {
|
|
131
|
+
constructor(
|
|
132
|
+
table: TTable,
|
|
133
|
+
state?: SelectQueryState,
|
|
134
|
+
hydration?: HydrationManager,
|
|
135
|
+
dependencies?: Partial<SelectQueryBuilderDependencies>,
|
|
136
|
+
lazyRelations?: Set<string>,
|
|
137
|
+
lazyRelationOptions?: Map<string, RelationIncludeOptions>,
|
|
138
|
+
entityConstructor?: EntityConstructor,
|
|
139
|
+
includeTree?: NormalizedRelationIncludeTree
|
|
140
|
+
) {
|
|
139
141
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
140
142
|
this.env = { table, deps };
|
|
141
143
|
const createAstService = (nextState: SelectQueryState) => deps.createQueryAstService(table, nextState);
|
|
@@ -145,11 +147,11 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
145
147
|
state: initialState,
|
|
146
148
|
hydration: initialHydration
|
|
147
149
|
};
|
|
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);
|
|
150
|
+
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
151
|
+
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
152
|
+
this.entityConstructor = entityConstructor;
|
|
153
|
+
this.includeTree = includeTree ?? {};
|
|
154
|
+
this.columnSelector = deps.createColumnSelector(this.env);
|
|
153
155
|
const relationManager = deps.createRelationManager(this.env);
|
|
154
156
|
this.fromFacet = new SelectFromFacet(this.env, createAstService);
|
|
155
157
|
this.joinFacet = new SelectJoinFacet(this.env, createAstService);
|
|
@@ -166,23 +168,23 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
166
168
|
* @param lazyRelations - Updated lazy relations set
|
|
167
169
|
* @returns New SelectQueryBuilder instance
|
|
168
170
|
*/
|
|
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
|
-
}
|
|
171
|
+
private clone<TNext = T>(
|
|
172
|
+
context: SelectQueryBuilderContext = this.context,
|
|
173
|
+
lazyRelations = new Set(this.lazyRelations),
|
|
174
|
+
lazyRelationOptions = new Map(this.lazyRelationOptions),
|
|
175
|
+
includeTree = this.includeTree
|
|
176
|
+
): SelectQueryBuilder<TNext, TTable> {
|
|
177
|
+
return new SelectQueryBuilder(
|
|
178
|
+
this.env.table as TTable,
|
|
179
|
+
context.state,
|
|
180
|
+
context.hydration,
|
|
181
|
+
this.env.deps,
|
|
182
|
+
lazyRelations,
|
|
183
|
+
lazyRelationOptions,
|
|
184
|
+
this.entityConstructor,
|
|
185
|
+
includeTree
|
|
186
|
+
) as SelectQueryBuilder<TNext, TTable>;
|
|
187
|
+
}
|
|
186
188
|
|
|
187
189
|
/**
|
|
188
190
|
* Applies an alias to the root FROM table.
|
|
@@ -562,42 +564,42 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
562
564
|
* qb.include('posts');
|
|
563
565
|
* @example
|
|
564
566
|
* qb.include('posts', { columns: ['id', 'title', 'published'] });
|
|
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
|
-
}
|
|
567
|
+
* @example
|
|
568
|
+
* qb.include('posts', {
|
|
569
|
+
* columns: ['id', 'title'],
|
|
570
|
+
* where: eq(postTable.columns.published, true)
|
|
571
|
+
* });
|
|
572
|
+
* @example
|
|
573
|
+
* qb.include({ posts: { include: { author: true } } });
|
|
574
|
+
*/
|
|
575
|
+
include<K extends keyof TTable['relations'] & string>(
|
|
576
|
+
relationName: K,
|
|
577
|
+
options?: RelationIncludeNodeInput<TTable['relations'][K]>
|
|
578
|
+
): SelectQueryBuilder<T, TTable>;
|
|
579
|
+
include(relations: RelationIncludeInput<TTable>): SelectQueryBuilder<T, TTable>;
|
|
580
|
+
include<K extends keyof TTable['relations'] & string>(
|
|
581
|
+
relationNameOrRelations: K | RelationIncludeInput<TTable>,
|
|
582
|
+
options?: RelationIncludeNodeInput<TTable['relations'][K]>
|
|
583
|
+
): SelectQueryBuilder<T, TTable> {
|
|
584
|
+
if (typeof relationNameOrRelations === 'object' && relationNameOrRelations !== null) {
|
|
585
|
+
const normalized = normalizeRelationInclude(relationNameOrRelations as RelationIncludeInput<TableDef>);
|
|
586
|
+
let nextContext = this.context;
|
|
587
|
+
for (const [relationName, node] of Object.entries(normalized)) {
|
|
588
|
+
nextContext = this.relationFacet.include(nextContext, relationName, node.options);
|
|
589
|
+
}
|
|
590
|
+
const nextTree = mergeRelationIncludeTrees(this.includeTree, normalized);
|
|
591
|
+
return this.clone(nextContext, undefined, undefined, nextTree);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const relationName = relationNameOrRelations as string;
|
|
595
|
+
const normalizedNode = normalizeRelationIncludeNode(options);
|
|
596
|
+
const nextContext = this.relationFacet.include(this.context, relationName, normalizedNode.options);
|
|
597
|
+
const shouldStore = Boolean(normalizedNode.include || normalizedNode.options);
|
|
598
|
+
const nextTree = shouldStore
|
|
599
|
+
? mergeRelationIncludeTrees(this.includeTree, { [relationName]: normalizedNode })
|
|
600
|
+
: this.includeTree;
|
|
601
|
+
return this.clone(nextContext, undefined, undefined, nextTree);
|
|
602
|
+
}
|
|
601
603
|
|
|
602
604
|
/**
|
|
603
605
|
* Includes a relation lazily in the query results
|
|
@@ -645,13 +647,13 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
645
647
|
* @example
|
|
646
648
|
* qb.includePick('posts', ['id', 'title', 'createdAt']);
|
|
647
649
|
*/
|
|
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
|
-
}
|
|
650
|
+
includePick<
|
|
651
|
+
K extends keyof TTable['relations'] & string,
|
|
652
|
+
C extends RelationTargetColumns<TTable['relations'][K]>
|
|
653
|
+
>(relationName: K, cols: C[]): SelectQueryBuilder<T, TTable> {
|
|
654
|
+
const options = { columns: cols as readonly C[] } as unknown as RelationIncludeNodeInput<TTable['relations'][K]>;
|
|
655
|
+
return this.include(relationName, options);
|
|
656
|
+
}
|
|
655
657
|
|
|
656
658
|
/**
|
|
657
659
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -668,13 +670,13 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
668
670
|
let currBuilder: SelectQueryBuilder<T, TTable> = this;
|
|
669
671
|
|
|
670
672
|
for (const entry of config) {
|
|
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
|
-
}
|
|
673
|
+
if (entry.type === 'root') {
|
|
674
|
+
currBuilder = currBuilder.select(...entry.columns);
|
|
675
|
+
} else {
|
|
676
|
+
const options = { columns: entry.columns } as unknown as RelationIncludeNodeInput<TTable['relations'][typeof entry.relationName]>;
|
|
677
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
678
680
|
|
|
679
681
|
return currBuilder;
|
|
680
682
|
}
|
|
@@ -691,16 +693,16 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
691
693
|
* Gets lazy relation include options
|
|
692
694
|
* @returns Map of relation names to include options
|
|
693
695
|
*/
|
|
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
|
-
}
|
|
696
|
+
getLazyRelationOptions(): Map<string, RelationIncludeOptions> {
|
|
697
|
+
return new Map(this.lazyRelationOptions);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Gets normalized nested include information for runtime preloading.
|
|
702
|
+
*/
|
|
703
|
+
getIncludeTree(): NormalizedRelationIncludeTree {
|
|
704
|
+
return cloneRelationIncludeTree(this.includeTree);
|
|
705
|
+
}
|
|
704
706
|
|
|
705
707
|
/**
|
|
706
708
|
* Gets the table definition for this query builder
|
|
@@ -796,14 +798,14 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
796
798
|
* Executes the query and returns both the paged items and the total.
|
|
797
799
|
*
|
|
798
800
|
* @example
|
|
799
|
-
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
801
|
+
* const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
800
802
|
*/
|
|
801
803
|
async executePaged(
|
|
802
804
|
session: OrmSession,
|
|
803
805
|
options: { page: number; pageSize: number }
|
|
804
|
-
): Promise<
|
|
806
|
+
): Promise<PaginatedResult<T>> {
|
|
805
807
|
const builder = this.ensureDefaultSelection();
|
|
806
|
-
return executePagedQuery(builder, session, options, sess =>
|
|
808
|
+
return executePagedQuery(builder, session, options, sess => builder.count(sess));
|
|
807
809
|
}
|
|
808
810
|
|
|
809
811
|
/**
|