typeorm-extensions 1.2.0

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 (31) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +12 -0
  3. package/README.md +46 -0
  4. package/package.json +33 -0
  5. package/src/constants/index.ts +9 -0
  6. package/src/extensions/get-many-with-totals.extension.ts +62 -0
  7. package/src/extensions/index.ts +4 -0
  8. package/src/extensions/ordering.extension.ts +123 -0
  9. package/src/extensions/pagination.extension.ts +35 -0
  10. package/src/extensions/typed/index.ts +12 -0
  11. package/src/extensions/typed/typed-distinct/typed-distinct.extension.ts +38 -0
  12. package/src/extensions/typed/typed-joins/typed-joins.extension.ts +141 -0
  13. package/src/extensions/typed/typed-order-by/typed-order-by.extension.ts +73 -0
  14. package/src/extensions/typed/typed-select/typed-select.extension.ts +124 -0
  15. package/src/extensions/typed/typed-where/typed-where.extension.ts +268 -0
  16. package/src/extensions/typed/typeorm-querybuilder.types.ts +75 -0
  17. package/src/extensions/typed/typeorm.types.ts +30 -0
  18. package/src/index.ts +3 -0
  19. package/src/types/interfaces/index.ts +2 -0
  20. package/src/types/interfaces/ordering.interface.ts +21 -0
  21. package/src/types/interfaces/pagination.interface.ts +8 -0
  22. package/src/types/modules/column.types.ts +5 -0
  23. package/src/types/modules/proxy-types/proxy-callback.types.ts +11 -0
  24. package/src/types/modules/relations.types.ts +34 -0
  25. package/src/types/util-types/index.ts +8 -0
  26. package/src/utils/common.utils.ts +2 -0
  27. package/src/utils/identifier.utils.ts +60 -0
  28. package/src/utils/pagination.utils.ts +17 -0
  29. package/src/utils/proxy-key.utils.ts +133 -0
  30. package/src/utils/sql.utils.ts +24 -0
  31. package/tsconfig.json +109 -0
package/.eslintignore ADDED
@@ -0,0 +1,2 @@
1
+ node_modules
2
+ dist
package/.eslintrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "root": true,
3
+ "parser": "@typescript-eslint/parser",
4
+ "plugins": [
5
+ "@typescript-eslint"
6
+ ],
7
+ "extends": [
8
+ "eslint:recommended",
9
+ "plugin:@typescript-eslint/eslint-recommended",
10
+ "plugin:@typescript-eslint/recommended"
11
+ ]
12
+ }
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # TypeORM Extensions
2
+
3
+ [![Build Status](https://travis-ci.org/your-username/typeorm-extensions.svg?branch=main)](https://travis-ci.org/your-username/typeorm-extensions)
4
+ [![npm version](https://badge.fury.io/js/typeorm-extensions.svg)](https://badge.fury.io/js/typeorm-extensions)
5
+
6
+ ## Description
7
+
8
+ TypeORM Extensions is a library that provides additional functionality and extensions for the TypeORM QueryBuilder. It aims to simplify common tasks and enhance the capabilities of TypeORM.
9
+
10
+ ## Features
11
+
12
+ - Simplicity: applying pagination and ordering to queries is as simple as calling a method.
13
+ - Type Safety: the library is written in TypeScript and provides type-safe QueryBuilder methods based on Entity metadata.
14
+ - Flexibility: the library is designed to be flexible and can be used with any TypeORM entity.
15
+
16
+ ## Installation
17
+
18
+ To install `typeorm-extensions`:
19
+
20
+ Npm:
21
+ ```bash
22
+ npm install typeorm-extensions
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```typescript
28
+ import { createQueryBuilder } from 'typeorm';
29
+ import 'typeorm-extensions'; // Import the library root to extend the QueryBuilder with all extensions
30
+
31
+ // Or init specific extension: import from 'typeorm-extensions/dist/extensions/pagination.extension';
32
+
33
+ const query = createQueryBuilder()
34
+ .from(User, 'user')
35
+ .selectTyped(user => ([
36
+ id: user.id,
37
+ name: user.name,
38
+ email: user.email,
39
+ ]))
40
+ .orderTyped(user => user.createdAt, 'ASC')
41
+ .applyPagination({ page: 1, pageSize: 10 });
42
+ ```
43
+
44
+ ## Documentation
45
+
46
+ For more information, please refer to the [documentation](https://koenigstag.github.io/typeorm-extensions).
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "typeorm-extensions",
3
+ "version": "1.2.0",
4
+ "description": "typeorm commonly used extensions",
5
+ "main": "./dist/index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/koenigstag/typeorm-extensions.git"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc -p .",
12
+ "lint": "eslint . --ext .ts",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": [
16
+ "typeorm",
17
+ "extension",
18
+ "extensions",
19
+ "util",
20
+ "utils"
21
+ ],
22
+ "author": "koenigstag",
23
+ "license": "ISC",
24
+ "dependencies": {
25
+ "typeorm": "^0.3.20"
26
+ },
27
+ "devDependencies": {
28
+ "@typescript-eslint/eslint-plugin": "^7.1.1",
29
+ "@typescript-eslint/parser": "^7.1.1",
30
+ "eslint": "^8.57.0",
31
+ "typescript": "5.3"
32
+ }
33
+ }
@@ -0,0 +1,9 @@
1
+ export const defaultPageSize = 10;
2
+
3
+ export const defaultUseTakeAndSkip = true;
4
+
5
+ export const defaultUseDoubleQuotes = false;
6
+
7
+ export const defaultOrderDirection = 'ASC';
8
+
9
+ export const defaultNullsOrder = undefined;
@@ -0,0 +1,62 @@
1
+ import { SelectQueryBuilder } from 'typeorm/query-builder/SelectQueryBuilder';
2
+ import { PaginationFilter } from '../types/interfaces/pagination.interface';
3
+ import { getLimitAndOffset } from '../utils/pagination.utils';
4
+ import { ApplyPaginationOptions } from './pagination.extension';
5
+
6
+ export type GetManyWithTotalsOptions = {
7
+ disableTotalsCalculation?: boolean;
8
+ loadAll?: boolean;
9
+ };
10
+
11
+ export interface ListWithTotals<Entity> {
12
+ list: Entity[];
13
+ totalCount: number | null;
14
+ limit: number | null;
15
+ offset: number | null;
16
+ }
17
+
18
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
19
+ interface SelectQueryBuilder<Entity> {
20
+ getManyWithTotals(
21
+ paginationFilter: PaginationFilter,
22
+ options?: GetManyWithTotalsOptions
23
+ ): Promise<ListWithTotals<Entity>>;
24
+ }
25
+ }
26
+
27
+ SelectQueryBuilder.prototype.getManyWithTotals = async function <Entity>(
28
+ paginationFilter: PaginationFilter,
29
+ options?: GetManyWithTotalsOptions & ApplyPaginationOptions
30
+ ): Promise<ListWithTotals<Entity>> {
31
+ const { disableTotalsCalculation = false, loadAll = false } = options || {};
32
+
33
+ const { limit, offset } = loadAll
34
+ ? { limit: null, offset: null }
35
+ : getLimitAndOffset(paginationFilter);
36
+
37
+ const requests = [];
38
+
39
+ if (!disableTotalsCalculation) {
40
+ requests[0] = this.getCount();
41
+ } else {
42
+ requests[0] = Promise.resolve(null);
43
+ }
44
+
45
+ if (loadAll) {
46
+ requests[1] = this.getMany();
47
+ } else {
48
+ requests[1] = this.applyPaginationFilter(paginationFilter).getMany();
49
+ }
50
+
51
+ const [totalCount, list] = (await Promise.all(requests)) as [
52
+ number | null,
53
+ Entity[]
54
+ ];
55
+
56
+ return {
57
+ list,
58
+ totalCount: totalCount,
59
+ limit,
60
+ offset,
61
+ };
62
+ };
@@ -0,0 +1,4 @@
1
+ export * from './get-many-with-totals.extension';
2
+ export * from './ordering.extension';
3
+ export * from './pagination.extension';
4
+ export * from './typed';
@@ -0,0 +1,123 @@
1
+ import { SelectQueryBuilder } from 'typeorm/query-builder/SelectQueryBuilder';
2
+ import type {
3
+ OrderParam,
4
+ OrderFilter,
5
+ OrderType,
6
+ } from '../types/interfaces/ordering.interface';
7
+ import {
8
+ defaultNullsOrder,
9
+ defaultOrderDirection,
10
+ defaultUseDoubleQuotes,
11
+ } from '../constants';
12
+ import { ObjectLiteral } from 'typeorm';
13
+ import { isNil } from '../utils/common.utils';
14
+ import { Identifier } from '../utils/identifier.utils';
15
+
16
+ const alwaysAliasWhiteList = [
17
+ 'id',
18
+ 'createdAt',
19
+ 'created_at',
20
+ 'updatedAt',
21
+ 'updated_at',
22
+ 'deletedAt',
23
+ 'deleted_at',
24
+ ];
25
+
26
+ export type ApplyOrderOptions = {
27
+ useDoubleQuotes?: boolean;
28
+ alias?: string;
29
+ alwaysAliasFields?: string[];
30
+ resetPreviousOrder?: boolean;
31
+ };
32
+
33
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
34
+ interface SelectQueryBuilder<Entity> {
35
+ applyOrder<OrderEntity>(
36
+ orderBy: OrderParam<OrderEntity>,
37
+ options?: ApplyOrderOptions
38
+ ): SelectQueryBuilder<Entity>;
39
+ applyOrderFilter<OrderEntity>(
40
+ orderFilter: OrderFilter<OrderEntity>,
41
+ options?: ApplyOrderOptions
42
+ ): SelectQueryBuilder<Entity>;
43
+ }
44
+ }
45
+
46
+ SelectQueryBuilder.prototype.applyOrder = function <
47
+ Entity extends ObjectLiteral,
48
+ OrderEntity
49
+ >(
50
+ orderBy: OrderParam<OrderEntity>,
51
+ options?: ApplyOrderOptions
52
+ ): SelectQueryBuilder<Entity> {
53
+ const { resetPreviousOrder = false } = options ?? {};
54
+
55
+ const orderOption = getOrderOption(orderBy, this.alias, options);
56
+
57
+ const query = resetPreviousOrder ? this.orderBy() : this;
58
+
59
+ return query.addOrderBy(
60
+ orderOption.selector,
61
+ orderOption.order,
62
+ orderOption.nulls
63
+ );
64
+ };
65
+
66
+ SelectQueryBuilder.prototype.applyOrderFilter = function <
67
+ Entity extends ObjectLiteral,
68
+ OrderEntity
69
+ >(
70
+ orderFilter: OrderFilter<OrderEntity>,
71
+ options?: ApplyOrderOptions
72
+ ): SelectQueryBuilder<Entity> {
73
+ if (!isNil(orderFilter?.orderBy)) {
74
+ return orderFilter.orderBy!.reduce(
75
+ (acc, order, index) =>
76
+ acc.applyOrder(order, {
77
+ ...options,
78
+ resetPreviousOrder: index === 0 ? options?.resetPreviousOrder : false,
79
+ }),
80
+ this as SelectQueryBuilder<Entity>
81
+ );
82
+ }
83
+
84
+ return this;
85
+ };
86
+
87
+ export const getOrderOption = <OrderEntity>(
88
+ orderBy: OrderParam<OrderEntity>,
89
+ defaultAlias: string,
90
+ options?: ApplyOrderOptions
91
+ ): OrderType => {
92
+ const {
93
+ useDoubleQuotes = defaultUseDoubleQuotes,
94
+ alias: customAlias,
95
+ alwaysAliasFields = alwaysAliasWhiteList,
96
+ } = options ?? {};
97
+ const {
98
+ field,
99
+ direction = defaultOrderDirection,
100
+ nulls: nullsOrder = defaultNullsOrder,
101
+ } = orderBy;
102
+
103
+ const alias =
104
+ customAlias ??
105
+ (alwaysAliasFields.includes(field as string) ? defaultAlias : undefined);
106
+
107
+ const identifier = new Identifier(field, alias, useDoubleQuotes);
108
+
109
+ const selector = identifier.fieldIdentifier();
110
+ const order = direction.toUpperCase() as 'ASC' | 'DESC';
111
+
112
+ const nulls = nullsOrder
113
+ ? (`NULLS ${nullsOrder.toUpperCase()}` as 'NULLS LAST' | 'NULLS FIRST')
114
+ : undefined;
115
+
116
+ return {
117
+ selector,
118
+ order,
119
+ nulls,
120
+ };
121
+ };
122
+
123
+ export {};
@@ -0,0 +1,35 @@
1
+ import { SelectQueryBuilder } from 'typeorm/query-builder/SelectQueryBuilder';
2
+ import type { PaginationFilter } from '../types/interfaces/pagination.interface';
3
+ import { defaultUseTakeAndSkip } from '../constants';
4
+ import { getLimitAndOffset } from '../utils/pagination.utils';
5
+ import { ObjectLiteral } from 'typeorm';
6
+
7
+ export type ApplyPaginationOptions = {
8
+ useTakeAndSkip?: boolean;
9
+ };
10
+
11
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
12
+ interface SelectQueryBuilder<Entity> {
13
+ applyPaginationFilter(
14
+ paginationFilter: PaginationFilter,
15
+ options?: ApplyPaginationOptions
16
+ ): SelectQueryBuilder<Entity>;
17
+ }
18
+ }
19
+
20
+ SelectQueryBuilder.prototype.applyPaginationFilter = function <Entity extends ObjectLiteral>(
21
+ paginationFilter: PaginationFilter,
22
+ options?: ApplyPaginationOptions
23
+ ): SelectQueryBuilder<Entity> {
24
+ const { useTakeAndSkip = defaultUseTakeAndSkip } = options || {};
25
+
26
+ const { limit, offset } = getLimitAndOffset(paginationFilter);
27
+
28
+ if (useTakeAndSkip) {
29
+ return this.take(limit).skip(offset);
30
+ }
31
+
32
+ return this.limit(limit).offset(offset);
33
+ };
34
+
35
+ export {};
@@ -0,0 +1,12 @@
1
+ //Extensions
2
+ export * from './typed-distinct/typed-distinct.extension';
3
+ // export * from './typed/typed-group-by/typed-group-by.extension';
4
+ // export * from './typed/typed-having/typed-having.extension';
5
+ export * from './typed-joins/typed-joins.extension';
6
+ export * from './typed-order-by/typed-order-by.extension';
7
+ export * from './typed-select/typed-select.extension';
8
+ export * from './typed-where/typed-where.extension';
9
+
10
+ // Types
11
+ export * from './typeorm-querybuilder.types';
12
+ export * from './typeorm.types';
@@ -0,0 +1,38 @@
1
+ import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
2
+ import { ColumnValueType } from '../typeorm.types';
3
+ import { getSqlKey } from '../../../utils/proxy-key.utils';
4
+
5
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
6
+ interface SelectQueryBuilder<Entity> {
7
+ /**
8
+ * Sets the distinct on clause for Postgres.
9
+ */
10
+ distinctOnTyped<Type extends ObjectLiteral = Entity>(
11
+ this: SelectQueryBuilder<Entity>,
12
+ ...distinctOn: Array<(proxy: Type) => ColumnValueType>
13
+ ): SelectQueryBuilder<Entity>;
14
+ /**
15
+ * Sets the distinct on clause for Postgres.
16
+ */
17
+ distinctOnTyped<Type extends ObjectLiteral = Entity>(
18
+ this: SelectQueryBuilder<Entity>,
19
+ distinctOn: (proxy: Type) => Array<ColumnValueType>
20
+ ): SelectQueryBuilder<Entity>;
21
+ }
22
+ }
23
+
24
+ SelectQueryBuilder.prototype.distinctOnTyped = function <
25
+ Entity extends ObjectLiteral,
26
+ Type extends ObjectLiteral = Entity
27
+ >(
28
+ this: SelectQueryBuilder<Entity>,
29
+ ...distinctOn: Array<(proxy: Type) => ColumnValueType | Array<ColumnValueType>>
30
+ ): SelectQueryBuilder<Entity> {
31
+ if (Array.isArray(distinctOn) && distinctOn.length) {
32
+ const keys = distinctOn.map((callback) => getSqlKey<Type>(callback, this.alias)).flat(3);
33
+
34
+ return this.distinctOn(keys as string[]);
35
+ }
36
+
37
+ return this;
38
+ };
@@ -0,0 +1,141 @@
1
+ import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
2
+ import { RelationalKeyProxyCallback } from '../typeorm-querybuilder.types';
3
+ import { getSqlKey } from '../../../utils/proxy-key.utils';
4
+
5
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
6
+ interface SelectQueryBuilder<Entity> {
7
+ leftJoinTyped<Type extends ObjectLiteral = Entity>(
8
+ this: SelectQueryBuilder<Entity>,
9
+ selection: RelationalKeyProxyCallback<Type>,
10
+ alias: string,
11
+ condition?: string,
12
+ parameters?: ObjectLiteral
13
+ ): SelectQueryBuilder<Entity>;
14
+ innerJoinTyped<Type extends ObjectLiteral = Entity>(
15
+ this: SelectQueryBuilder<Entity>,
16
+ selection: RelationalKeyProxyCallback<Type>,
17
+ alias: string,
18
+ condition?: string,
19
+ parameters?: ObjectLiteral
20
+ ): SelectQueryBuilder<Entity>;
21
+
22
+ leftJoinAndSelectTyped<Type extends ObjectLiteral = Entity>(
23
+ this: SelectQueryBuilder<Entity>,
24
+ selection: RelationalKeyProxyCallback<Type>,
25
+ alias: string,
26
+ condition?: string,
27
+ parameters?: ObjectLiteral
28
+ ): SelectQueryBuilder<Entity>;
29
+ innerJoinAndSelectTyped<Type extends ObjectLiteral = Entity>(
30
+ this: SelectQueryBuilder<Entity>,
31
+ selection: RelationalKeyProxyCallback<Type>,
32
+ alias: string,
33
+ condition?: string,
34
+ parameters?: ObjectLiteral
35
+ ): SelectQueryBuilder<Entity>;
36
+ }
37
+ }
38
+
39
+ SelectQueryBuilder.prototype.leftJoinTyped = function <
40
+ Entity extends ObjectLiteral,
41
+ Type extends ObjectLiteral = Entity
42
+ >(
43
+ this: SelectQueryBuilder<Entity>,
44
+ selection: RelationalKeyProxyCallback<Type>,
45
+ alias: string,
46
+ condition?: string,
47
+ parameters?: ObjectLiteral
48
+ ) {
49
+ if (typeof selection === 'function') {
50
+ return addJoin(this, 'leftJoin', selection, alias, condition, parameters);
51
+ }
52
+
53
+ return this;
54
+ };
55
+
56
+ SelectQueryBuilder.prototype.innerJoinTyped = function <
57
+ Entity extends ObjectLiteral,
58
+ Type extends ObjectLiteral = Entity
59
+ >(
60
+ this: SelectQueryBuilder<Entity>,
61
+ selection: RelationalKeyProxyCallback<Type>,
62
+ alias: string,
63
+ condition?: string,
64
+ parameters?: ObjectLiteral
65
+ ) {
66
+ if (typeof selection === 'function') {
67
+ return addJoin(this, 'innerJoin', selection, alias, condition, parameters);
68
+ }
69
+
70
+ return this;
71
+ };
72
+
73
+ SelectQueryBuilder.prototype.leftJoinAndSelectTyped = function <
74
+ Entity extends ObjectLiteral,
75
+ Type extends ObjectLiteral = Entity
76
+ >(
77
+ this: SelectQueryBuilder<Entity>,
78
+ selection: RelationalKeyProxyCallback<Type>,
79
+ alias: string,
80
+ condition?: string,
81
+ parameters?: ObjectLiteral
82
+ ) {
83
+ if (typeof selection === 'function') {
84
+ return addJoin(
85
+ this,
86
+ 'leftJoinAndSelect',
87
+ selection,
88
+ alias,
89
+ condition,
90
+ parameters
91
+ );
92
+ }
93
+
94
+ return this;
95
+ };
96
+
97
+ SelectQueryBuilder.prototype.innerJoinAndSelectTyped = function <
98
+ Entity extends ObjectLiteral,
99
+ Type extends ObjectLiteral = Entity
100
+ >(
101
+ this: SelectQueryBuilder<Entity>,
102
+ selection: RelationalKeyProxyCallback<Type>,
103
+ alias: string,
104
+ condition?: string,
105
+ parameters?: ObjectLiteral
106
+ ) {
107
+ if (typeof selection === 'function') {
108
+ return addJoin(
109
+ this,
110
+ 'innerJoinAndSelect',
111
+ selection,
112
+ alias,
113
+ condition,
114
+ parameters
115
+ );
116
+ }
117
+
118
+ return this;
119
+ };
120
+
121
+ type JoinMethod =
122
+ | 'leftJoin'
123
+ | 'innerJoin'
124
+ | 'leftJoinAndSelect'
125
+ | 'innerJoinAndSelect';
126
+
127
+ function addJoin<
128
+ Entity extends ObjectLiteral,
129
+ Type extends ObjectLiteral = Entity
130
+ >(
131
+ query: SelectQueryBuilder<Entity>,
132
+ method: JoinMethod,
133
+ selection: RelationalKeyProxyCallback<Type>,
134
+ alias: string,
135
+ condition?: string,
136
+ parameters?: ObjectLiteral
137
+ ) {
138
+ const key = getSqlKey<Type>(selection, query.alias) as string;
139
+
140
+ return query[method](key, alias, condition, parameters);
141
+ }
@@ -0,0 +1,73 @@
1
+ import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
2
+ import { ColumnValueType } from '../typeorm.types';
3
+ import { KeyHolder } from '../typeorm-querybuilder.types';
4
+ import { getSqlKey } from '../../../utils/proxy-key.utils';
5
+
6
+ declare module 'typeorm/query-builder/SelectQueryBuilder' {
7
+ interface SelectQueryBuilder<Entity> {
8
+ /**
9
+ * Sets ORDER BY condition in the query builder.
10
+ * If you had previously ORDER BY expression defined,
11
+ * calling this function will override previously set ORDER BY conditions.
12
+ */
13
+ orderByTyped<Type extends ObjectLiteral = Entity>(
14
+ this: SelectQueryBuilder<Entity>,
15
+ selection: (proxy: Type) => ColumnValueType | KeyHolder,
16
+ order?: 'ASC' | 'DESC',
17
+ nulls?: 'NULLS FIRST' | 'NULLS LAST'
18
+ ): SelectQueryBuilder<Entity>;
19
+ /**
20
+ * Adds ORDER BY condition in the query builder.
21
+ */
22
+ addOrderByTyped<Type extends ObjectLiteral = Entity>(
23
+ this: SelectQueryBuilder<Entity>,
24
+ selection: (proxy: Type) => ColumnValueType | KeyHolder,
25
+ order?: 'ASC' | 'DESC',
26
+ nulls?: 'NULLS FIRST' | 'NULLS LAST'
27
+ ): SelectQueryBuilder<Entity>;
28
+ }
29
+ }
30
+
31
+ SelectQueryBuilder.prototype.orderByTyped = function <
32
+ Entity extends ObjectLiteral,
33
+ Type extends ObjectLiteral = Entity
34
+ >(
35
+ this: SelectQueryBuilder<Entity>,
36
+ selection?: (proxy: Type) => ColumnValueType | KeyHolder,
37
+ order?: 'ASC' | 'DESC',
38
+ nulls?: 'NULLS FIRST' | 'NULLS LAST'
39
+ ): SelectQueryBuilder<Entity> {
40
+ if (selection instanceof KeyHolder) {
41
+ return this.orderBy(selection.toSql(), order, nulls);
42
+ }
43
+
44
+ if (typeof selection === 'function') {
45
+ const key = getSqlKey<Type>(selection, this.alias) as string;
46
+
47
+ return this.orderBy(key, order, nulls);
48
+ }
49
+
50
+ return this;
51
+ };
52
+
53
+ SelectQueryBuilder.prototype.addOrderByTyped = function <
54
+ Entity extends ObjectLiteral,
55
+ Type extends ObjectLiteral = Entity
56
+ >(
57
+ this: SelectQueryBuilder<Entity>,
58
+ selection?: (proxy: Type) => ColumnValueType | KeyHolder,
59
+ order?: 'ASC' | 'DESC',
60
+ nulls?: 'NULLS FIRST' | 'NULLS LAST'
61
+ ): SelectQueryBuilder<Entity> {
62
+ if (selection instanceof KeyHolder) {
63
+ return this.addOrderBy(selection.toSql(), order, nulls);
64
+ }
65
+
66
+ if (typeof selection === 'function') {
67
+ const key = getSqlKey<Type>(selection, this.alias) as string;
68
+
69
+ return this.addOrderBy(key, order, nulls);
70
+ }
71
+
72
+ return this;
73
+ };