typeorm-extensions 2.2.0-rc.8 → 2.2.0-rc.9
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/README.md +0 -8
- package/dist/extensions/calculated-column.extension.d.ts +3 -3
- package/dist/extensions/calculated-column.extension.js +3 -16
- package/dist/extensions/cursor-pagination.extension.js +3 -11
- package/dist/extensions/get-many-with-totals.extension.js +4 -20
- package/dist/extensions/join-lateral.extension.js +4 -6
- package/dist/extensions/period-filter.extension.js +1 -11
- package/dist/extensions/typed/index.d.ts +1 -0
- package/dist/extensions/typed/index.js +1 -0
- package/dist/extensions/typed/typed-calculated/typed-calculated-column.extension.d.ts +25 -0
- package/dist/extensions/typed/typed-calculated/typed-calculated-column.extension.js +24 -0
- package/dist/extensions/typed/typed-having/typed-having.extension.js +1 -1
- package/dist/extensions/typed/typed-joins/typed-join-and-map.extension.js +11 -10
- package/dist/extensions/typed/typed-joins/typed-joins.extension.js +11 -22
- package/dist/extensions/typed/typed-order-by/typed-order-by.extension.js +11 -17
- package/dist/extensions/typed/typed-returning/typed-returning.extension.js +1 -9
- package/dist/extensions/typed/typed-select/typed-select.extension.js +2 -8
- package/dist/extensions/typed/typed-where/typed-period-filter.extension.js +1 -11
- package/dist/extensions/typed/typed-where/typed-where-array.extension.js +4 -18
- package/dist/extensions/typed/typed-where/typed-where-ilike.extension.js +1 -11
- package/dist/extensions/typed/typed-where/typed-where-is-any.extension.js +3 -22
- package/dist/extensions/typed/typed-where/typed-where-is-distinct-from.extension.js +3 -22
- package/dist/extensions/typed/typed-where/typed-where-is-in.extension.js +3 -23
- package/dist/extensions/typed/typed-where/typed-where-json.extension.js +4 -23
- package/dist/extensions/typed/typed-where/typed-where-lower.extension.js +1 -11
- package/dist/extensions/typed/typed-where/typed-where-similar.extension.js +1 -10
- package/dist/extensions/typed/typed-where/typed-where.extension.js +2 -12
- package/dist/extensions/union.extension.js +1 -1
- package/dist/extensions/where-array.extension.js +1 -11
- package/dist/extensions/where-exists.extension.js +4 -15
- package/dist/extensions/where-is-any.extension.d.ts +38 -160
- package/dist/extensions/where-is-any.extension.js +1 -11
- package/dist/extensions/where-is-distinct-from.extension.js +1 -11
- package/dist/extensions/where-is-in.extension.d.ts +35 -145
- package/dist/extensions/where-is-in.extension.js +11 -29
- package/dist/extensions/where-json.extension.js +1 -11
- package/dist/extensions/where-relation-exists.extension.js +5 -25
- package/dist/index.d.ts +1 -6
- package/dist/index.js +1 -12
- package/dist/utils/calculated-column.utils.d.ts +8 -0
- package/dist/utils/calculated-column.utils.js +20 -3
- package/dist/utils/common.utils.d.ts +2 -0
- package/dist/utils/common.utils.js +4 -1
- package/dist/utils/cursor.utils.js +4 -6
- package/dist/utils/json-path.utils.js +2 -2
- package/dist/utils/pagination.utils.d.ts +5 -0
- package/dist/utils/pagination.utils.js +20 -10
- package/dist/utils/parameter.utils.d.ts +10 -0
- package/dist/utils/parameter.utils.js +22 -1
- package/dist/utils/period.utils.js +2 -1
- package/dist/utils/prototype.utils.d.ts +9 -0
- package/dist/utils/prototype.utils.js +12 -2
- package/dist/utils/query-builder.utils.d.ts +22 -2
- package/dist/utils/query-builder.utils.js +67 -44
- package/dist/utils/table.utils.js +9 -11
- package/dist/utils/time-zone.utils.d.ts +8 -0
- package/dist/utils/time-zone.utils.js +15 -5
- package/dist/utils/typed-where.utils.d.ts +9 -0
- package/dist/utils/typed-where.utils.js +17 -0
- package/dist/utils/where.utils.d.ts +2 -0
- package/dist/utils/where.utils.js +12 -14
- package/package.json +1 -1
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { DeleteQueryBuilder, SelectQueryBuilder, UpdateQueryBuilder } from 'typeorm';
|
|
2
|
+
import { SoftDeleteQueryBuilder } from 'typeorm/query-builder/SoftDeleteQueryBuilder';
|
|
1
3
|
export type PatchPrototypeOptions = {
|
|
2
4
|
/** Leave a method the target already has, own or inherited: TypeORM's, or another library's. */
|
|
3
5
|
onlyMissing?: boolean;
|
|
4
6
|
};
|
|
7
|
+
/** The query builders with a WHERE clause, which the where extensions patch. */
|
|
8
|
+
export declare const WHERE_QUERY_BUILDERS: (typeof SelectQueryBuilder | typeof UpdateQueryBuilder | typeof DeleteQueryBuilder | typeof SoftDeleteQueryBuilder)[];
|
|
5
9
|
export declare function patchPrototype<T extends {
|
|
6
10
|
prototype: any;
|
|
7
11
|
}, S extends {
|
|
8
12
|
prototype: any;
|
|
9
13
|
}>(target: T, source: S, options?: PatchPrototypeOptions): void;
|
|
14
|
+
export declare function patchPrototypes<S extends {
|
|
15
|
+
prototype: any;
|
|
16
|
+
}>(targets: ReadonlyArray<{
|
|
17
|
+
prototype: any;
|
|
18
|
+
}>, source: S, options?: PatchPrototypeOptions): void;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.patchPrototype = void 0;
|
|
3
|
+
exports.patchPrototypes = exports.patchPrototype = exports.WHERE_QUERY_BUILDERS = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const SoftDeleteQueryBuilder_1 = require("typeorm/query-builder/SoftDeleteQueryBuilder");
|
|
7
|
+
/** The query builders with a WHERE clause, which the where extensions patch. */
|
|
8
|
+
exports.WHERE_QUERY_BUILDERS = [typeorm_1.SelectQueryBuilder, typeorm_1.UpdateQueryBuilder, typeorm_1.DeleteQueryBuilder, SoftDeleteQueryBuilder_1.SoftDeleteQueryBuilder];
|
|
5
9
|
function patchPrototype(target, source, options = {}) {
|
|
6
10
|
for (const method of Object.keys(source.prototype)) {
|
|
7
11
|
if (options.onlyMissing && method in target.prototype) {
|
|
@@ -11,3 +15,9 @@ function patchPrototype(target, source, options = {}) {
|
|
|
11
15
|
}
|
|
12
16
|
}
|
|
13
17
|
exports.patchPrototype = patchPrototype;
|
|
18
|
+
function patchPrototypes(targets, source, options) {
|
|
19
|
+
for (const target of targets) {
|
|
20
|
+
patchPrototype(target, source, options);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.patchPrototypes = patchPrototypes;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { QueryBuilder } from 'typeorm';
|
|
2
|
-
import type { ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
|
|
2
|
+
import type { ObjectLiteral, QueryRunner, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm';
|
|
3
3
|
import type { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata';
|
|
4
|
+
import type { Alias } from 'typeorm/query-builder/Alias';
|
|
4
5
|
import type { KeyProxyCallback } from '../types/modules/proxy-callback.types';
|
|
5
6
|
import type { OrderType } from '../types/interfaces/ordering.interface';
|
|
7
|
+
import { KeyHolder } from './proxy-key.utils';
|
|
6
8
|
import { JsonPathSqlOptions } from './json-path.utils';
|
|
9
|
+
/**
|
|
10
|
+
* The aliases of the query and of the queries it is part of, its own first. The builder of a `Brackets` callback
|
|
11
|
+
* has the outer query's main alias but an empty alias list: the aliases, joins included, are on its parent. A
|
|
12
|
+
* subquery sees the aliases of the outer query too.
|
|
13
|
+
*/
|
|
14
|
+
export declare function listQueryAliases(builder: WhereExpressionBuilder | QueryBuilder<ObjectLiteral>): Alias[];
|
|
7
15
|
/** Replaces placeholders of `deferColumnKey` in SQL built by `builder`, through the aliases it has by then. */
|
|
8
16
|
export declare function resolveDeferredKeys(builder: WhereExpressionBuilder, statement: string): string;
|
|
9
17
|
/**
|
|
@@ -50,6 +58,14 @@ export declare function isTypedJsonPath<Type extends ObjectLiteral>(builder: Whe
|
|
|
50
58
|
* one condition per column has no single obvious meaning (AND? OR?), so don't guess.
|
|
51
59
|
*/
|
|
52
60
|
export declare function getTypedSingleColumnKey<Type extends ObjectLiteral>(builder: WhereExpressionBuilder, callback: KeyProxyCallback<Type>, methodName: string, jsonOptions?: JsonPathSqlOptions): string;
|
|
61
|
+
/**
|
|
62
|
+
* The alias and the entity property a typed callback picks, for methods that take a property rather than a column
|
|
63
|
+
* (a `@CalculatedColumn`): `u => u.imagesCount` is on the main alias, `q => q.owner.imagesCount` on `owner`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveTypedProperty<Type extends ObjectLiteral>(builder: WhereExpressionBuilder, callback: KeyProxyCallback<Type>, methodName: string): {
|
|
66
|
+
aliasName: string | undefined;
|
|
67
|
+
propertyPath: string;
|
|
68
|
+
};
|
|
53
69
|
/**
|
|
54
70
|
* Key for typed select / order / distinct / group by on a SelectQueryBuilder.
|
|
55
71
|
*
|
|
@@ -61,10 +77,14 @@ export declare function getTypedSingleColumnKey<Type extends ObjectLiteral>(buil
|
|
|
61
77
|
* PostgreSQL folds an unquoted `cte.firstName` to `firstname`.
|
|
62
78
|
* Strings are kept as is.
|
|
63
79
|
*/
|
|
64
|
-
export declare function getTypedSelectionKey<Type extends ObjectLiteral>(builder: WhereExpressionBuilder, selection: KeyProxyCallback<Type> | string, useQuotes?: boolean, columnsFor?: string): string | string[];
|
|
80
|
+
export declare function getTypedSelectionKey<Type extends ObjectLiteral>(builder: WhereExpressionBuilder, selection: KeyProxyCallback<Type> | KeyHolder | string, useQuotes?: boolean, columnsFor?: string): string | string[];
|
|
65
81
|
/**
|
|
66
82
|
* The ORDER BY a query is built with, in the order it was applied. `allOrderBys`, not `orderBys`: it is what the SQL
|
|
67
83
|
* is built from, so without an explicit order it falls back to the `orderBy` of @Entity, and respects the
|
|
68
84
|
* `disable-global-order` option.
|
|
69
85
|
*/
|
|
70
86
|
export declare function getAppliedOrderBy<Entity extends ObjectLiteral>(builder: QueryBuilder<Entity>): OrderType[];
|
|
87
|
+
/** The query without paging: no ORDER BY (nor the entity's default one), LIMIT, OFFSET, take or skip. */
|
|
88
|
+
export declare function withoutPaging<Entity extends ObjectLiteral>(query: SelectQueryBuilder<Entity>): SelectQueryBuilder<Entity>;
|
|
89
|
+
/** The query runner a builder was created with, from a transactional manager; `undefined` for one from the pool. */
|
|
90
|
+
export declare function getQueryRunner<Entity extends ObjectLiteral>(builder: QueryBuilder<Entity>): QueryRunner | undefined;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAppliedOrderBy = exports.getTypedSelectionKey = exports.getTypedSingleColumnKey = exports.isTypedJsonPath = exports.getTypedColumnKey = exports.toFieldSql = exports.findFieldColumn = exports.getColumnDatabaseName = exports.resolveDeferredKeys = void 0;
|
|
3
|
+
exports.getQueryRunner = exports.withoutPaging = exports.getAppliedOrderBy = exports.getTypedSelectionKey = exports.resolveTypedProperty = exports.getTypedSingleColumnKey = exports.isTypedJsonPath = exports.getTypedColumnKey = exports.toFieldSql = exports.findFieldColumn = exports.getColumnDatabaseName = exports.resolveDeferredKeys = exports.listQueryAliases = void 0;
|
|
4
4
|
const typeorm_1 = require("typeorm");
|
|
5
5
|
const QueryExpressionMap_1 = require("typeorm/query-builder/QueryExpressionMap");
|
|
6
6
|
const proxy_key_utils_1 = require("./proxy-key.utils");
|
|
7
7
|
const json_path_utils_1 = require("./json-path.utils");
|
|
8
8
|
const sql_utils_1 = require("./sql.utils");
|
|
9
|
+
const calculated_column_utils_1 = require("./calculated-column.utils");
|
|
9
10
|
/**
|
|
10
11
|
* Whether single-level typed keys are qualified with the main alias (`user.firstName`).
|
|
11
12
|
*
|
|
@@ -33,21 +34,24 @@ function requireMainAliasName(queryBuilder, key) {
|
|
|
33
34
|
return mainAlias.name;
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
-
* outer query's main alias but an empty alias list: the aliases, joins included, are on its parent. A
|
|
38
|
-
* sees the aliases of the outer query too
|
|
37
|
+
* The aliases of the query and of the queries it is part of, its own first. The builder of a `Brackets` callback
|
|
38
|
+
* has the outer query's main alias but an empty alias list: the aliases, joins included, are on its parent. A
|
|
39
|
+
* subquery sees the aliases of the outer query too.
|
|
39
40
|
*/
|
|
40
|
-
function
|
|
41
|
-
var _a
|
|
41
|
+
function listQueryAliases(builder) {
|
|
42
|
+
var _a;
|
|
43
|
+
const aliases = [];
|
|
42
44
|
// parentQueryBuilder is protected in TypeORM's types
|
|
43
|
-
for (let query =
|
|
44
|
-
const { aliases = [], mainAlias } = (_a = query.expressionMap) !== null && _a !== void 0 ? _a : {};
|
|
45
|
-
|
|
46
|
-
if (alias) {
|
|
47
|
-
return alias;
|
|
48
|
-
}
|
|
45
|
+
for (let query = builder; query; query = query.parentQueryBuilder) {
|
|
46
|
+
const { aliases: own = [], mainAlias } = (_a = query.expressionMap) !== null && _a !== void 0 ? _a : {};
|
|
47
|
+
aliases.push(...own, ...(mainAlias ? [mainAlias] : []));
|
|
49
48
|
}
|
|
50
|
-
return
|
|
49
|
+
return aliases;
|
|
50
|
+
}
|
|
51
|
+
exports.listQueryAliases = listQueryAliases;
|
|
52
|
+
/** An alias of the query by name, or of a query it is part of (see `listQueryAliases`). */
|
|
53
|
+
function findQueryAlias(queryBuilder, aliasName) {
|
|
54
|
+
return listQueryAliases(queryBuilder).find((candidate) => candidate.name === aliasName);
|
|
51
55
|
}
|
|
52
56
|
// private-use characters: no identifier or SQL that TypeORM builds contains them
|
|
53
57
|
const DEFERRED_KEY_START = '\uE000';
|
|
@@ -74,7 +78,7 @@ function deferColumnKey(aliasName, separator, name) {
|
|
|
74
78
|
* subquery in the condition of a raw join): TypeORM can't map it, and PostgreSQL would fold it to lower case.
|
|
75
79
|
*/
|
|
76
80
|
function toDeferredKeySql(alias, aliasName, separator, name, escape) {
|
|
77
|
-
const metadata = (alias
|
|
81
|
+
const metadata = metadataOf(alias);
|
|
78
82
|
if (separator === DEFERRED_UNQUOTED) {
|
|
79
83
|
return metadata ? `${aliasName}.${name}` : `${escape(aliasName)}.${escape(name)}`;
|
|
80
84
|
}
|
|
@@ -149,13 +153,11 @@ function installDeferredKeyResolution() {
|
|
|
149
153
|
}
|
|
150
154
|
}
|
|
151
155
|
installDeferredKeyResolution();
|
|
156
|
+
const metadataOf = (alias) => (alias === null || alias === void 0 ? void 0 : alias.hasMetadata) ? alias.metadata : undefined;
|
|
152
157
|
/** Entity metadata of a query alias (the main alias when `aliasName` is undefined), if it has any. */
|
|
153
158
|
function getAliasMetadata(queryBuilder, aliasName) {
|
|
154
159
|
var _a;
|
|
155
|
-
|
|
156
|
-
? (_a = queryBuilder.expressionMap) === null || _a === void 0 ? void 0 : _a.mainAlias
|
|
157
|
-
: findQueryAlias(queryBuilder, aliasName);
|
|
158
|
-
return (alias === null || alias === void 0 ? void 0 : alias.hasMetadata) ? alias.metadata : undefined;
|
|
160
|
+
return metadataOf(aliasName === undefined ? (_a = queryBuilder.expressionMap) === null || _a === void 0 ? void 0 : _a.mainAlias : findQueryAlias(queryBuilder, aliasName));
|
|
159
161
|
}
|
|
160
162
|
/**
|
|
161
163
|
* Database name of an entity property's column (`@Column({ name })`), looked up in the metadata of
|
|
@@ -185,6 +187,7 @@ function findFieldColumn(builder, field) {
|
|
|
185
187
|
const metadata = getAliasMetadata(queryBuilder, field.slice(0, dot));
|
|
186
188
|
return metadata && findColumn(metadata, field.slice(dot + 1));
|
|
187
189
|
}
|
|
190
|
+
// only by database name: an unqualified property name may mean another table's column
|
|
188
191
|
return (_a = getAliasMetadata(queryBuilder, undefined)) === null || _a === void 0 ? void 0 : _a.columns.find((column) => column.databaseName === field);
|
|
189
192
|
}
|
|
190
193
|
exports.findFieldColumn = findFieldColumn;
|
|
@@ -205,27 +208,17 @@ exports.findFieldColumn = findFieldColumn;
|
|
|
205
208
|
*/
|
|
206
209
|
function toFieldSql(builder, field) {
|
|
207
210
|
const queryBuilder = builder;
|
|
211
|
+
const column = findFieldColumn(builder, field);
|
|
208
212
|
const dot = field.indexOf('.');
|
|
209
|
-
if (
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const columnSql = queryBuilder.escape(column.databaseName);
|
|
215
|
-
return isAliasPrefixingEnabled(queryBuilder) ? `${queryBuilder.escape(aliasName)}.${columnSql}` : columnSql;
|
|
216
|
-
}
|
|
217
|
-
const parts = TWO_PART_FIELD.exec(field);
|
|
218
|
-
if (parts && !findQueryAlias(queryBuilder, aliasName)) {
|
|
219
|
-
return deferColumnKey(parts[1], DEFERRED_FIELD, parts[2]);
|
|
220
|
-
}
|
|
213
|
+
if (column) {
|
|
214
|
+
const columnSql = queryBuilder.escape(column.databaseName);
|
|
215
|
+
return dot > 0 && isAliasPrefixingEnabled(queryBuilder)
|
|
216
|
+
? `${queryBuilder.escape(field.slice(0, dot))}.${columnSql}`
|
|
217
|
+
: columnSql;
|
|
221
218
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const column = metadata === null || metadata === void 0 ? void 0 : metadata.columns.find((candidate) => candidate.databaseName === field);
|
|
226
|
-
if (column) {
|
|
227
|
-
return queryBuilder.escape(column.databaseName);
|
|
228
|
-
}
|
|
219
|
+
const parts = dot > 0 ? TWO_PART_FIELD.exec(field) : null;
|
|
220
|
+
if (parts && !findQueryAlias(queryBuilder, parts[1])) {
|
|
221
|
+
return deferColumnKey(parts[1], DEFERRED_FIELD, parts[2]);
|
|
229
222
|
}
|
|
230
223
|
return (0, sql_utils_1.stringToSQLIdentifier)(field, (0, sql_utils_1.getDriverType)(builder));
|
|
231
224
|
}
|
|
@@ -266,15 +259,13 @@ function findColumnPath(metadata, keys) {
|
|
|
266
259
|
* before `from()` the property name is used as the column name.
|
|
267
260
|
*/
|
|
268
261
|
function resolveTypedKey(queryBuilder, keys) {
|
|
269
|
-
var _a, _b;
|
|
270
262
|
const resolved = resolveTypedKeyPath(queryBuilder, keys);
|
|
271
263
|
// deeper than `alias.column` only inside a JSON column: a nested relation can't be mapped to an alias
|
|
272
264
|
if (!resolved.jsonPath && keys.length > proxy_key_utils_1.MAX_KEY_DEPTH) {
|
|
273
265
|
throw (0, proxy_key_utils_1.createKeyTooDeepError)(keys);
|
|
274
266
|
}
|
|
275
|
-
const column = (_a = resolved.column) !== null && _a !== void 0 ? _a : (_b = resolved.metadata) === null || _b === void 0 ? void 0 : _b.findColumnWithPropertyPath(resolved.propertyPath);
|
|
276
267
|
// a @CalculatedColumn: TypeORM would write "alias"."property", a column the table doesn't have
|
|
277
|
-
if ((
|
|
268
|
+
if ((0, calculated_column_utils_1.isCalculated)(resolved.column)) {
|
|
278
269
|
throw new TypeError(`${keys.join('.')} is a @CalculatedColumn, not a column of the table: use the SQL expression that fills it`);
|
|
279
270
|
}
|
|
280
271
|
return resolved;
|
|
@@ -283,10 +274,12 @@ function resolveTypedKeyPath(queryBuilder, keys) {
|
|
|
283
274
|
const prefixing = isAliasPrefixingEnabled(queryBuilder);
|
|
284
275
|
if (keys.length === 1) {
|
|
285
276
|
const aliasName = prefixing ? requireMainAliasName(queryBuilder, keys[0]) : undefined;
|
|
277
|
+
const metadata = getAliasMetadata(queryBuilder, aliasName);
|
|
286
278
|
return {
|
|
287
279
|
aliasName,
|
|
288
280
|
propertyPath: keys[0],
|
|
289
|
-
metadata
|
|
281
|
+
metadata,
|
|
282
|
+
column: metadata === null || metadata === void 0 ? void 0 : metadata.findColumnWithPropertyPath(keys[0]),
|
|
290
283
|
};
|
|
291
284
|
}
|
|
292
285
|
const [firstKey, ...restKeys] = keys;
|
|
@@ -314,7 +307,7 @@ function resolveTypedKeyPath(queryBuilder, keys) {
|
|
|
314
307
|
};
|
|
315
308
|
}
|
|
316
309
|
}
|
|
317
|
-
const metadata = (queryAlias
|
|
310
|
+
const metadata = metadataOf(queryAlias);
|
|
318
311
|
return {
|
|
319
312
|
aliasName: firstKey,
|
|
320
313
|
propertyPath: restKeys.join('.'),
|
|
@@ -327,11 +320,11 @@ function resolveTypedKeyPath(queryBuilder, keys) {
|
|
|
327
320
|
* inside a JSON column: `"exec"."details" -> 'meta' ->> 'endTs'` (see `toJsonPathSql`).
|
|
328
321
|
*/
|
|
329
322
|
function toQuotedColumnKey(queryBuilder, { aliasName, propertyPath, metadata, column, jsonPath }, jsonOptions) {
|
|
330
|
-
var _a
|
|
323
|
+
var _a;
|
|
331
324
|
if (aliasName !== undefined && !metadata && !findQueryAlias(queryBuilder, aliasName)) {
|
|
332
325
|
return deferColumnKey(aliasName, DEFERRED_PROPERTY, propertyPath);
|
|
333
326
|
}
|
|
334
|
-
const columnName = (
|
|
327
|
+
const columnName = (_a = column === null || column === void 0 ? void 0 : column.databaseName) !== null && _a !== void 0 ? _a : propertyPath;
|
|
335
328
|
const columnSql = aliasName === undefined
|
|
336
329
|
? queryBuilder.escape(columnName)
|
|
337
330
|
: `${queryBuilder.escape(aliasName)}.${queryBuilder.escape(columnName)}`;
|
|
@@ -377,6 +370,19 @@ function getTypedSingleColumnKey(builder, callback, methodName, jsonOptions) {
|
|
|
377
370
|
return key;
|
|
378
371
|
}
|
|
379
372
|
exports.getTypedSingleColumnKey = getTypedSingleColumnKey;
|
|
373
|
+
/**
|
|
374
|
+
* The alias and the entity property a typed callback picks, for methods that take a property rather than a column
|
|
375
|
+
* (a `@CalculatedColumn`): `u => u.imagesCount` is on the main alias, `q => q.owner.imagesCount` on `owner`.
|
|
376
|
+
*/
|
|
377
|
+
function resolveTypedProperty(builder, callback, methodName) {
|
|
378
|
+
const keyHolder = (0, proxy_key_utils_1.getKeyHolder)(callback);
|
|
379
|
+
if (Array.isArray(keyHolder)) {
|
|
380
|
+
throw new TypeError(`${methodName} expects the callback to pick a single property, got ${keyHolder.length}`);
|
|
381
|
+
}
|
|
382
|
+
const { aliasName, propertyPath } = resolveTypedKeyPath(builder, keyHolder.getKeys());
|
|
383
|
+
return { aliasName, propertyPath };
|
|
384
|
+
}
|
|
385
|
+
exports.resolveTypedProperty = resolveTypedProperty;
|
|
380
386
|
/**
|
|
381
387
|
* Throws for a key that names no column of its table: a relation whose join column is on the other side
|
|
382
388
|
* (one-to-many, many-to-many, the inverse side of a one-to-one) or an embedded entity. TypeORM leaves such a key
|
|
@@ -457,3 +463,20 @@ function getAppliedOrderBy(builder) {
|
|
|
457
463
|
});
|
|
458
464
|
}
|
|
459
465
|
exports.getAppliedOrderBy = getAppliedOrderBy;
|
|
466
|
+
/** The query without paging: no ORDER BY (nor the entity's default one), LIMIT, OFFSET, take or skip. */
|
|
467
|
+
function withoutPaging(query) {
|
|
468
|
+
return query
|
|
469
|
+
.orderBy()
|
|
470
|
+
.offset(undefined)
|
|
471
|
+
.limit(undefined)
|
|
472
|
+
.skip(undefined)
|
|
473
|
+
.take(undefined)
|
|
474
|
+
.setOption('disable-global-order');
|
|
475
|
+
}
|
|
476
|
+
exports.withoutPaging = withoutPaging;
|
|
477
|
+
/** The query runner a builder was created with, from a transactional manager; `undefined` for one from the pool. */
|
|
478
|
+
function getQueryRunner(builder) {
|
|
479
|
+
// queryRunner is protected in TypeORM's types
|
|
480
|
+
return builder.queryRunner;
|
|
481
|
+
}
|
|
482
|
+
exports.getQueryRunner = getQueryRunner;
|
|
@@ -4,6 +4,7 @@ exports.tableHelper = void 0;
|
|
|
4
4
|
const typeorm_1 = require("typeorm");
|
|
5
5
|
const sql_utils_1 = require("./sql.utils");
|
|
6
6
|
const json_path_utils_1 = require("./json-path.utils");
|
|
7
|
+
const time_zone_utils_1 = require("./time-zone.utils");
|
|
7
8
|
/**
|
|
8
9
|
* The argument of an aggregate and the clause after it for a `filter` written with `syntax`:
|
|
9
10
|
* `CASE WHEN filter THEN argument END`, or `argument` and ` FILTER (WHERE filter)`.
|
|
@@ -45,9 +46,9 @@ const DATE_TRUNC_UNITS = [
|
|
|
45
46
|
'century',
|
|
46
47
|
'millennium',
|
|
47
48
|
];
|
|
48
|
-
function assertPostgres(method, driver) {
|
|
49
|
+
function assertPostgres(method, driver, hint) {
|
|
49
50
|
if (driver !== undefined && !(0, sql_utils_1.isPostgresLikeDriver)(driver)) {
|
|
50
|
-
throw new TypeError(`tableHelper.${method}(): PostgreSQL only, the driver is "${driver}"`);
|
|
51
|
+
throw new TypeError(`tableHelper.${method}(): PostgreSQL only, the driver is "${driver}"${hint ? `: ${hint}` : ''}`);
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
function toExpression(value, toColumn) {
|
|
@@ -58,7 +59,7 @@ function toTimeZone(method, timeZone, toColumn) {
|
|
|
58
59
|
if (!timeZone.trim()) {
|
|
59
60
|
throw new TypeError(`tableHelper.${method}(): the time zone is empty`);
|
|
60
61
|
}
|
|
61
|
-
return sqlString(toPostgresZone(timeZone));
|
|
62
|
+
return sqlString(toPostgresZone(method, timeZone));
|
|
62
63
|
}
|
|
63
64
|
if ('sql' in timeZone) {
|
|
64
65
|
return timeZone.sql;
|
|
@@ -66,19 +67,18 @@ function toTimeZone(method, timeZone, toColumn) {
|
|
|
66
67
|
const column = toColumn(timeZone.column);
|
|
67
68
|
return timeZone.fallback === undefined
|
|
68
69
|
? column
|
|
69
|
-
: `COALESCE(${column}, ${sqlString(toPostgresZone(timeZone.fallback))})`;
|
|
70
|
+
: `COALESCE(${column}, ${sqlString(toPostgresZone(method, timeZone.fallback))})`;
|
|
70
71
|
}
|
|
71
|
-
const ISO_OFFSET = /^([+-])(\d{2}):?(\d{2})?$/;
|
|
72
72
|
/**
|
|
73
73
|
* PostgreSQL reads `'+02:00'` as a POSIX zone, whose offsets count west: UTC−2. An ISO 8601 offset is
|
|
74
74
|
* written as the POSIX zone of the same offset, `'<+0200>-02:00'`, so `'+02:00'` is UTC+2 as everywhere else.
|
|
75
75
|
*/
|
|
76
|
-
function toPostgresZone(timeZone) {
|
|
77
|
-
const offset =
|
|
76
|
+
function toPostgresZone(method, timeZone) {
|
|
77
|
+
const offset = (0, time_zone_utils_1.parseUtcOffset)(timeZone.trim(), `tableHelper.${method}(): "${timeZone}" is not a UTC offset`);
|
|
78
78
|
if (offset === null) {
|
|
79
79
|
return timeZone;
|
|
80
80
|
}
|
|
81
|
-
const
|
|
81
|
+
const { sign, hours, minutes } = offset;
|
|
82
82
|
return `<${sign}${hours}${minutes}>${sign === '+' ? '-' : '+'}${hours}:${minutes}`;
|
|
83
83
|
}
|
|
84
84
|
/** The JSON functions of a database: PostgreSQL's unless the driver is MySQL / MariaDB or SQLite. */
|
|
@@ -200,9 +200,7 @@ const createTableHelper = (alias, options = {}, databaseNames) => ({
|
|
|
200
200
|
arrayAgg(columnName, aggOptions = {}) {
|
|
201
201
|
var _a;
|
|
202
202
|
const { distinct = false, orderBy, filter } = aggOptions;
|
|
203
|
-
|
|
204
|
-
throw new TypeError(`tableHelper.arrayAgg(): arrays are PostgreSQL's, the driver is "${options.driver}": use jsonAgg`);
|
|
205
|
-
}
|
|
203
|
+
assertPostgres('arrayAgg', options.driver, 'use jsonAgg');
|
|
206
204
|
const order = orderBy ? aggregateOrder('arrayAgg', orderBy, (column) => this.column(column)) : undefined;
|
|
207
205
|
// PostgreSQL: "in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list"
|
|
208
206
|
if (distinct && order && order.column !== columnName) {
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
type UtcOffset = {
|
|
2
|
+
sign: '+' | '-';
|
|
3
|
+
hours: string;
|
|
4
|
+
minutes: string;
|
|
5
|
+
};
|
|
6
|
+
/** The parts of an ISO 8601 UTC offset (`+02:00`, `-0530`, `+02`); `null` for other text, a `TypeError` past 23:59. */
|
|
7
|
+
export declare function parseUtcOffset(text: string, errorMessage: string): UtcOffset | null;
|
|
1
8
|
/** Throws a `TypeError` for a time zone the runtime doesn't know. */
|
|
2
9
|
export declare function assertTimeZone(timeZone: string): void;
|
|
3
10
|
/**
|
|
@@ -6,3 +13,4 @@ export declare function assertTimeZone(timeZone: string): void;
|
|
|
6
13
|
* instant already: it is returned as that `Date`. Any other string throws a `TypeError` naming `name`.
|
|
7
14
|
*/
|
|
8
15
|
export declare function readInTimeZone(value: string, timeZone: string, name: string): Date;
|
|
16
|
+
export {};
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readInTimeZone = exports.assertTimeZone = void 0;
|
|
3
|
+
exports.readInTimeZone = exports.assertTimeZone = exports.parseUtcOffset = void 0;
|
|
4
4
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
5
5
|
const MAX_CACHED_FORMATTERS = 500;
|
|
6
6
|
const DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?(Z|[+-]\d{2}(?::?\d{2})?)?)?$/i;
|
|
7
7
|
const OFFSET = /^([+-])(\d{2}):?(\d{2})?$/;
|
|
8
|
+
/** The parts of an ISO 8601 UTC offset (`+02:00`, `-0530`, `+02`); `null` for other text, a `TypeError` past 23:59. */
|
|
9
|
+
function parseUtcOffset(text, errorMessage) {
|
|
10
|
+
const offset = OFFSET.exec(text);
|
|
11
|
+
if (offset === null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const [, sign, hours, minutes = '00'] = offset;
|
|
15
|
+
if (Number(hours) > 23 || Number(minutes) > 59) {
|
|
16
|
+
throw new TypeError(errorMessage);
|
|
17
|
+
}
|
|
18
|
+
return { sign: sign, hours, minutes };
|
|
19
|
+
}
|
|
20
|
+
exports.parseUtcOffset = parseUtcOffset;
|
|
8
21
|
const formatters = new Map();
|
|
9
22
|
function getFormatter(timeZone) {
|
|
10
23
|
let formatter = formatters.get(timeZone);
|
|
@@ -94,9 +107,6 @@ function getOffsetMinutes(offset, value, name) {
|
|
|
94
107
|
if (offset.toUpperCase() === 'Z') {
|
|
95
108
|
return 0;
|
|
96
109
|
}
|
|
97
|
-
const
|
|
98
|
-
if (Number(hours) > 23 || Number(minutes) > 59) {
|
|
99
|
-
throw new TypeError(`Invalid ${name} "${value}": not a UTC offset`);
|
|
100
|
-
}
|
|
110
|
+
const { sign, hours, minutes } = parseUtcOffset(offset, `Invalid ${name} "${value}": not a UTC offset`);
|
|
101
111
|
return (sign === '-' ? -1 : 1) * (Number(hours) * 60 + Number(minutes));
|
|
102
112
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
|
|
2
|
+
import type { KeyProxyCallback } from '../types/modules/proxy-callback.types';
|
|
3
|
+
import type { JsonPathSqlOptions } from './json-path.utils';
|
|
4
|
+
/**
|
|
5
|
+
* Calls the untyped where `method` with the single column a typed callback picks, followed by `args`, as the typed
|
|
6
|
+
* where methods that only add the column to their untyped counterpart do. A callback that isn't a function, from
|
|
7
|
+
* untyped code, leaves the builder as it is.
|
|
8
|
+
*/
|
|
9
|
+
export declare function attachTypedColumnWhere<Type extends ObjectLiteral, QB extends WhereExpressionBuilder, Args extends unknown[] = unknown[]>(builder: QB, method: string, where: KeyProxyCallback<Type>, jsonOptions: JsonPathSqlOptions | undefined, ...args: Args): QB;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachTypedColumnWhere = void 0;
|
|
4
|
+
const query_builder_utils_1 = require("./query-builder.utils");
|
|
5
|
+
/**
|
|
6
|
+
* Calls the untyped where `method` with the single column a typed callback picks, followed by `args`, as the typed
|
|
7
|
+
* where methods that only add the column to their untyped counterpart do. A callback that isn't a function, from
|
|
8
|
+
* untyped code, leaves the builder as it is.
|
|
9
|
+
*/
|
|
10
|
+
function attachTypedColumnWhere(builder, method, where, jsonOptions, ...args) {
|
|
11
|
+
if (typeof where !== 'function') {
|
|
12
|
+
return builder;
|
|
13
|
+
}
|
|
14
|
+
const key = (0, query_builder_utils_1.getTypedSingleColumnKey)(builder, where, `${method}Typed`, jsonOptions);
|
|
15
|
+
return builder[method](key, ...args);
|
|
16
|
+
}
|
|
17
|
+
exports.attachTypedColumnWhere = attachTypedColumnWhere;
|
|
@@ -5,6 +5,8 @@ export declare function getValuePlaceholder<T>(value: T, paramName?: string): st
|
|
|
5
5
|
* Whether `params` is a `{ name: value }` params object (a plain object or a class instance such
|
|
6
6
|
* as a DTO), rather than the value itself (a primitive, an array, a `Date`, a `Buffer`).
|
|
7
7
|
*/
|
|
8
|
+
/** The value a condition compares with: the value of a one-key params object, or the params themselves (a Date or a Buffer is a value too). */
|
|
9
|
+
export declare function getComparedValue(params: unknown): unknown;
|
|
8
10
|
export declare function isParamsObject(params: unknown): params is Record<string, unknown>;
|
|
9
11
|
/**
|
|
10
12
|
* Checks whether `conditions` already references a key of `params` as a TypeORM
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.andWhereNarrowing = exports.attachWhere = exports.hasParamPlaceholder = exports.isParamsObject = exports.getValuePlaceholder = void 0;
|
|
3
|
+
exports.andWhereNarrowing = exports.attachWhere = exports.hasParamPlaceholder = exports.isParamsObject = exports.getComparedValue = exports.getValuePlaceholder = void 0;
|
|
4
4
|
const sql_utils_1 = require("./sql.utils");
|
|
5
5
|
const query_builder_utils_1 = require("./query-builder.utils");
|
|
6
|
+
const parameter_utils_1 = require("./parameter.utils");
|
|
7
|
+
const common_utils_1 = require("./common.utils");
|
|
6
8
|
function getValuePlaceholder(value, paramName) {
|
|
7
9
|
if (value === undefined || value === null || paramName === undefined) {
|
|
8
10
|
return 'NULL';
|
|
@@ -18,16 +20,20 @@ exports.getValuePlaceholder = getValuePlaceholder;
|
|
|
18
20
|
* `:` or `.` is a parameter or a column (`ILIKE :like`, `= t.in`), not an operator.
|
|
19
21
|
*/
|
|
20
22
|
const OPERATOR_AT_END = /(?:[=<>!~@&|?]|(?<![\w$:.])(?:LIKE|ILIKE|IN|SIMILAR TO|DISTINCT FROM|BETWEEN|ANY|ALL))\s*$/i;
|
|
21
|
-
const isDate = (value) => Object.prototype.toString.call(value) === '[object Date]';
|
|
22
23
|
/**
|
|
23
24
|
* Objects that are parameter values themselves, not `{ name: value }` params objects:
|
|
24
25
|
* `Date`, and binary data (`Buffer`, typed arrays, `ArrayBuffer`).
|
|
25
26
|
*/
|
|
26
|
-
const isValueObject = (value) => isDate(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer;
|
|
27
|
+
const isValueObject = (value) => (0, common_utils_1.isDate)(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer;
|
|
27
28
|
/**
|
|
28
29
|
* Whether `params` is a `{ name: value }` params object (a plain object or a class instance such
|
|
29
30
|
* as a DTO), rather than the value itself (a primitive, an array, a `Date`, a `Buffer`).
|
|
30
31
|
*/
|
|
32
|
+
/** The value a condition compares with: the value of a one-key params object, or the params themselves (a Date or a Buffer is a value too). */
|
|
33
|
+
function getComparedValue(params) {
|
|
34
|
+
return isParamsObject(params) ? Object.values(params)[0] : params;
|
|
35
|
+
}
|
|
36
|
+
exports.getComparedValue = getComparedValue;
|
|
31
37
|
function isParamsObject(params) {
|
|
32
38
|
return (params !== null &&
|
|
33
39
|
typeof params === 'object' &&
|
|
@@ -44,14 +50,7 @@ function hasParamPlaceholder(conditions, params) {
|
|
|
44
50
|
if (!isParamsObject(params)) {
|
|
45
51
|
return false;
|
|
46
52
|
}
|
|
47
|
-
|
|
48
|
-
let match;
|
|
49
|
-
while ((match = placeholderRegex.exec(conditions)) !== null) {
|
|
50
|
-
if (Object.prototype.hasOwnProperty.call(params, match[1])) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
53
|
+
return (0, parameter_utils_1.getPlaceholderNames)(conditions).some((name) => Object.prototype.hasOwnProperty.call(params, name));
|
|
55
54
|
}
|
|
56
55
|
exports.hasParamPlaceholder = hasParamPlaceholder;
|
|
57
56
|
/**
|
|
@@ -87,13 +86,12 @@ function attachWhere(builder, method, field, conditions, params, options) {
|
|
|
87
86
|
}
|
|
88
87
|
if (addValue && hasParams) {
|
|
89
88
|
assertSingleValueParams(fieldName, params);
|
|
90
|
-
|
|
91
|
-
const firstValue = isParamsObject(params) ? Object.values(params)[0] : params;
|
|
89
|
+
const firstValue = getComparedValue(params);
|
|
92
90
|
// 0, false, '' are valid values like any other
|
|
93
91
|
// null, undefined, NaN and invalid dates are equal to NULL
|
|
94
92
|
const valueIsValid = firstValue !== undefined &&
|
|
95
93
|
(typeof firstValue === 'number' ? !isNaN(firstValue) : true) &&
|
|
96
|
-
(isDate(firstValue) ? !isNaN(firstValue.getTime()) : true);
|
|
94
|
+
((0, common_utils_1.isDate)(firstValue) ? !isNaN(firstValue.getTime()) : true);
|
|
97
95
|
const paramName = valueIsValid
|
|
98
96
|
? (0, sql_utils_1.createUniqueParameterName)(method)
|
|
99
97
|
: undefined;
|