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.
- package/.eslintignore +2 -0
- package/.eslintrc +12 -0
- package/README.md +46 -0
- package/package.json +33 -0
- package/src/constants/index.ts +9 -0
- package/src/extensions/get-many-with-totals.extension.ts +62 -0
- package/src/extensions/index.ts +4 -0
- package/src/extensions/ordering.extension.ts +123 -0
- package/src/extensions/pagination.extension.ts +35 -0
- package/src/extensions/typed/index.ts +12 -0
- package/src/extensions/typed/typed-distinct/typed-distinct.extension.ts +38 -0
- package/src/extensions/typed/typed-joins/typed-joins.extension.ts +141 -0
- package/src/extensions/typed/typed-order-by/typed-order-by.extension.ts +73 -0
- package/src/extensions/typed/typed-select/typed-select.extension.ts +124 -0
- package/src/extensions/typed/typed-where/typed-where.extension.ts +268 -0
- package/src/extensions/typed/typeorm-querybuilder.types.ts +75 -0
- package/src/extensions/typed/typeorm.types.ts +30 -0
- package/src/index.ts +3 -0
- package/src/types/interfaces/index.ts +2 -0
- package/src/types/interfaces/ordering.interface.ts +21 -0
- package/src/types/interfaces/pagination.interface.ts +8 -0
- package/src/types/modules/column.types.ts +5 -0
- package/src/types/modules/proxy-types/proxy-callback.types.ts +11 -0
- package/src/types/modules/relations.types.ts +34 -0
- package/src/types/util-types/index.ts +8 -0
- package/src/utils/common.utils.ts +2 -0
- package/src/utils/identifier.utils.ts +60 -0
- package/src/utils/pagination.utils.ts +17 -0
- package/src/utils/proxy-key.utils.ts +133 -0
- package/src/utils/sql.utils.ts +24 -0
- package/tsconfig.json +109 -0
package/.eslintignore
ADDED
package/.eslintrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# TypeORM Extensions
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/your-username/typeorm-extensions)
|
|
4
|
+
[](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,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,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
|
+
};
|