typeorm-extensions 2.1.0 → 2.2.0-rc.1

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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -3
  3. package/dist/decorators/calculated-column.decorator.d.ts +30 -0
  4. package/dist/decorators/calculated-column.decorator.js +82 -0
  5. package/dist/decorators/index.d.ts +1 -0
  6. package/dist/decorators/index.js +17 -0
  7. package/dist/extensions/calculated-column.extension.d.ts +33 -0
  8. package/dist/extensions/calculated-column.extension.js +33 -0
  9. package/dist/extensions/cursor-pagination.extension.d.ts +2 -1
  10. package/dist/extensions/cursor-pagination.extension.js +4 -3
  11. package/dist/extensions/get-many-with-totals.extension.d.ts +9 -1
  12. package/dist/extensions/get-many-with-totals.extension.js +159 -10
  13. package/dist/extensions/index.d.ts +7 -0
  14. package/dist/extensions/index.js +7 -0
  15. package/dist/extensions/join-lateral.extension.d.ts +19 -0
  16. package/dist/extensions/join-lateral.extension.js +50 -0
  17. package/dist/extensions/join-unnest.extension.d.ts +19 -0
  18. package/dist/extensions/join-unnest.extension.js +40 -0
  19. package/dist/extensions/order.extension.js +18 -7
  20. package/dist/extensions/query-returning.extension.d.ts +29 -0
  21. package/dist/extensions/query-returning.extension.js +50 -0
  22. package/dist/extensions/typed/index.d.ts +3 -0
  23. package/dist/extensions/typed/index.js +3 -2
  24. package/dist/extensions/typed/typed-distinct/typed-distinct.extension.d.ts +3 -2
  25. package/dist/extensions/typed/typed-group-by/typed-group-by.extension.d.ts +24 -0
  26. package/dist/extensions/typed/typed-group-by/typed-group-by.extension.js +31 -0
  27. package/dist/extensions/typed/typed-having/typed-having.extension.d.ts +36 -0
  28. package/dist/extensions/typed/typed-having/typed-having.extension.js +42 -0
  29. package/dist/extensions/typed/typed-joins/typed-joins.extension.d.ts +5 -4
  30. package/dist/extensions/typed/typed-order-by/typed-order-by-array-position.extension.d.ts +3 -2
  31. package/dist/extensions/typed/typed-order-by/typed-order-by-array-position.extension.js +10 -2
  32. package/dist/extensions/typed/typed-order-by/typed-order-by.extension.d.ts +3 -2
  33. package/dist/extensions/typed/typed-order-by/typed-order-by.extension.js +3 -2
  34. package/dist/extensions/typed/typed-root.extension.d.ts +25 -0
  35. package/dist/extensions/typed/typed-root.extension.js +13 -0
  36. package/dist/extensions/typed/typed-select/typed-select.extension.d.ts +5 -4
  37. package/dist/extensions/typed/typed-select/typed-select.extension.js +3 -2
  38. package/dist/extensions/typed/typed-where/typed-period-filter.extension.d.ts +2 -1
  39. package/dist/extensions/typed/typed-where/typed-where-array.extension.d.ts +10 -9
  40. package/dist/extensions/typed/typed-where/typed-where-array.extension.js +32 -0
  41. package/dist/extensions/typed/typed-where/typed-where-ilike.extension.d.ts +7 -6
  42. package/dist/extensions/typed/typed-where/typed-where-is-any.extension.d.ts +7 -6
  43. package/dist/extensions/typed/typed-where/typed-where-is-distinct-from.extension.d.ts +7 -6
  44. package/dist/extensions/typed/typed-where/typed-where-is-in.extension.d.ts +7 -6
  45. package/dist/extensions/typed/typed-where/typed-where-json.extension.d.ts +7 -6
  46. package/dist/extensions/typed/typed-where/typed-where-lower.extension.d.ts +7 -6
  47. package/dist/extensions/typed/typed-where/typed-where-similar.extension.d.ts +5 -4
  48. package/dist/extensions/typed/typed-where/typed-where.extension.d.ts +4 -3
  49. package/dist/extensions/union.extension.d.ts +22 -0
  50. package/dist/extensions/union.extension.js +52 -0
  51. package/dist/extensions/where-exists.extension.d.ts +50 -0
  52. package/dist/extensions/where-exists.extension.js +64 -0
  53. package/dist/extensions/where-relation-exists.extension.d.ts +38 -0
  54. package/dist/extensions/where-relation-exists.extension.js +95 -0
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.js +1 -0
  57. package/dist/types/extensions/cursor-pagination.types.d.ts +5 -0
  58. package/dist/types/extensions/get-many-with-totals.types.d.ts +19 -0
  59. package/dist/types/extensions/index.d.ts +5 -0
  60. package/dist/types/extensions/index.js +5 -0
  61. package/dist/types/extensions/join-lateral.types.d.ts +6 -0
  62. package/dist/types/extensions/join-lateral.types.js +2 -0
  63. package/dist/types/extensions/period.types.d.ts +8 -0
  64. package/dist/types/extensions/query-returning.types.d.ts +11 -0
  65. package/dist/types/extensions/query-returning.types.js +2 -0
  66. package/dist/types/extensions/typed-group-by.types.d.ts +8 -0
  67. package/dist/types/extensions/typed-group-by.types.js +2 -0
  68. package/dist/types/extensions/typed-having.types.d.ts +2 -0
  69. package/dist/types/extensions/typed-having.types.js +2 -0
  70. package/dist/types/extensions/union.types.d.ts +12 -0
  71. package/dist/types/extensions/union.types.js +2 -0
  72. package/dist/types/extensions/where.types.d.ts +1 -0
  73. package/dist/types/modules/typed-root.types.d.ts +17 -0
  74. package/dist/types/modules/typed-root.types.js +2 -0
  75. package/dist/utils/calculated-column.utils.d.ts +21 -0
  76. package/dist/utils/calculated-column.utils.js +63 -0
  77. package/dist/utils/parameter.utils.d.ts +7 -0
  78. package/dist/utils/parameter.utils.js +21 -0
  79. package/dist/utils/period.utils.js +7 -2
  80. package/dist/utils/prototype.utils.d.ts +5 -1
  81. package/dist/utils/prototype.utils.js +4 -1
  82. package/dist/utils/proxy-key.utils.d.ts +3 -3
  83. package/dist/utils/proxy-key.utils.js +7 -7
  84. package/dist/utils/query-builder.utils.d.ts +8 -0
  85. package/dist/utils/query-builder.utils.js +30 -2
  86. package/dist/utils/table.utils.d.ts +112 -2
  87. package/dist/utils/table.utils.js +206 -11
  88. package/dist/utils/time-zone.utils.d.ts +8 -0
  89. package/dist/utils/time-zone.utils.js +102 -0
  90. package/dist/utils/where.utils.d.ts +2 -2
  91. package/dist/utils/where.utils.js +23 -2
  92. package/package.json +3 -3
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typeorm_1 = require("typeorm");
4
+ const prototype_utils_1 = require("../utils/prototype.utils");
5
+ const query_builder_utils_1 = require("../utils/query-builder.utils");
6
+ const sql_utils_1 = require("../utils/sql.utils");
7
+ const where_utils_1 = require("../utils/where.utils");
8
+ /* eslint-enable @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars */
9
+ // patching
10
+ const extension = {
11
+ prototype: {
12
+ innerJoinUnnest(field, array, arrayType) {
13
+ return innerJoinUnnest(this, field, array, arrayType);
14
+ },
15
+ },
16
+ };
17
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.SelectQueryBuilder, extension);
18
+ // implementation
19
+ function innerJoinUnnest(builder, field, array, arrayType) {
20
+ const castTo = (0, sql_utils_1.assertArrayType)(arrayType !== null && arrayType !== void 0 ? arrayType : columnArrayType(builder, field));
21
+ if (!(array === null || array === void 0 ? void 0 : array.length)) {
22
+ // narrows the whole WHERE, as the join does: after .where(a).orWhere(b) not a OR b AND FALSE
23
+ return (0, where_utils_1.andWhereNarrowing)(builder, 'FALSE');
24
+ }
25
+ const paramName = (0, sql_utils_1.createUniqueParameterName)('unnest');
26
+ const alias = (0, sql_utils_1.createUniqueParameterName)('unnest');
27
+ const value = builder.escape('value');
28
+ // DISTINCT: a value repeated in the array would repeat the rows it matches
29
+ return builder.innerJoin(`(SELECT DISTINCT unnest(CAST(:${paramName} AS ${castTo})) AS ${value})`, alias, `${(0, query_builder_utils_1.toFieldSql)(builder, field)} = ${builder.escape(alias)}.${value}`, { [paramName]: array });
30
+ }
31
+ /** `<column type>[]` of the entity column `field` names, as the driver spells the type. */
32
+ function columnArrayType(builder, field) {
33
+ const column = (0, query_builder_utils_1.findFieldColumn)(builder, field);
34
+ if (!column || column.type === 'enum' || column.type === 'simple-enum') {
35
+ throw new TypeError(`innerJoinUnnest: pass the array type for "${field}", e.g. 'uuid[]': ` +
36
+ (column ? 'the type of an enum column is named by the database' : 'it is not an entity column'));
37
+ }
38
+ const driver = builder.connection.driver;
39
+ return `${driver.normalizeType(column)}[]`;
40
+ }
@@ -8,6 +8,8 @@ const prototype_utils_1 = require("../utils/prototype.utils");
8
8
  const table_utils_1 = require("../utils/table.utils");
9
9
  const order_utils_1 = require("../utils/order.utils");
10
10
  const query_builder_utils_1 = require("../utils/query-builder.utils");
11
+ const sql_utils_1 = require("../utils/sql.utils");
12
+ const calculated_column_utils_1 = require("../utils/calculated-column.utils");
11
13
  // patching
12
14
  const extension = {
13
15
  prototype: {
@@ -37,19 +39,28 @@ function getOrderOption(builder, orderBy, options) {
37
39
  const { field, direction, isReversed, nulls: nullsOrder, tableAlias: otherTableAlias, } = orderBy;
38
40
  const alias = otherTableAlias || customAlias ||
39
41
  (alwaysAliasFields.includes(field) ? defaultAlias : undefined);
40
- const table = (0, table_utils_1.tableHelper)(alias, { useQuotes });
41
- // TypeORM maps an unquoted `alias.property` to the column itself; anything else must name the
42
- // column: `@Column({ name: 'created_at' }) createdAt` is ordered by "created_at", not "createdAt"
43
- const column = alias && !useQuotes
44
- ? field
45
- : (_a = (0, query_builder_utils_1.getColumnDatabaseName)(builder, alias, field)) !== null && _a !== void 0 ? _a : field;
46
- const selector = table.column(column);
47
42
  const order = typeof isReversed === 'boolean' && (0, common_utils_1.isNil)(direction)
48
43
  ? (isReversed ? 'DESC' : 'ASC')
49
44
  : (0, order_utils_1.toSqlOrderDirection)(direction);
50
45
  const nulls = typeof nullsOrder === 'string' && /first|last/i.test(nullsOrder)
51
46
  ? `NULLS ${nullsOrder.toUpperCase()}`
52
47
  : constants_1.defaultNullsOrder;
48
+ // a @CalculatedColumn has no column: order by its value, selected with addSelectCalculated
49
+ const calculatedAlias = alias !== null && alias !== void 0 ? alias : defaultAlias;
50
+ if ((0, calculated_column_utils_1.isCalculatedColumn)(builder, field, calculatedAlias)) {
51
+ return {
52
+ selector: (0, calculated_column_utils_1.selectCalculatedForOrder)(builder, field, calculatedAlias, 'applyOrder'),
53
+ order,
54
+ nulls,
55
+ };
56
+ }
57
+ const table = (0, table_utils_1.tableHelper)(alias, { useQuotes, driver: (0, sql_utils_1.getDriverType)(builder) });
58
+ // TypeORM maps an unquoted `alias.property` to the column itself; anything else must name the
59
+ // column: `@Column({ name: 'created_at' }) createdAt` is ordered by "created_at", not "createdAt"
60
+ const column = alias && !useQuotes
61
+ ? field
62
+ : (_a = (0, query_builder_utils_1.getColumnDatabaseName)(builder, alias, field)) !== null && _a !== void 0 ? _a : field;
63
+ const selector = table.column(column);
53
64
  return {
54
65
  selector,
55
66
  order,
@@ -0,0 +1,29 @@
1
+ import { ObjectLiteral } from 'typeorm';
2
+ import type { QueryReturningResult } from '../types/extensions/query-returning.types';
3
+ export interface QueryReturningMethods {
4
+ /**
5
+ * Runs a raw statement and resolves its rows and the row count it touched, in the same shape
6
+ * whatever the statement: `{ records, affected }`.
7
+ *
8
+ * `query()` shapes its result by the command instead. On PostgreSQL an UPDATE or a DELETE resolves
9
+ * to `[rows, rowCount]`, while a SELECT or an INSERT resolves to the rows, so `(await query(sql))[0]`
10
+ * is the first row of an INSERT … RETURNING but the whole rows array of an UPDATE … RETURNING:
11
+ * truthy, so a `if (!row) throw` check passes, and every field of it reads `undefined`.
12
+ *
13
+ * On an entity manager bound to a query runner (inside a transaction) the statement runs on that
14
+ * runner, so it stays in the transaction; otherwise it gets a query runner of its own and releases it.
15
+ */
16
+ queryReturning<Row = ObjectLiteral>(query: string, parameters?: unknown[]): Promise<QueryReturningResult<Row>>;
17
+ }
18
+ declare module 'typeorm/entity-manager/EntityManager' {
19
+ interface EntityManager extends QueryReturningMethods {
20
+ }
21
+ }
22
+ declare module 'typeorm/repository/Repository' {
23
+ interface Repository<Entity extends ObjectLiteral> extends QueryReturningMethods {
24
+ }
25
+ }
26
+ declare module 'typeorm/data-source/DataSource' {
27
+ interface DataSource extends QueryReturningMethods {
28
+ }
29
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typeorm_1 = require("typeorm");
4
+ const prototype_utils_1 = require("../utils/prototype.utils");
5
+ /* eslint-enable @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars */
6
+ // patching
7
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.EntityManager, {
8
+ prototype: {
9
+ queryReturning: function (query, parameters) {
10
+ return queryReturning(this, query, parameters);
11
+ },
12
+ },
13
+ });
14
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.Repository, {
15
+ prototype: {
16
+ queryReturning: function (query, parameters) {
17
+ return queryReturning(this.manager, query, parameters);
18
+ },
19
+ },
20
+ });
21
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.DataSource, {
22
+ prototype: {
23
+ queryReturning: function (query, parameters) {
24
+ return queryReturning(this.manager, query, parameters);
25
+ },
26
+ },
27
+ });
28
+ // implementation
29
+ const WRITE_RETURNING = /^(?:INSERT|UPDATE|DELETE)\s[\s\S]*\bRETURNING\b/i;
30
+ async function queryReturning(manager, query, parameters) {
31
+ var _a, _b, _c;
32
+ const boundQueryRunner = manager.queryRunner;
33
+ // TypeORM 1.x names the manager's data source `dataSource`; 0.3 calls it `connection`
34
+ const dataSource = (_a = manager.dataSource) !== null && _a !== void 0 ? _a : manager.connection;
35
+ const queryRunner = boundQueryRunner !== null && boundQueryRunner !== void 0 ? boundQueryRunner : dataSource.createQueryRunner();
36
+ // TypeORM 0.3's runner of the sqlite3 driver runs a statement that starts with `INSERT ` / `UPDATE ` /
37
+ // `DELETE ` without reading rows, which drops a RETURNING; after a line break it reads them.
38
+ // A string: TypeORM 1.x has no 'sqlite' driver type
39
+ const driverType = dataSource.options.type;
40
+ const sql = driverType === 'sqlite' && WRITE_RETURNING.test(query) ? `\n${query}` : query;
41
+ try {
42
+ const result = await queryRunner.query(sql, parameters, true);
43
+ return { records: (_b = result.records) !== null && _b !== void 0 ? _b : [], affected: (_c = result.affected) !== null && _c !== void 0 ? _c : null };
44
+ }
45
+ finally {
46
+ if (!boundQueryRunner) {
47
+ await queryRunner.release();
48
+ }
49
+ }
50
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './typed-distinct/typed-distinct.extension';
2
+ export * from './typed-group-by/typed-group-by.extension';
3
+ export * from './typed-having/typed-having.extension';
2
4
  export * from './typed-joins/typed-joins.extension';
3
5
  export * from './typed-order-by/typed-order-by.extension';
4
6
  export * from './typed-select/typed-select.extension';
@@ -14,3 +16,4 @@ export * from './typed-where/typed-where-lower.extension';
14
16
  export * from './typed-where/typed-where-similar.extension';
15
17
  export * from './typed-returning/typed-returning.extension';
16
18
  export * from './typed-order-by/typed-order-by-array-position.extension';
19
+ export * from './typed-root.extension';
@@ -16,8 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  //Extensions
18
18
  __exportStar(require("./typed-distinct/typed-distinct.extension"), exports);
19
- // export * from './typed/typed-group-by/typed-group-by.extension';
20
- // export * from './typed/typed-having/typed-having.extension';
19
+ __exportStar(require("./typed-group-by/typed-group-by.extension"), exports);
20
+ __exportStar(require("./typed-having/typed-having.extension"), exports);
21
21
  __exportStar(require("./typed-joins/typed-joins.extension"), exports);
22
22
  __exportStar(require("./typed-order-by/typed-order-by.extension"), exports);
23
23
  __exportStar(require("./typed-select/typed-select.extension"), exports);
@@ -33,3 +33,4 @@ __exportStar(require("./typed-where/typed-where-lower.extension"), exports);
33
33
  __exportStar(require("./typed-where/typed-where-similar.extension"), exports);
34
34
  __exportStar(require("./typed-returning/typed-returning.extension"), exports);
35
35
  __exportStar(require("./typed-order-by/typed-order-by-array-position.extension"), exports);
36
+ __exportStar(require("./typed-root.extension"), exports);
@@ -1,14 +1,15 @@
1
1
  import { ObjectLiteral } from 'typeorm';
2
2
  import { KeyProxyCallback } from '../../../types/modules/proxy-callback.types';
3
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
3
4
  declare module 'typeorm/query-builder/SelectQueryBuilder' {
4
5
  interface SelectQueryBuilder<Entity extends ObjectLiteral> {
5
6
  /**
6
7
  * Sets the distinct on clause for Postgres.
7
8
  */
8
- distinctOnTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, ...distinctOn: Array<KeyProxyCallback<Type>>): SelectQueryBuilder<Entity>;
9
+ distinctOnTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, ...distinctOn: Array<KeyProxyCallback<Type>>): SelectQueryBuilder<Entity>;
9
10
  /**
10
11
  * Sets the distinct on clause for Postgres.
11
12
  */
12
- distinctOnTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, distinctOn: KeyProxyCallback<Type>): SelectQueryBuilder<Entity>;
13
+ distinctOnTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, distinctOn: KeyProxyCallback<Type>): SelectQueryBuilder<Entity>;
13
14
  }
14
15
  }
@@ -0,0 +1,24 @@
1
+ import { ObjectLiteral } from 'typeorm';
2
+ import type { DeepUnwrapArray } from '../../../types/modules/proxy-callback.types';
3
+ import type { TypedGroupByOptions } from '../../../types/extensions/typed-group-by.types';
4
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
5
+ /** A value a column holds: a relation (`u => u.images`) or a JSON object is no column to group by. */
6
+ type GroupedColumn = string | number | boolean | Date | ArrayBufferView | ArrayBuffer | null | undefined;
7
+ /** One column, `user => user.id`, or several, `user => [user.id, user.email]`. */
8
+ type GroupBySelection<Type extends ObjectLiteral> = (proxy: DeepUnwrapArray<Type>) => GroupedColumn | GroupedColumn[];
9
+ export interface TypedGroupByMethods<Entity extends ObjectLiteral> {
10
+ /**
11
+ * Sets GROUP BY to the columns the callback selects: `user => user.id`, or several at once,
12
+ * `user => [user.id, user.email]`. Replaces previously set GROUP BY.
13
+ */
14
+ groupByTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(selection: GroupBySelection<Type>, options?: TypedGroupByOptions): this;
15
+ /**
16
+ * Adds the columns the callback selects to GROUP BY.
17
+ */
18
+ addGroupByTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(selection: GroupBySelection<Type>, options?: TypedGroupByOptions): this;
19
+ }
20
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
21
+ interface SelectQueryBuilder<Entity extends ObjectLiteral> extends TypedGroupByMethods<Entity> {
22
+ }
23
+ }
24
+ export {};
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typeorm_1 = require("typeorm");
4
+ const query_builder_utils_1 = require("../../../utils/query-builder.utils");
5
+ const prototype_utils_1 = require("../../../utils/prototype.utils");
6
+ /* eslint-enable @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars */
7
+ // patching
8
+ const extension = {
9
+ prototype: {
10
+ groupByTyped(selection, options) {
11
+ // keys first: a JSON path throws before the previous GROUP BY is dropped
12
+ const [first, ...rest] = toGroupByKeys(this, selection, options);
13
+ if (first === undefined) {
14
+ return this.groupBy();
15
+ }
16
+ return addGroupByKeys(this.groupBy(first), rest);
17
+ },
18
+ addGroupByTyped(selection, options) {
19
+ return addGroupByKeys(this, toGroupByKeys(this, selection, options));
20
+ },
21
+ },
22
+ };
23
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.SelectQueryBuilder, extension);
24
+ // implementation
25
+ function toGroupByKeys(builder, selection, options) {
26
+ const keys = (0, query_builder_utils_1.getTypedSelectionKey)(builder, selection, options === null || options === void 0 ? void 0 : options.useQuotes);
27
+ return Array.isArray(keys) ? keys : [keys];
28
+ }
29
+ function addGroupByKeys(builder, keys) {
30
+ return keys.reduce((query, key) => query.addGroupBy(key), builder);
31
+ }
@@ -0,0 +1,36 @@
1
+ import { ObjectLiteral } from 'typeorm';
2
+ import { DeepUnwrapArray, ProxyColumnValueType } from '../../../types/modules/proxy-callback.types';
3
+ import { TypedWhereArgs, TypeOrDefault, UnsetType } from '../../../types/modules/typed-params.types';
4
+ import type { TypedAggregate } from '../../../types/extensions/typed-having.types';
5
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
6
+ type Selection<Entity extends ObjectLiteral, Type, Value> = (proxy: DeepUnwrapArray<TypeOrDefault<Type, TypedRoot<Entity>>>) => Value;
7
+ /**
8
+ * A value a column holds. A relation (`u => u.images`), the end of a key path or a JSON object is no column:
9
+ * `COUNT("user"."images")` would fail in the database.
10
+ */
11
+ type AggregatedColumn = string | number | bigint | boolean | Date | ArrayBufferView | ArrayBuffer | readonly unknown[] | null | undefined;
12
+ /** `'*'`, all the rows, only for COUNT. */
13
+ type CountAll<Aggregate> = Aggregate extends 'COUNT' ? '*' : never;
14
+ /** The value an aggregate is compared with: a count, a sum or an average is a number, MIN / MAX the column's value. */
15
+ type AggregateValue<Aggregate, Value> = Aggregate extends 'MIN' | 'MAX' ? Value : number;
16
+ /**
17
+ * Typesafe HAVING conditions on an aggregate of an entity property: `havingTyped('COUNT', u => u.images.id, '>=', 2)`
18
+ * gives `HAVING COUNT("images"."id") >= :having_…`. Parameters work as in `whereTyped`; with `strictParams` the
19
+ * value is a number for COUNT, SUM and AVG, and the column's value for MIN and MAX. `'*'` counts every row.
20
+ *
21
+ * One signature, not overloads: with overloads TypeScript checks the other arguments before the arrow
22
+ * function, and the column type would not be known for the value.
23
+ */
24
+ export interface TypedHavingMethods<Entity extends ObjectLiteral> {
25
+ /** Sets HAVING `aggregate(column) condition`, replacing the previous HAVING. */
26
+ havingTyped<Type extends ObjectLiteral = UnsetType, Aggregate extends TypedAggregate = TypedAggregate, Value extends ProxyColumnValueType = ProxyColumnValueType, Operator extends string = string>(aggregate: Aggregate, selection: Selection<Entity, Type, Value & AggregatedColumn> | CountAll<Aggregate>, conditions: Operator, ...args: TypedWhereArgs<Type, Operator, AggregateValue<Aggregate, Value>>): this;
27
+ /** Adds AND HAVING `aggregate(column) condition`. */
28
+ andHavingTyped<Type extends ObjectLiteral = UnsetType, Aggregate extends TypedAggregate = TypedAggregate, Value extends ProxyColumnValueType = ProxyColumnValueType, Operator extends string = string>(aggregate: Aggregate, selection: Selection<Entity, Type, Value & AggregatedColumn> | CountAll<Aggregate>, conditions: Operator, ...args: TypedWhereArgs<Type, Operator, AggregateValue<Aggregate, Value>>): this;
29
+ /** Adds OR HAVING `aggregate(column) condition`. */
30
+ orHavingTyped<Type extends ObjectLiteral = UnsetType, Aggregate extends TypedAggregate = TypedAggregate, Value extends ProxyColumnValueType = ProxyColumnValueType, Operator extends string = string>(aggregate: Aggregate, selection: Selection<Entity, Type, Value & AggregatedColumn> | CountAll<Aggregate>, conditions: Operator, ...args: TypedWhereArgs<Type, Operator, AggregateValue<Aggregate, Value>>): this;
31
+ }
32
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
33
+ interface SelectQueryBuilder<Entity extends ObjectLiteral> extends TypedHavingMethods<Entity> {
34
+ }
35
+ }
36
+ export {};
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typeorm_1 = require("typeorm");
4
+ const query_builder_utils_1 = require("../../../utils/query-builder.utils");
5
+ const prototype_utils_1 = require("../../../utils/prototype.utils");
6
+ const where_utils_1 = require("../../../utils/where.utils");
7
+ const createHavingMethod = (method) => function (aggregate, selection, conditions, parameters, options) {
8
+ return attachTypedHaving(this, method, aggregate, selection, conditions, parameters, options);
9
+ };
10
+ const extension = {
11
+ prototype: {
12
+ havingTyped: createHavingMethod('having'),
13
+ andHavingTyped: createHavingMethod('andHaving'),
14
+ orHavingTyped: createHavingMethod('orHaving'),
15
+ },
16
+ };
17
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.SelectQueryBuilder, extension);
18
+ // implementation
19
+ const AGGREGATES = ['COUNT', 'COUNT DISTINCT', 'SUM', 'AVG', 'MIN', 'MAX'];
20
+ function attachTypedHaving(builder, method, aggregate, selection, conditions, parameters, options) {
21
+ const methodName = `${method}Typed`;
22
+ // the aggregate goes into the SQL as is
23
+ if (!AGGREGATES.includes(aggregate)) {
24
+ throw new TypeError(`${methodName}: the aggregate is one of ${AGGREGATES.join(', ')}, got "${String(aggregate)}"`);
25
+ }
26
+ let argument;
27
+ if (selection === '*') {
28
+ if (aggregate !== 'COUNT') {
29
+ throw new TypeError(`${methodName}: only COUNT takes '*', got ${aggregate}`);
30
+ }
31
+ argument = '*';
32
+ }
33
+ else {
34
+ // a path into a JSON column is cast: to a number to add it up, and for MIN / MAX to the type of the
35
+ // value it is compared with, as in whereTyped; a count needs no cast
36
+ const compared = (0, where_utils_1.isParamsObject)(parameters) ? Object.values(parameters)[0] : parameters;
37
+ const value = aggregate === 'SUM' || aggregate === 'AVG' ? 0 : aggregate === 'MIN' || aggregate === 'MAX' ? compared : undefined;
38
+ argument = (0, query_builder_utils_1.getTypedSingleColumnKey)(builder, selection, methodName, { value });
39
+ }
40
+ const expression = aggregate === 'COUNT DISTINCT' ? `COUNT(DISTINCT ${argument})` : `${aggregate}(${argument})`;
41
+ return (0, where_utils_1.attachWhere)(builder, method, expression, conditions, parameters, { addValue: options === null || options === void 0 ? void 0 : options.addValue });
42
+ }
@@ -1,10 +1,11 @@
1
1
  import { ObjectLiteral } from 'typeorm';
2
2
  import { RelationalKeyProxyCallback } from '../../../types/modules/proxy-callback.types';
3
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
3
4
  declare module 'typeorm/query-builder/SelectQueryBuilder' {
4
5
  interface SelectQueryBuilder<Entity extends ObjectLiteral> {
5
- leftJoinTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
6
- innerJoinTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
7
- leftJoinAndSelectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
8
- innerJoinAndSelectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
6
+ leftJoinTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
7
+ innerJoinTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
8
+ leftJoinAndSelectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
9
+ innerJoinAndSelectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: RelationalKeyProxyCallback<Type>, alias: string, condition?: string, parameters?: ObjectLiteral): SelectQueryBuilder<Entity>;
9
10
  }
10
11
  }
@@ -2,17 +2,18 @@ import '../../order-by-array-position.extension';
2
2
  import { ObjectLiteral } from 'typeorm';
3
3
  import { DeepUnwrapArray, ProxyColumnValueType } from '../../../types/modules/proxy-callback.types';
4
4
  import type { ArgsType } from '../../../types/util-types';
5
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
5
6
  export interface TypedOrderByArrayPositionMethods<Entity extends ObjectLiteral> {
6
7
  /**
7
8
  * Sets ORDER BY the position of the property's column value in `values` (PostgreSQL):
8
9
  * `array_position(:values, column)`. Rows whose value isn't in `values` come last.
9
10
  * Like `orderBy`, it replaces the previous ORDER BY. See `orderByArrayPosition`.
10
11
  */
11
- orderByArrayPositionTyped<Type extends ObjectLiteral = Entity>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, values: ArgsType, arrayType?: string): this;
12
+ orderByArrayPositionTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, values: ArgsType, arrayType?: string): this;
12
13
  /**
13
14
  * Adds ORDER BY the position of the property's column value in `values` (PostgreSQL), like `addOrderBy`.
14
15
  */
15
- addOrderByArrayPositionTyped<Type extends ObjectLiteral = Entity>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, values: ArgsType, arrayType?: string): this;
16
+ addOrderByArrayPositionTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, values: ArgsType, arrayType?: string): this;
16
17
  }
17
18
  declare module 'typeorm/query-builder/SelectQueryBuilder' {
18
19
  interface SelectQueryBuilder<Entity extends ObjectLiteral> extends TypedOrderByArrayPositionMethods<Entity> {
@@ -9,8 +9,16 @@ const order_utils_1 = require("../../../utils/order.utils");
9
9
  // patching
10
10
  const createOrderByArrayPositionTypedMethod = (replace) => function (selection, values, arrayType) {
11
11
  const methodName = replace ? 'orderByArrayPositionTyped' : 'addOrderByArrayPositionTyped';
12
- const column = (0, query_builder_utils_1.getTypedSingleColumnKey)(this, selection, methodName);
13
- return (0, order_utils_1.attachOrderByArrayPosition)(this, column, values, arrayType, replace);
12
+ // a path into a JSON column is cast to the type of the values, as typed where methods do it,
13
+ // so a number in the JSON is compared as a number, not as its text
14
+ const value = Array.isArray(values) ? values.find((candidate) => candidate != null) : undefined;
15
+ const column = (0, query_builder_utils_1.getTypedSingleColumnKey)(this, selection, methodName, { value });
16
+ const jsonType = typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : undefined;
17
+ // a JSON value of another type, a "n/a" among numbers, would fail the cast: it goes last instead
18
+ const key = jsonType && (0, query_builder_utils_1.isTypedJsonPath)(this, selection)
19
+ ? `CASE WHEN jsonb_typeof(CAST(${(0, query_builder_utils_1.getTypedSingleColumnKey)(this, selection, methodName, { accessor: 'json' })} AS jsonb)) = '${jsonType}' THEN ${column} END`
20
+ : column;
21
+ return (0, order_utils_1.attachOrderByArrayPosition)(this, key, values, arrayType, replace);
14
22
  };
15
23
  const extension = {
16
24
  prototype: {
@@ -2,6 +2,7 @@ import { ObjectLiteral } from 'typeorm';
2
2
  import { DeepUnwrapArray, ProxyColumnValueType } from '../../../types/modules/proxy-callback.types';
3
3
  import { KeyHolder } from '../../../utils/proxy-key.utils';
4
4
  import type { TypedOrderByOptions } from '../../../types/extensions/typed-order-by.types';
5
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
5
6
  declare module 'typeorm/query-builder/SelectQueryBuilder' {
6
7
  interface SelectQueryBuilder<Entity extends ObjectLiteral> {
7
8
  /**
@@ -9,10 +10,10 @@ declare module 'typeorm/query-builder/SelectQueryBuilder' {
9
10
  * If you had previously ORDER BY expression defined,
10
11
  * calling this function will override previously set ORDER BY conditions.
11
12
  */
12
- orderByTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType | KeyHolder, order?: 'ASC' | 'DESC', nulls?: 'NULLS FIRST' | 'NULLS LAST', options?: TypedOrderByOptions): SelectQueryBuilder<Entity>;
13
+ orderByTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType | KeyHolder, order?: 'ASC' | 'DESC', nulls?: 'NULLS FIRST' | 'NULLS LAST', options?: TypedOrderByOptions): SelectQueryBuilder<Entity>;
13
14
  /**
14
15
  * Adds ORDER BY condition in the query builder.
15
16
  */
16
- addOrderByTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType | KeyHolder, order?: 'ASC' | 'DESC', nulls?: 'NULLS FIRST' | 'NULLS LAST', options?: TypedOrderByOptions): SelectQueryBuilder<Entity>;
17
+ addOrderByTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType | KeyHolder, order?: 'ASC' | 'DESC', nulls?: 'NULLS FIRST' | 'NULLS LAST', options?: TypedOrderByOptions): SelectQueryBuilder<Entity>;
17
18
  }
18
19
  }
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const typeorm_1 = require("typeorm");
4
4
  const proxy_key_utils_1 = require("../../../utils/proxy-key.utils");
5
5
  const query_builder_utils_1 = require("../../../utils/query-builder.utils");
6
+ const sql_utils_1 = require("../../../utils/sql.utils");
6
7
  // patching and implementation
7
8
  typeorm_1.SelectQueryBuilder.prototype.orderByTyped = function (selection, order, nulls, options) {
8
9
  if (selection instanceof proxy_key_utils_1.KeyHolder) {
9
- return this.orderBy(selection.toSql(undefined, options === null || options === void 0 ? void 0 : options.useQuotes), order, nulls);
10
+ return this.orderBy(selection.toSql(undefined, options === null || options === void 0 ? void 0 : options.useQuotes, (0, sql_utils_1.getDriverType)(this)), order, nulls);
10
11
  }
11
12
  if (typeof selection === 'function') {
12
13
  const key = (0, query_builder_utils_1.getTypedSelectionKey)(this, selection, options === null || options === void 0 ? void 0 : options.useQuotes);
@@ -16,7 +17,7 @@ typeorm_1.SelectQueryBuilder.prototype.orderByTyped = function (selection, order
16
17
  };
17
18
  typeorm_1.SelectQueryBuilder.prototype.addOrderByTyped = function (selection, order, nulls, options) {
18
19
  if (selection instanceof proxy_key_utils_1.KeyHolder) {
19
- return this.addOrderBy(selection.toSql(undefined, options === null || options === void 0 ? void 0 : options.useQuotes), order, nulls);
20
+ return this.addOrderBy(selection.toSql(undefined, options === null || options === void 0 ? void 0 : options.useQuotes, (0, sql_utils_1.getDriverType)(this)), order, nulls);
20
21
  }
21
22
  if (typeof selection === 'function') {
22
23
  const key = (0, query_builder_utils_1.getTypedSelectionKey)(this, selection, options === null || options === void 0 ? void 0 : options.useQuotes);
@@ -0,0 +1,25 @@
1
+ import { ObjectLiteral } from 'typeorm';
2
+ import type { WithTypedRoot } from '../../types/modules/typed-root.types';
3
+ type KnownEntity<Entity> = 0 extends 1 & Entity ? ObjectLiteral : Entity;
4
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
5
+ interface SelectQueryBuilder<Entity extends ObjectLiteral> {
6
+ /**
7
+ * Sets the root of the typed callbacks of the calls that follow, instead of passing it to each of them:
8
+ * the aliases of the query and their entities.
9
+ *
10
+ * Type-only: returns the builder itself. Call it once; a second call merges the roots.
11
+ *
12
+ * @example
13
+ * type Joins = { checkin: CheckIn; event: Event };
14
+ *
15
+ * checkInRepository
16
+ * .createQueryBuilder('checkin')
17
+ * .innerJoin('checkin.event', 'event')
18
+ * .typed<Joins>()
19
+ * .selectTyped((q) => q.checkin.customerId, 'customerId')
20
+ * .whereTyped((q) => q.event.eventType, '=', type) // instead of whereTyped<Joins>(…)
21
+ */
22
+ typed<Root extends ObjectLiteral>(): SelectQueryBuilder<WithTypedRoot<KnownEntity<Entity>, Root>>;
23
+ }
24
+ }
25
+ export {};
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typeorm_1 = require("typeorm");
4
+ const prototype_utils_1 = require("../../utils/prototype.utils");
5
+ // patching
6
+ const extension = {
7
+ prototype: {
8
+ typed() {
9
+ return this;
10
+ },
11
+ },
12
+ };
13
+ (0, prototype_utils_1.patchPrototype)(typeorm_1.SelectQueryBuilder, extension);
@@ -1,13 +1,14 @@
1
1
  import { ObjectLiteral } from 'typeorm';
2
2
  import { KeyProxyCallback } from '../../../types/modules/proxy-callback.types';
3
3
  import { KeyHolder } from '../../../utils/proxy-key.utils';
4
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
4
5
  declare module 'typeorm/query-builder/SelectQueryBuilder' {
5
6
  interface SelectQueryBuilder<Entity> {
6
7
  /**
7
8
  * Creates SELECT query.
8
9
  * Replaces all previous selections if they exist.
9
10
  */
10
- selectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: KeyProxyCallback<Type>, selectionAliasName?: string, useQuotes?: boolean): SelectQueryBuilder<Entity>;
11
+ selectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: KeyProxyCallback<Type>, selectionAliasName?: string, useQuotes?: boolean): SelectQueryBuilder<Entity>;
11
12
  /**
12
13
  * Creates SELECT query and selects given data.
13
14
  * Replaces all previous selections if they exist.
@@ -17,11 +18,11 @@ declare module 'typeorm/query-builder/SelectQueryBuilder' {
17
18
  * Creates SELECT query and selects given data.
18
19
  * Replaces all previous selections if they exist.
19
20
  */
20
- selectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>, useQuotes?: boolean): SelectQueryBuilder<Entity>;
21
+ selectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>, useQuotes?: boolean): SelectQueryBuilder<Entity>;
21
22
  /**
22
23
  * Adds new selection to the SELECT query.
23
24
  */
24
- addSelectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: KeyProxyCallback<Type>, selectionAliasName?: string, useQuotes?: boolean): SelectQueryBuilder<Entity>;
25
+ addSelectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: KeyProxyCallback<Type>, selectionAliasName?: string, useQuotes?: boolean): SelectQueryBuilder<Entity>;
25
26
  /**
26
27
  * Adds new selection to the SELECT query.
27
28
  */
@@ -29,6 +30,6 @@ declare module 'typeorm/query-builder/SelectQueryBuilder' {
29
30
  /**
30
31
  * Adds new selection to the SELECT query.
31
32
  */
32
- addSelectTyped<Type extends ObjectLiteral = Entity>(this: SelectQueryBuilder<Entity>, selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>, useQuotes?: boolean): SelectQueryBuilder<Entity>;
33
+ addSelectTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(this: SelectQueryBuilder<Entity>, selection: string[] | KeyHolder[] | Array<KeyProxyCallback<Type>>, useQuotes?: boolean): SelectQueryBuilder<Entity>;
33
34
  }
34
35
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const typeorm_1 = require("typeorm");
4
4
  const proxy_key_utils_1 = require("../../../utils/proxy-key.utils");
5
5
  const query_builder_utils_1 = require("../../../utils/query-builder.utils");
6
+ const sql_utils_1 = require("../../../utils/sql.utils");
6
7
  const prototype_utils_1 = require("../../../utils/prototype.utils");
7
8
  // patching
8
9
  const extension = {
@@ -23,11 +24,11 @@ const extension = {
23
24
  // implementation
24
25
  const attachSelectMethod = (query, method, selection, selectionAliasName, useQuotes) => {
25
26
  if (selection instanceof proxy_key_utils_1.KeyHolder) {
26
- return query[method](selection.toSql(undefined, useQuotes), selectionAliasName);
27
+ return query[method](selection.toSql(undefined, useQuotes, (0, sql_utils_1.getDriverType)(query)), selectionAliasName);
27
28
  }
28
29
  if (Array.isArray(selection)) {
29
30
  const arrayOfKeys = selection.flatMap((select) => select instanceof proxy_key_utils_1.KeyHolder
30
- ? (0, proxy_key_utils_1.getSqlKeyFromProxyCallback)(select, () => query.alias, useQuotes)
31
+ ? (0, proxy_key_utils_1.getSqlKeyFromProxyCallback)(select, () => query.alias, useQuotes, (0, sql_utils_1.getDriverType)(query))
31
32
  : (0, query_builder_utils_1.getTypedSelectionKey)(query, select, useQuotes));
32
33
  return query[method](arrayOfKeys);
33
34
  }
@@ -3,6 +3,7 @@ import { ObjectLiteral } from 'typeorm';
3
3
  import { DeepUnwrapArray, ProxyColumnValueType } from '../../../types/modules/proxy-callback.types';
4
4
  import type { PeriodFilter } from '../../../types/interfaces/period.interface';
5
5
  import type { ApplyPeriodOptions } from '../../../types/extensions/period.types';
6
+ import type { TypedRoot } from '../../../types/modules/typed-root.types';
6
7
  export interface TypedPeriodFilterMethods<Entity extends ObjectLiteral> {
7
8
  /**
8
9
  * Adds AND WHERE conditions for a period on an entity property:
@@ -11,7 +12,7 @@ export interface TypedPeriodFilterMethods<Entity extends ObjectLiteral> {
11
12
  * Both ends are inclusive unless `options.includeFrom` / `options.includeTo` is `false`.
12
13
  * A date-only string (`'2024-01-31'`) stands for the whole day: `periodTo: '2024-01-31'` → `column < '2024-02-01'`.
13
14
  */
14
- applyPeriodFilterTyped<Type extends ObjectLiteral = Entity>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, periodFilter: PeriodFilter | null | undefined, options?: ApplyPeriodOptions): this;
15
+ applyPeriodFilterTyped<Type extends ObjectLiteral = TypedRoot<Entity>>(selection: (proxy: DeepUnwrapArray<Type>) => ProxyColumnValueType, periodFilter: PeriodFilter | null | undefined, options?: ApplyPeriodOptions): this;
15
16
  }
16
17
  declare module 'typeorm/query-builder/WhereExpressionBuilder' {
17
18
  interface WhereExpressionBuilder extends TypedPeriodFilterMethods<ObjectLiteral> {