metal-orm 1.0.76 → 1.0.78
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 +2 -2
- 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 +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/inflection/compound.mjs +14 -0
- package/scripts/inflection/pt-br.mjs +63 -9
- package/src/query-builder/select/select-operations.ts +122 -115
- package/src/query-builder/select.ts +23 -21
package/package.json
CHANGED
|
@@ -70,3 +70,17 @@ export const applyToCompoundHead = (term, { connectors, transformWord } = {}) =>
|
|
|
70
70
|
return rebuildFromWords(out, format, original);
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
export const applyToCompoundWords = (term, { connectors, transformWord } = {}) => {
|
|
74
|
+
if (!term || !String(term).trim()) return '';
|
|
75
|
+
const original = String(term).trim();
|
|
76
|
+
const format = detectTextFormat(original);
|
|
77
|
+
const words = splitIntoWords(original, format);
|
|
78
|
+
|
|
79
|
+
const out = words.map(word => {
|
|
80
|
+
const normalized = normalizeLookup(word);
|
|
81
|
+
if (connectors?.has?.(normalized)) return word;
|
|
82
|
+
return transformWord ? transformWord(word) : word;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return rebuildFromWords(out, format, original);
|
|
86
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyToCompoundHead,
|
|
3
|
+
applyToCompoundWords,
|
|
4
|
+
detectTextFormat,
|
|
3
5
|
normalizeLookup,
|
|
6
|
+
splitIntoWords,
|
|
4
7
|
stripDiacritics
|
|
5
8
|
} from './compound.mjs';
|
|
6
9
|
|
|
@@ -172,6 +175,14 @@ export const PT_BR_CONNECTORS = Object.freeze(new Set(
|
|
|
172
175
|
].map(normalizeLookup)
|
|
173
176
|
));
|
|
174
177
|
|
|
178
|
+
const hasConnectorWord = (term, connectors) => {
|
|
179
|
+
if (!term || !String(term).trim()) return false;
|
|
180
|
+
const original = String(term).trim();
|
|
181
|
+
const format = detectTextFormat(original);
|
|
182
|
+
const words = splitIntoWords(original, format);
|
|
183
|
+
return words.some(word => connectors?.has?.(normalizeLookup(word)));
|
|
184
|
+
};
|
|
185
|
+
|
|
175
186
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
176
187
|
// INFLECTION RULES
|
|
177
188
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -338,6 +349,36 @@ export const singularizeWordPtBr = (
|
|
|
338
349
|
return normalized;
|
|
339
350
|
};
|
|
340
351
|
|
|
352
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
353
|
+
// NOUN SPECIFIERS (SUBSTANTIVOS DETERMINANTES)
|
|
354
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Portuguese words that act as specifiers/delimiters in compound nouns.
|
|
358
|
+
* When these appear as the second term, only the first term varies.
|
|
359
|
+
* @type {ReadonlySet<string>}
|
|
360
|
+
*/
|
|
361
|
+
export const PT_BR_NOUN_SPECIFIERS = Object.freeze(new Set(
|
|
362
|
+
[
|
|
363
|
+
'correcao', 'padrao', 'limite', 'chave', 'base', 'chefe',
|
|
364
|
+
'satelite', 'fantasma', 'monstro', 'escola', 'piloto',
|
|
365
|
+
'femea', 'macho', 'geral', 'solicitacao'
|
|
366
|
+
].map(normalizeLookup)
|
|
367
|
+
));
|
|
368
|
+
|
|
369
|
+
const isCompoundWithSpecifier = (term, specifiers = PT_BR_NOUN_SPECIFIERS) => {
|
|
370
|
+
if (!term || !String(term).trim()) return false;
|
|
371
|
+
const original = String(term).trim();
|
|
372
|
+
const format = detectTextFormat(original);
|
|
373
|
+
const words = splitIntoWords(original, format);
|
|
374
|
+
|
|
375
|
+
if (words.length < 2) return false;
|
|
376
|
+
|
|
377
|
+
// Check if the last word is a known specifier
|
|
378
|
+
const lastWord = words[words.length - 1];
|
|
379
|
+
return specifiers.has(normalizeLookup(lastWord));
|
|
380
|
+
};
|
|
381
|
+
|
|
341
382
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
342
383
|
// COMPOUND TERM HANDLING
|
|
343
384
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -347,16 +388,26 @@ export const singularizeWordPtBr = (
|
|
|
347
388
|
*/
|
|
348
389
|
export const pluralizeRelationPropertyPtBr = (
|
|
349
390
|
term,
|
|
350
|
-
{ pluralizeWord = pluralizeWordPtBr, connectors = PT_BR_CONNECTORS } = {}
|
|
351
|
-
) =>
|
|
391
|
+
{ pluralizeWord = pluralizeWordPtBr, connectors = PT_BR_CONNECTORS, specifiers = PT_BR_NOUN_SPECIFIERS } = {}
|
|
392
|
+
) => {
|
|
393
|
+
if (hasConnectorWord(term, connectors) || isCompoundWithSpecifier(term, specifiers)) {
|
|
394
|
+
return applyToCompoundHead(term, { connectors, transformWord: pluralizeWord });
|
|
395
|
+
}
|
|
396
|
+
return applyToCompoundWords(term, { connectors, transformWord: pluralizeWord });
|
|
397
|
+
}
|
|
352
398
|
|
|
353
399
|
/**
|
|
354
400
|
* Singularizes a compound property/relation name in Portuguese.
|
|
355
401
|
*/
|
|
356
402
|
export const singularizeRelationPropertyPtBr = (
|
|
357
403
|
term,
|
|
358
|
-
{ singularizeWord = singularizeWordPtBr, connectors = PT_BR_CONNECTORS } = {}
|
|
359
|
-
) =>
|
|
404
|
+
{ singularizeWord = singularizeWordPtBr, connectors = PT_BR_CONNECTORS, specifiers = PT_BR_NOUN_SPECIFIERS } = {}
|
|
405
|
+
) => {
|
|
406
|
+
if (hasConnectorWord(term, connectors) || isCompoundWithSpecifier(term, specifiers)) {
|
|
407
|
+
return applyToCompoundHead(term, { connectors, transformWord: singularizeWord });
|
|
408
|
+
}
|
|
409
|
+
return applyToCompoundWords(term, { connectors, transformWord: singularizeWord });
|
|
410
|
+
}
|
|
360
411
|
|
|
361
412
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
362
413
|
// INFLECTOR FACTORY
|
|
@@ -376,16 +427,19 @@ export const createPtBrInflector = ({ customIrregulars = {} } = {}) => {
|
|
|
376
427
|
...buildSingularIrregulars(customIrregulars)
|
|
377
428
|
});
|
|
378
429
|
|
|
430
|
+
const pluralizeWord = (w) => pluralizeWordPtBr(w, irregularPlurals);
|
|
431
|
+
const singularizeWord = (w) => singularizeWordPtBr(w, irregularSingulars);
|
|
432
|
+
|
|
379
433
|
return Object.freeze({
|
|
380
434
|
locale: 'pt-BR',
|
|
381
435
|
irregularPlurals,
|
|
382
436
|
irregularSingulars,
|
|
383
|
-
pluralizeWord
|
|
384
|
-
singularizeWord
|
|
385
|
-
pluralizeRelationProperty: pluralizeRelationPropertyPtBr,
|
|
386
|
-
singularizeRelationProperty: singularizeRelationPropertyPtBr,
|
|
437
|
+
pluralizeWord,
|
|
438
|
+
singularizeWord,
|
|
439
|
+
pluralizeRelationProperty: (term) => pluralizeRelationPropertyPtBr(term, { pluralizeWord }),
|
|
440
|
+
singularizeRelationProperty: (term) => singularizeRelationPropertyPtBr(term, { singularizeWord }),
|
|
387
441
|
normalizeForLookup: normalizeWord
|
|
388
442
|
});
|
|
389
443
|
};
|
|
390
444
|
|
|
391
|
-
export default createPtBrInflector;
|
|
445
|
+
export default createPtBrInflector;
|
|
@@ -1,79 +1,86 @@
|
|
|
1
|
-
import { TableDef } from '../../schema/table.js';
|
|
2
|
-
import { ColumnDef } from '../../schema/column-types.js';
|
|
3
|
-
import { OrderingTerm, SelectQueryNode } from '../../core/ast/query.js';
|
|
4
|
-
import { FunctionNode, ExpressionNode, exists, notExists } from '../../core/ast/expression.js';
|
|
5
|
-
import { derivedTable } from '../../core/ast/builders.js';
|
|
6
|
-
import { SelectQueryState } from '../select-query-state.js';
|
|
7
|
-
import { SelectQueryBuilderContext, SelectQueryBuilderEnvironment } from '../select-query-builder-deps.js';
|
|
8
|
-
import { SelectPredicateFacet } from './predicate-facet.js';
|
|
9
|
-
import { SelectRelationFacet } from './relation-facet.js';
|
|
10
|
-
import { ORDER_DIRECTIONS, OrderDirection } from '../../core/sql/sql.js';
|
|
11
|
-
import { OrmSession } from '../../orm/orm-session.js';
|
|
12
|
-
import type { SelectQueryBuilder } from '../select.js';
|
|
13
|
-
|
|
14
|
-
export type WhereHasOptions = {
|
|
15
|
-
correlate?: ExpressionNode;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type RelationCallback = <TChildTable extends TableDef>(
|
|
19
|
-
qb: SelectQueryBuilder<unknown, TChildTable>
|
|
20
|
-
) => SelectQueryBuilder<unknown, TChildTable>;
|
|
21
|
-
|
|
22
|
-
type ChildBuilderFactory = <R, TChild extends TableDef>(table: TChild) => SelectQueryBuilder<R, TChild>;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Builds a new query context with an ORDER BY clause applied.
|
|
26
|
-
*/
|
|
27
|
-
export function applyOrderBy(
|
|
28
|
-
context: SelectQueryBuilderContext,
|
|
29
|
-
predicateFacet: SelectPredicateFacet,
|
|
30
|
-
term: ColumnDef | OrderingTerm,
|
|
31
|
-
directionOrOptions: OrderDirection | { direction?: OrderDirection; nulls?: 'FIRST' | 'LAST'; collation?: string }
|
|
32
|
-
): SelectQueryBuilderContext {
|
|
33
|
-
const options =
|
|
34
|
-
typeof directionOrOptions === 'string' ? { direction: directionOrOptions } : directionOrOptions;
|
|
35
|
-
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
36
|
-
return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
|
|
1
|
+
import { TableDef } from '../../schema/table.js';
|
|
2
|
+
import { ColumnDef } from '../../schema/column-types.js';
|
|
3
|
+
import { OrderingTerm, SelectQueryNode } from '../../core/ast/query.js';
|
|
4
|
+
import { FunctionNode, ExpressionNode, exists, notExists } from '../../core/ast/expression.js';
|
|
5
|
+
import { derivedTable } from '../../core/ast/builders.js';
|
|
6
|
+
import { SelectQueryState } from '../select-query-state.js';
|
|
7
|
+
import { SelectQueryBuilderContext, SelectQueryBuilderEnvironment } from '../select-query-builder-deps.js';
|
|
8
|
+
import { SelectPredicateFacet } from './predicate-facet.js';
|
|
9
|
+
import { SelectRelationFacet } from './relation-facet.js';
|
|
10
|
+
import { ORDER_DIRECTIONS, OrderDirection } from '../../core/sql/sql.js';
|
|
11
|
+
import { OrmSession } from '../../orm/orm-session.js';
|
|
12
|
+
import type { SelectQueryBuilder } from '../select.js';
|
|
13
|
+
|
|
14
|
+
export type WhereHasOptions = {
|
|
15
|
+
correlate?: ExpressionNode;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type RelationCallback = <TChildTable extends TableDef>(
|
|
19
|
+
qb: SelectQueryBuilder<unknown, TChildTable>
|
|
20
|
+
) => SelectQueryBuilder<unknown, TChildTable>;
|
|
21
|
+
|
|
22
|
+
type ChildBuilderFactory = <R, TChild extends TableDef>(table: TChild) => SelectQueryBuilder<R, TChild>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Builds a new query context with an ORDER BY clause applied.
|
|
26
|
+
*/
|
|
27
|
+
export function applyOrderBy(
|
|
28
|
+
context: SelectQueryBuilderContext,
|
|
29
|
+
predicateFacet: SelectPredicateFacet,
|
|
30
|
+
term: ColumnDef | OrderingTerm,
|
|
31
|
+
directionOrOptions: OrderDirection | { direction?: OrderDirection; nulls?: 'FIRST' | 'LAST'; collation?: string }
|
|
32
|
+
): SelectQueryBuilderContext {
|
|
33
|
+
const options =
|
|
34
|
+
typeof directionOrOptions === 'string' ? { direction: directionOrOptions } : directionOrOptions;
|
|
35
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
36
|
+
return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Runs the count query for the provided context and session.
|
|
41
|
+
*/
|
|
42
|
+
export async function executeCount(
|
|
43
|
+
context: SelectQueryBuilderContext,
|
|
44
|
+
env: SelectQueryBuilderEnvironment,
|
|
45
|
+
session: OrmSession
|
|
46
|
+
): Promise<number> {
|
|
47
|
+
const unpagedAst: SelectQueryNode = {
|
|
48
|
+
...context.state.ast,
|
|
49
|
+
orderBy: undefined,
|
|
50
|
+
limit: undefined,
|
|
51
|
+
offset: undefined
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const nextState = new SelectQueryState(env.table as TableDef, unpagedAst);
|
|
55
|
+
const nextContext: SelectQueryBuilderContext = {
|
|
56
|
+
...context,
|
|
57
|
+
state: nextState
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const subAst = nextContext.hydration.applyToAst(nextState.ast);
|
|
61
|
+
const countQuery: SelectQueryNode = {
|
|
62
|
+
type: 'SelectQuery',
|
|
63
|
+
from: derivedTable(subAst, '__metal_count'),
|
|
64
|
+
columns: [{ type: 'Function', name: 'COUNT', args: [], alias: 'total' } as FunctionNode],
|
|
65
|
+
joins: []
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const execCtx = session.getExecutionContext();
|
|
69
|
+
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
70
|
+
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
71
|
+
const value = results[0]?.values?.[0]?.[0];
|
|
72
|
+
|
|
73
|
+
if (typeof value === 'number') return value;
|
|
74
|
+
if (typeof value === 'bigint') return Number(value);
|
|
75
|
+
if (typeof value === 'string') return Number(value);
|
|
76
|
+
return value === null || value === undefined ? 0 : Number(value);
|
|
37
77
|
}
|
|
38
78
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
env: SelectQueryBuilderEnvironment,
|
|
45
|
-
session: OrmSession
|
|
46
|
-
): Promise<number> {
|
|
47
|
-
const unpagedAst: SelectQueryNode = {
|
|
48
|
-
...context.state.ast,
|
|
49
|
-
orderBy: undefined,
|
|
50
|
-
limit: undefined,
|
|
51
|
-
offset: undefined
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const nextState = new SelectQueryState(env.table as TableDef, unpagedAst);
|
|
55
|
-
const nextContext: SelectQueryBuilderContext = {
|
|
56
|
-
...context,
|
|
57
|
-
state: nextState
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const subAst = nextContext.hydration.applyToAst(nextState.ast);
|
|
61
|
-
const countQuery: SelectQueryNode = {
|
|
62
|
-
type: 'SelectQuery',
|
|
63
|
-
from: derivedTable(subAst, '__metal_count'),
|
|
64
|
-
columns: [{ type: 'Function', name: 'COUNT', args: [], alias: 'total' } as FunctionNode],
|
|
65
|
-
joins: []
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const execCtx = session.getExecutionContext();
|
|
69
|
-
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
70
|
-
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
71
|
-
const value = results[0]?.values?.[0]?.[0];
|
|
72
|
-
|
|
73
|
-
if (typeof value === 'number') return value;
|
|
74
|
-
if (typeof value === 'bigint') return Number(value);
|
|
75
|
-
if (typeof value === 'string') return Number(value);
|
|
76
|
-
return value === null || value === undefined ? 0 : Number(value);
|
|
79
|
+
export interface PaginatedResult<T> {
|
|
80
|
+
items: T[];
|
|
81
|
+
totalItems: number;
|
|
82
|
+
page: number;
|
|
83
|
+
pageSize: number;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
/**
|
|
@@ -84,7 +91,7 @@ export async function executePagedQuery<T, TTable extends TableDef>(
|
|
|
84
91
|
session: OrmSession,
|
|
85
92
|
options: { page: number; pageSize: number },
|
|
86
93
|
countCallback: (session: OrmSession) => Promise<number>
|
|
87
|
-
): Promise<
|
|
94
|
+
): Promise<PaginatedResult<T>> {
|
|
88
95
|
const { page, pageSize } = options;
|
|
89
96
|
|
|
90
97
|
if (!Number.isInteger(page) || page < 1) {
|
|
@@ -101,44 +108,44 @@ export async function executePagedQuery<T, TTable extends TableDef>(
|
|
|
101
108
|
countCallback(session)
|
|
102
109
|
]);
|
|
103
110
|
|
|
104
|
-
return { items, totalItems };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Builds an EXISTS or NOT EXISTS predicate for a related table.
|
|
109
|
-
*/
|
|
110
|
-
export function buildWhereHasPredicate<TTable extends TableDef>(
|
|
111
|
-
env: SelectQueryBuilderEnvironment,
|
|
112
|
-
context: SelectQueryBuilderContext,
|
|
113
|
-
relationFacet: SelectRelationFacet,
|
|
114
|
-
createChildBuilder: ChildBuilderFactory,
|
|
115
|
-
relationName: keyof TTable['relations'] & string,
|
|
116
|
-
callbackOrOptions?: RelationCallback | WhereHasOptions,
|
|
117
|
-
maybeOptions?: WhereHasOptions,
|
|
118
|
-
negate = false
|
|
119
|
-
): ExpressionNode {
|
|
120
|
-
const relation = env.table.relations[relationName as string];
|
|
121
|
-
if (!relation) {
|
|
122
|
-
throw new Error(`Relation '${relationName}' not found on table '${env.table.name}'`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const callback = typeof callbackOrOptions === 'function' ? callbackOrOptions : undefined;
|
|
126
|
-
const options = (typeof callbackOrOptions === 'function' ? maybeOptions : callbackOrOptions) as
|
|
127
|
-
| WhereHasOptions
|
|
128
|
-
| undefined;
|
|
129
|
-
|
|
130
|
-
let subQb = createChildBuilder<unknown, TableDef>(relation.target);
|
|
131
|
-
if (callback) {
|
|
132
|
-
subQb = callback(subQb);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const subAst = subQb.getAST();
|
|
136
|
-
const finalSubAst = relationFacet.applyRelationCorrelation(
|
|
137
|
-
context,
|
|
138
|
-
relationName,
|
|
139
|
-
subAst,
|
|
140
|
-
options?.correlate
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
111
|
+
return { items, totalItems, page, pageSize };
|
|
144
112
|
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Builds an EXISTS or NOT EXISTS predicate for a related table.
|
|
116
|
+
*/
|
|
117
|
+
export function buildWhereHasPredicate<TTable extends TableDef>(
|
|
118
|
+
env: SelectQueryBuilderEnvironment,
|
|
119
|
+
context: SelectQueryBuilderContext,
|
|
120
|
+
relationFacet: SelectRelationFacet,
|
|
121
|
+
createChildBuilder: ChildBuilderFactory,
|
|
122
|
+
relationName: keyof TTable['relations'] & string,
|
|
123
|
+
callbackOrOptions?: RelationCallback | WhereHasOptions,
|
|
124
|
+
maybeOptions?: WhereHasOptions,
|
|
125
|
+
negate = false
|
|
126
|
+
): ExpressionNode {
|
|
127
|
+
const relation = env.table.relations[relationName as string];
|
|
128
|
+
if (!relation) {
|
|
129
|
+
throw new Error(`Relation '${relationName}' not found on table '${env.table.name}'`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const callback = typeof callbackOrOptions === 'function' ? callbackOrOptions : undefined;
|
|
133
|
+
const options = (typeof callbackOrOptions === 'function' ? maybeOptions : callbackOrOptions) as
|
|
134
|
+
| WhereHasOptions
|
|
135
|
+
| undefined;
|
|
136
|
+
|
|
137
|
+
let subQb = createChildBuilder<unknown, TableDef>(relation.target);
|
|
138
|
+
if (callback) {
|
|
139
|
+
subQb = callback(subQb);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const subAst = subQb.getAST();
|
|
143
|
+
const finalSubAst = relationFacet.applyRelationCorrelation(
|
|
144
|
+
context,
|
|
145
|
+
relationName,
|
|
146
|
+
subAst,
|
|
147
|
+
options?.correlate
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
151
|
+
}
|
|
@@ -50,14 +50,16 @@ import { executeHydrated, executeHydratedPlain, executeHydratedWithContexts } fr
|
|
|
50
50
|
import { EntityConstructor } from '../orm/entity-metadata.js';
|
|
51
51
|
import { materializeAs } from '../orm/entity-materializer.js';
|
|
52
52
|
import { resolveSelectQuery } from './query-resolution.js';
|
|
53
|
-
import {
|
|
54
|
-
applyOrderBy,
|
|
55
|
-
buildWhereHasPredicate,
|
|
56
|
-
executeCount,
|
|
57
|
-
executePagedQuery,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
import {
|
|
54
|
+
applyOrderBy,
|
|
55
|
+
buildWhereHasPredicate,
|
|
56
|
+
executeCount,
|
|
57
|
+
executePagedQuery,
|
|
58
|
+
PaginatedResult,
|
|
59
|
+
RelationCallback,
|
|
60
|
+
WhereHasOptions
|
|
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';
|
|
@@ -792,19 +794,19 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
792
794
|
return executeCount(this.context, this.env, session);
|
|
793
795
|
}
|
|
794
796
|
|
|
795
|
-
/**
|
|
796
|
-
* Executes the query and returns both the paged items and the total.
|
|
797
|
-
*
|
|
798
|
-
* @example
|
|
799
|
-
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
800
|
-
*/
|
|
801
|
-
async executePaged(
|
|
802
|
-
session: OrmSession,
|
|
803
|
-
options: { page: number; pageSize: number }
|
|
804
|
-
): Promise<
|
|
805
|
-
const builder = this.ensureDefaultSelection();
|
|
806
|
-
return executePagedQuery(builder, session, options, sess => this.count(sess));
|
|
807
|
-
}
|
|
797
|
+
/**
|
|
798
|
+
* Executes the query and returns both the paged items and the total.
|
|
799
|
+
*
|
|
800
|
+
* @example
|
|
801
|
+
* const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
802
|
+
*/
|
|
803
|
+
async executePaged(
|
|
804
|
+
session: OrmSession,
|
|
805
|
+
options: { page: number; pageSize: number }
|
|
806
|
+
): Promise<PaginatedResult<T>> {
|
|
807
|
+
const builder = this.ensureDefaultSelection();
|
|
808
|
+
return executePagedQuery(builder, session, options, sess => this.count(sess));
|
|
809
|
+
}
|
|
808
810
|
|
|
809
811
|
/**
|
|
810
812
|
* Executes the query with provided execution and hydration contexts
|