crud-query-parser 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +37 -11
- package/dist/adapters/typeorm/index.d.mts +104 -10
- package/dist/adapters/typeorm/index.d.ts +104 -10
- package/dist/adapters/typeorm/index.js +1 -1
- package/dist/adapters/typeorm/index.js.map +1 -1
- package/dist/adapters/typeorm/index.mjs +1 -1
- package/dist/adapters/typeorm/index.mjs.map +1 -1
- package/dist/{parsed-request-where.builder-DME55XmN.d.ts → crud-request-where.builder-B5241Aht.d.ts} +7 -7
- package/dist/{parsed-request-where.builder-DRZUAxu4.d.mts → crud-request-where.builder-BwWLx0Bh.d.mts} +7 -7
- package/dist/{crud-request-CvDKp6Iy.d.mts → crud-request-x16CuDRF.d.mts} +1 -0
- package/dist/{crud-request-CvDKp6Iy.d.ts → crud-request-x16CuDRF.d.ts} +1 -0
- package/dist/filters/index.d.mts +11 -2
- package/dist/filters/index.d.ts +11 -2
- package/dist/filters/index.js +1 -1
- package/dist/filters/index.js.map +1 -1
- package/dist/filters/index.mjs +1 -1
- package/dist/filters/index.mjs.map +1 -1
- package/dist/helpers/nestjs/index.d.mts +2 -2
- package/dist/helpers/nestjs/index.d.ts +2 -2
- package/dist/helpers/nestjs/index.js.map +1 -1
- package/dist/helpers/nestjs/index.mjs.map +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/parsers/crud/index.d.mts +34 -9
- package/dist/parsers/crud/index.d.ts +34 -9
- package/dist/parsers/crud/index.js +1 -1
- package/dist/parsers/crud/index.js.map +1 -1
- package/dist/parsers/crud/index.mjs +1 -1
- package/dist/parsers/crud/index.mjs.map +1 -1
- package/dist/{query-adapter-Vebxws3V.d.ts → query-adapter-CEcyFcWr.d.ts} +1 -1
- package/dist/{query-adapter-BliD9hJN.d.mts → query-adapter-CeTK3yxp.d.mts} +1 -1
- package/dist/{request-parser-WaQBZsYG.d.mts → request-parser-BMkszvGr.d.mts} +1 -1
- package/dist/{request-parser-B-fK5GnP.d.ts → request-parser-BxVulcsX.d.ts} +1 -1
- package/package.json +133 -118
package/README.md
CHANGED
@@ -5,14 +5,9 @@ This library parses HTTP requests and converts them to TypeORM query builders, a
|
|
5
5
|
## Install
|
6
6
|
|
7
7
|
```sh
|
8
|
-
npm install
|
8
|
+
npm install crud-query-parser
|
9
9
|
```
|
10
10
|
|
11
|
-
### Other modules
|
12
|
-
|
13
|
-
- `@crud-query-parser/typeorm`: TypeORM adapter
|
14
|
-
- `@crud-query-parser/nestjs`: NestJS utilities
|
15
|
-
|
16
11
|
## Usage
|
17
12
|
|
18
13
|
You have to pick a request parser and a query adapter.
|
@@ -40,12 +35,15 @@ console.log(result);
|
|
40
35
|
|
41
36
|
### CRUD
|
42
37
|
|
43
|
-
|
38
|
+
The CRUD parser is an implementation of the `@nestjsx/crud` [query params format](https://github.com/nestjsx/crud/wiki/Requests#query-params).
|
44
39
|
|
45
40
|
```ts
|
46
41
|
import { CrudRequestParser } from 'crud-query-parser/parsers/crud';
|
47
42
|
|
48
43
|
const parser = new CrudRequestParser();
|
44
|
+
|
45
|
+
// Then, you have to pass a query string object to it
|
46
|
+
// const crudRequest = parser.parse(request.query);
|
49
47
|
```
|
50
48
|
|
51
49
|
## Database adapters
|
@@ -59,7 +57,8 @@ import { TypeormQueryAdapter } from 'crud-query-parser/adapters/typeorm';
|
|
59
57
|
|
60
58
|
const adapter = new TypeormQueryAdapter();
|
61
59
|
|
62
|
-
//
|
60
|
+
// Then, you can pass a query builder to it:
|
61
|
+
// const result = adapter.getMany(repository.createQueryBuilder(), crudRequest);
|
63
62
|
```
|
64
63
|
|
65
64
|
## Helpers
|
@@ -74,15 +73,37 @@ Sample code:
|
|
74
73
|
@Controller('users')
|
75
74
|
export class UserController {
|
76
75
|
|
76
|
+
constructor(
|
77
|
+
private service: UserService,
|
78
|
+
) {}
|
79
|
+
|
77
80
|
@Get()
|
78
|
-
@Crud(CrudRequestParser)
|
79
|
-
public async getMany(@ParseCrudRequest() crudRequest: CrudRequest) {
|
81
|
+
@Crud(CrudRequestParser) // <- You specify which parser to use
|
82
|
+
public async getMany(@ParseCrudRequest() crudRequest: CrudRequest) { // <- The request query will be automatically parsed
|
80
83
|
return this.service.getMany(crudRequest);
|
81
84
|
}
|
82
85
|
|
83
86
|
}
|
84
87
|
```
|
85
88
|
|
89
|
+
```ts
|
90
|
+
@Injectable()
|
91
|
+
export class UserService {
|
92
|
+
|
93
|
+
protected crudAdapter = new TypeormQueryAdapter();
|
94
|
+
|
95
|
+
constructor(
|
96
|
+
@InjectRepository(UserEntity)
|
97
|
+
private repository: Repository<UserEntity>,
|
98
|
+
) {}
|
99
|
+
|
100
|
+
public async getMany(crudRequest: CrudRequest) {
|
101
|
+
return await this.crudAdapter.getMany(this.repository.createQueryBuilder(), crudRequest);
|
102
|
+
}
|
103
|
+
|
104
|
+
}
|
105
|
+
```
|
106
|
+
|
86
107
|
## Filters
|
87
108
|
|
88
109
|
You may need to filter what the user can or cannot query. You can modify the `CrudRequest` object as needed.
|
@@ -94,7 +115,7 @@ There are a few filters provided by the library, which are listed below.
|
|
94
115
|
This filter will add the condition on top of all other where conditions
|
95
116
|
|
96
117
|
```ts
|
97
|
-
import { ensureCondition } from 'crud-query-parser/filters';
|
118
|
+
import { ensureCondition, ensureEqCondition } from 'crud-query-parser/filters';
|
98
119
|
|
99
120
|
// ...
|
100
121
|
|
@@ -103,6 +124,11 @@ crudRequest = ensureCondition(crudRequest, {
|
|
103
124
|
operator: CrudRequestWhereOperator.EQ,
|
104
125
|
value: true,
|
105
126
|
});
|
127
|
+
|
128
|
+
// Alternatively, a shorthand for equals conditions:
|
129
|
+
crudRequest = ensureEqCondition(crudRequest, {
|
130
|
+
isActive: true,
|
131
|
+
});
|
106
132
|
```
|
107
133
|
|
108
134
|
### Ensure page limit
|
@@ -1,11 +1,56 @@
|
|
1
1
|
import { SelectQueryBuilder, ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
|
2
|
-
import {
|
3
|
-
import {
|
2
|
+
import { Alias } from 'typeorm/query-builder/Alias';
|
3
|
+
import { Q as QueryAdapter, G as GetManyResult } from '../../query-adapter-CeTK3yxp.mjs';
|
4
|
+
import { c as CrudRequest, P as ParsedRequestSelect, a as CrudRequestRelation, b as CrudRequestOrder, d as CrudRequestWhere, F as FieldPath, g as CrudRequestWhereField } from '../../crud-request-x16CuDRF.mjs';
|
4
5
|
|
6
|
+
interface TypeOrmQueryAdapterOptions {
|
7
|
+
/**
|
8
|
+
* Whether it will use ILIKE for case-insensitive operations.
|
9
|
+
*
|
10
|
+
* If undefined, it will be enabled by default for postgres and aurora-postgres databases
|
11
|
+
*/
|
12
|
+
ilike?: boolean;
|
13
|
+
/**
|
14
|
+
* What it will do when it finds invalid fields.
|
15
|
+
*
|
16
|
+
* By default, `select` and `order` will ignore invalid fields, and `where` will deny invalid fields.
|
17
|
+
*/
|
18
|
+
invalidFields?: {
|
19
|
+
/**
|
20
|
+
* What it will do when it finds invalid fields in `select`.
|
21
|
+
*
|
22
|
+
* If "ignore", it will remove invalid fields
|
23
|
+
* If "deny", it will throw an exception for invalid fields
|
24
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
25
|
+
* If undefined, it will default to "ignore"
|
26
|
+
*/
|
27
|
+
select?: 'ignore' | 'deny' | 'allow-unsafe';
|
28
|
+
/**
|
29
|
+
* What it will do when it finds invalid fields in `order`.
|
30
|
+
*
|
31
|
+
* If "ignore", it will remove invalid fields
|
32
|
+
* If "deny", it will throw an exception for invalid fields
|
33
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
34
|
+
* If undefined, it will default to "ignore"
|
35
|
+
*/
|
36
|
+
order?: 'ignore' | 'deny' | 'allow-unsafe';
|
37
|
+
/**
|
38
|
+
* What it will do when it finds invalid fields in `order`.
|
39
|
+
*
|
40
|
+
* If "ignore", it will remove invalid fields
|
41
|
+
* If "deny", it will throw an exception for invalid fields
|
42
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
43
|
+
* If undefined, it will default to "deny"
|
44
|
+
*/
|
45
|
+
where?: 'ignore' | 'deny' | 'allow-unsafe';
|
46
|
+
};
|
47
|
+
}
|
5
48
|
/**
|
6
49
|
* Adapts queries to TypeORM query builder object
|
7
50
|
*/
|
8
|
-
declare class
|
51
|
+
declare class TypeOrmQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {
|
52
|
+
private readonly options;
|
53
|
+
constructor(options?: TypeOrmQueryAdapterOptions);
|
9
54
|
/**
|
10
55
|
* @inheritDoc
|
11
56
|
*/
|
@@ -30,38 +75,47 @@ declare class TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any
|
|
30
75
|
*
|
31
76
|
* @param qb The query builder
|
32
77
|
* @param query The parsed query
|
78
|
+
* @param offset The parsed query offset
|
33
79
|
*/
|
34
|
-
protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E>;
|
80
|
+
protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest, offset?: number): SelectQueryBuilder<E>;
|
35
81
|
/**
|
36
82
|
* Adapts a select
|
37
83
|
*
|
38
84
|
* @param qb The query builder
|
85
|
+
* @param alias The base alias
|
39
86
|
* @param select The parsed select fields
|
40
87
|
*/
|
41
|
-
protected adaptSelect<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, select: ParsedRequestSelect): void;
|
88
|
+
protected adaptSelect<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, alias: Alias, select: ParsedRequestSelect): void;
|
42
89
|
/**
|
43
90
|
* Adapts the join relation list
|
44
91
|
*
|
45
92
|
* @param qb The query builder
|
93
|
+
* @param baseAlias The base alias
|
46
94
|
* @param relations The parsed relation list
|
95
|
+
* @param select The parsed select fields
|
47
96
|
*/
|
48
|
-
protected adaptRelations<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, relations: CrudRequestRelation[]): void;
|
97
|
+
protected adaptRelations<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, baseAlias: Alias, relations: CrudRequestRelation[], select: ParsedRequestSelect): void;
|
49
98
|
/**
|
50
99
|
* Adapts the order by list
|
51
100
|
*
|
52
101
|
* @param qb The query builder
|
102
|
+
* @param alias The base alias
|
103
|
+
* @param relations The list of relations
|
53
104
|
* @param ordering The parsed ordering
|
54
105
|
*/
|
55
|
-
protected adaptOrder<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, ordering: CrudRequestOrder[]): void;
|
106
|
+
protected adaptOrder<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, alias: Alias, relations: CrudRequestRelation[], ordering: CrudRequestOrder[]): void;
|
56
107
|
/**
|
57
108
|
* Adapts a where condition
|
58
109
|
*
|
110
|
+
* @param alias The query builder alias
|
111
|
+
* @param relations The list of relations
|
59
112
|
* @param qb The query builder
|
60
113
|
* @param where The quere condition
|
61
114
|
* @param or Whether this where condition is AND/OR
|
62
115
|
* @param params The registered parameter name list
|
116
|
+
* @param isILikeEnabled Whether the ILIKE operator can be used
|
63
117
|
*/
|
64
|
-
protected adaptWhere(qb: WhereExpressionBuilder, where: CrudRequestWhere, or: boolean, params: string[]): void;
|
118
|
+
protected adaptWhere(alias: Alias, relations: CrudRequestRelation[], qb: WhereExpressionBuilder, where: CrudRequestWhere, or: boolean, params: string[], isILikeEnabled: boolean): void;
|
65
119
|
/**
|
66
120
|
* Creates a query parameter name based on a field
|
67
121
|
*
|
@@ -69,16 +123,56 @@ declare class TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any
|
|
69
123
|
* @param field The field path
|
70
124
|
*/
|
71
125
|
protected createParam(paramsDefined: string[], field: string[]): string;
|
126
|
+
/**
|
127
|
+
* Checks whether the field is valid
|
128
|
+
*
|
129
|
+
* @param alias The base alias
|
130
|
+
* @param path The field path
|
131
|
+
* @param source The source where the field validation comes from
|
132
|
+
*/
|
133
|
+
protected validateField(alias: Alias, path: FieldPath, source: 'select' | 'order' | 'where'): boolean;
|
134
|
+
/**
|
135
|
+
* Checks whether the field is valid
|
136
|
+
*
|
137
|
+
* @param alias The base alias
|
138
|
+
* @param path The field path
|
139
|
+
*/
|
140
|
+
protected isFieldValid(alias: Alias, path: FieldPath): boolean;
|
72
141
|
/**
|
73
142
|
* Maps where operators to a pseudo-SQL statement and a parameter map
|
74
143
|
*
|
144
|
+
* @param alias The query builder alias
|
145
|
+
* @param relations The list of relations
|
75
146
|
* @param where The where condition
|
76
147
|
* @param param The parameter name
|
148
|
+
* @param isILikeEnabled Whether the ILIKE operator can be used
|
77
149
|
*/
|
78
|
-
protected mapWhereOperators(where: CrudRequestWhereField, param: string): {
|
150
|
+
protected mapWhereOperators(alias: Alias, relations: CrudRequestRelation[], where: CrudRequestWhereField, param: string, isILikeEnabled: boolean): {
|
79
151
|
where: string;
|
80
152
|
params: ObjectLiteral;
|
81
153
|
};
|
154
|
+
/**
|
155
|
+
* Gets a field alias based on its base path
|
156
|
+
*
|
157
|
+
* @param alias The query main alias
|
158
|
+
* @param relations The relations
|
159
|
+
* @param base The base path
|
160
|
+
*/
|
161
|
+
protected getFieldAlias(alias: Alias, relations: CrudRequestRelation[], base: string[]): string;
|
162
|
+
/**
|
163
|
+
* Creates an ILIKE expression that works on all databases
|
164
|
+
*
|
165
|
+
* @param isILikeEnabled Whether ILIKE is supported
|
166
|
+
* @param field The field name
|
167
|
+
* @param not Whether the expression is inverted
|
168
|
+
*/
|
169
|
+
protected createLowerLike(isILikeEnabled: boolean, field: string, not?: boolean): string;
|
170
|
+
/**
|
171
|
+
* Checks whether ILIKE expressions are available for the current database
|
172
|
+
*
|
173
|
+
* @param qb The query builder
|
174
|
+
*/
|
175
|
+
protected isILikeEnabled(qb: SelectQueryBuilder<any>): boolean;
|
82
176
|
}
|
83
177
|
|
84
|
-
export {
|
178
|
+
export { TypeOrmQueryAdapter, type TypeOrmQueryAdapterOptions };
|
@@ -1,11 +1,56 @@
|
|
1
1
|
import { SelectQueryBuilder, ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
|
2
|
-
import {
|
3
|
-
import {
|
2
|
+
import { Alias } from 'typeorm/query-builder/Alias';
|
3
|
+
import { Q as QueryAdapter, G as GetManyResult } from '../../query-adapter-CEcyFcWr.js';
|
4
|
+
import { c as CrudRequest, P as ParsedRequestSelect, a as CrudRequestRelation, b as CrudRequestOrder, d as CrudRequestWhere, F as FieldPath, g as CrudRequestWhereField } from '../../crud-request-x16CuDRF.js';
|
4
5
|
|
6
|
+
interface TypeOrmQueryAdapterOptions {
|
7
|
+
/**
|
8
|
+
* Whether it will use ILIKE for case-insensitive operations.
|
9
|
+
*
|
10
|
+
* If undefined, it will be enabled by default for postgres and aurora-postgres databases
|
11
|
+
*/
|
12
|
+
ilike?: boolean;
|
13
|
+
/**
|
14
|
+
* What it will do when it finds invalid fields.
|
15
|
+
*
|
16
|
+
* By default, `select` and `order` will ignore invalid fields, and `where` will deny invalid fields.
|
17
|
+
*/
|
18
|
+
invalidFields?: {
|
19
|
+
/**
|
20
|
+
* What it will do when it finds invalid fields in `select`.
|
21
|
+
*
|
22
|
+
* If "ignore", it will remove invalid fields
|
23
|
+
* If "deny", it will throw an exception for invalid fields
|
24
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
25
|
+
* If undefined, it will default to "ignore"
|
26
|
+
*/
|
27
|
+
select?: 'ignore' | 'deny' | 'allow-unsafe';
|
28
|
+
/**
|
29
|
+
* What it will do when it finds invalid fields in `order`.
|
30
|
+
*
|
31
|
+
* If "ignore", it will remove invalid fields
|
32
|
+
* If "deny", it will throw an exception for invalid fields
|
33
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
34
|
+
* If undefined, it will default to "ignore"
|
35
|
+
*/
|
36
|
+
order?: 'ignore' | 'deny' | 'allow-unsafe';
|
37
|
+
/**
|
38
|
+
* What it will do when it finds invalid fields in `order`.
|
39
|
+
*
|
40
|
+
* If "ignore", it will remove invalid fields
|
41
|
+
* If "deny", it will throw an exception for invalid fields
|
42
|
+
* If "allow-unsafe", it will not validate any fields. Unsafe: this can allow SQL injection
|
43
|
+
* If undefined, it will default to "deny"
|
44
|
+
*/
|
45
|
+
where?: 'ignore' | 'deny' | 'allow-unsafe';
|
46
|
+
};
|
47
|
+
}
|
5
48
|
/**
|
6
49
|
* Adapts queries to TypeORM query builder object
|
7
50
|
*/
|
8
|
-
declare class
|
51
|
+
declare class TypeOrmQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {
|
52
|
+
private readonly options;
|
53
|
+
constructor(options?: TypeOrmQueryAdapterOptions);
|
9
54
|
/**
|
10
55
|
* @inheritDoc
|
11
56
|
*/
|
@@ -30,38 +75,47 @@ declare class TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any
|
|
30
75
|
*
|
31
76
|
* @param qb The query builder
|
32
77
|
* @param query The parsed query
|
78
|
+
* @param offset The parsed query offset
|
33
79
|
*/
|
34
|
-
protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E>;
|
80
|
+
protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest, offset?: number): SelectQueryBuilder<E>;
|
35
81
|
/**
|
36
82
|
* Adapts a select
|
37
83
|
*
|
38
84
|
* @param qb The query builder
|
85
|
+
* @param alias The base alias
|
39
86
|
* @param select The parsed select fields
|
40
87
|
*/
|
41
|
-
protected adaptSelect<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, select: ParsedRequestSelect): void;
|
88
|
+
protected adaptSelect<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, alias: Alias, select: ParsedRequestSelect): void;
|
42
89
|
/**
|
43
90
|
* Adapts the join relation list
|
44
91
|
*
|
45
92
|
* @param qb The query builder
|
93
|
+
* @param baseAlias The base alias
|
46
94
|
* @param relations The parsed relation list
|
95
|
+
* @param select The parsed select fields
|
47
96
|
*/
|
48
|
-
protected adaptRelations<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, relations: CrudRequestRelation[]): void;
|
97
|
+
protected adaptRelations<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, baseAlias: Alias, relations: CrudRequestRelation[], select: ParsedRequestSelect): void;
|
49
98
|
/**
|
50
99
|
* Adapts the order by list
|
51
100
|
*
|
52
101
|
* @param qb The query builder
|
102
|
+
* @param alias The base alias
|
103
|
+
* @param relations The list of relations
|
53
104
|
* @param ordering The parsed ordering
|
54
105
|
*/
|
55
|
-
protected adaptOrder<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, ordering: CrudRequestOrder[]): void;
|
106
|
+
protected adaptOrder<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, alias: Alias, relations: CrudRequestRelation[], ordering: CrudRequestOrder[]): void;
|
56
107
|
/**
|
57
108
|
* Adapts a where condition
|
58
109
|
*
|
110
|
+
* @param alias The query builder alias
|
111
|
+
* @param relations The list of relations
|
59
112
|
* @param qb The query builder
|
60
113
|
* @param where The quere condition
|
61
114
|
* @param or Whether this where condition is AND/OR
|
62
115
|
* @param params The registered parameter name list
|
116
|
+
* @param isILikeEnabled Whether the ILIKE operator can be used
|
63
117
|
*/
|
64
|
-
protected adaptWhere(qb: WhereExpressionBuilder, where: CrudRequestWhere, or: boolean, params: string[]): void;
|
118
|
+
protected adaptWhere(alias: Alias, relations: CrudRequestRelation[], qb: WhereExpressionBuilder, where: CrudRequestWhere, or: boolean, params: string[], isILikeEnabled: boolean): void;
|
65
119
|
/**
|
66
120
|
* Creates a query parameter name based on a field
|
67
121
|
*
|
@@ -69,16 +123,56 @@ declare class TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any
|
|
69
123
|
* @param field The field path
|
70
124
|
*/
|
71
125
|
protected createParam(paramsDefined: string[], field: string[]): string;
|
126
|
+
/**
|
127
|
+
* Checks whether the field is valid
|
128
|
+
*
|
129
|
+
* @param alias The base alias
|
130
|
+
* @param path The field path
|
131
|
+
* @param source The source where the field validation comes from
|
132
|
+
*/
|
133
|
+
protected validateField(alias: Alias, path: FieldPath, source: 'select' | 'order' | 'where'): boolean;
|
134
|
+
/**
|
135
|
+
* Checks whether the field is valid
|
136
|
+
*
|
137
|
+
* @param alias The base alias
|
138
|
+
* @param path The field path
|
139
|
+
*/
|
140
|
+
protected isFieldValid(alias: Alias, path: FieldPath): boolean;
|
72
141
|
/**
|
73
142
|
* Maps where operators to a pseudo-SQL statement and a parameter map
|
74
143
|
*
|
144
|
+
* @param alias The query builder alias
|
145
|
+
* @param relations The list of relations
|
75
146
|
* @param where The where condition
|
76
147
|
* @param param The parameter name
|
148
|
+
* @param isILikeEnabled Whether the ILIKE operator can be used
|
77
149
|
*/
|
78
|
-
protected mapWhereOperators(where: CrudRequestWhereField, param: string): {
|
150
|
+
protected mapWhereOperators(alias: Alias, relations: CrudRequestRelation[], where: CrudRequestWhereField, param: string, isILikeEnabled: boolean): {
|
79
151
|
where: string;
|
80
152
|
params: ObjectLiteral;
|
81
153
|
};
|
154
|
+
/**
|
155
|
+
* Gets a field alias based on its base path
|
156
|
+
*
|
157
|
+
* @param alias The query main alias
|
158
|
+
* @param relations The relations
|
159
|
+
* @param base The base path
|
160
|
+
*/
|
161
|
+
protected getFieldAlias(alias: Alias, relations: CrudRequestRelation[], base: string[]): string;
|
162
|
+
/**
|
163
|
+
* Creates an ILIKE expression that works on all databases
|
164
|
+
*
|
165
|
+
* @param isILikeEnabled Whether ILIKE is supported
|
166
|
+
* @param field The field name
|
167
|
+
* @param not Whether the expression is inverted
|
168
|
+
*/
|
169
|
+
protected createLowerLike(isILikeEnabled: boolean, field: string, not?: boolean): string;
|
170
|
+
/**
|
171
|
+
* Checks whether ILIKE expressions are available for the current database
|
172
|
+
*
|
173
|
+
* @param qb The query builder
|
174
|
+
*/
|
175
|
+
protected isILikeEnabled(qb: SelectQueryBuilder<any>): boolean;
|
82
176
|
}
|
83
177
|
|
84
|
-
export {
|
178
|
+
export { TypeOrmQueryAdapter, type TypeOrmQueryAdapterOptions };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";var
|
1
|
+
"use strict";var E=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var f=(l,t)=>E(l,"name",{value:t,configurable:!0});var S=(l,t)=>{for(var r in t)E(l,r,{get:t[r],enumerable:!0})},A=(l,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of R(t))!_.call(l,e)&&e!==r&&E(l,e,{get:()=>t[e],enumerable:!(n=O(t,e))||n.enumerable});return l};var I=l=>A(E({},"__esModule",{value:!0}),l);var W={};S(W,{TypeOrmQueryAdapter:()=>L});module.exports=I(W);var y=require("typeorm");function h(l,t,r=0){if(!Array.isArray(t)||t.length<r)throw new Error(`${l} must be an array with at least ${r} items`);return t}f(h,"ensureArray");function p(l,t){if(N(t)&&t!==!0)throw new Error(`${l} must be true, null or undefined`)}f(p,"ensureEmpty");function N(l){return l!=null}f(N,"isValid");function w(l,t,r){return l??(t&&r?t*r:0)}f(w,"getOffset");function m(l,t){return l.length!==t.length?!1:l.every((r,n)=>t[n]===r)}f(m,"pathEquals");function T(l,t){return l.length-1!==t.length?!1:t.every((r,n)=>l[n]===r)}f(T,"pathHasBase");function g(l){if(l.length===0)throw new Error("Cannot break an empty path");let t=[...l],r=t.pop();return[t,r]}f(g,"pathGetBaseAndName");var L=class{constructor(t={}){this.options=t}static{f(this,"TypeOrmQueryAdapter")}build(t,r){return t=this.createBaseQuery(t,r),t=this.paginateQuery(t,r),t}async getOne(t,r){return await this.createBaseQuery(t,r).getOne()??null}async getMany(t,r){let n=w(r.offset,r.limit,r.page),e=this.createBaseQuery(t,r),a=await this.paginateQuery(e.clone(),r,n).getMany(),u=await e.getCount(),d=r.limit??u,i=a.length,c=Math.floor(n/d)+1,o=Math.ceil(u/d);return{data:a,count:i,page:c,pageCount:o,total:u}}createBaseQuery(t,r){let n=[],e=this.isILikeEnabled(t),s=t.expressionMap.mainAlias;if(!s)throw new Error("No main alias found in query builder");return this.adaptSelect(t,s,r.select),this.adaptRelations(t,s,r.relations,r.select),this.adaptWhere(s,r.relations,t,r.where,!1,n,e),this.adaptOrder(t,s,r.relations,r.order),t}paginateQuery(t,r,n){return t.limit(r.limit).offset(n)}adaptSelect(t,r,n){if(n.length===0)return;let e=n.filter(s=>s.field.length===1).filter(s=>this.validateField(r,s.field,"select"));t.select(e.map(s=>[r.name,...s.field].join(".")))}adaptRelations(t,r,n,e){for(let s of n){let a=[r.name,...s.field].join("."),u=s.alias||[r.name,...s.field].join("_"),d=e.filter(i=>T(i.field,s.field)).filter(i=>this.validateField(r,i.field,"select"));d.length===0?t.leftJoinAndSelect(a,u):(t.leftJoin(a,u),t.addSelect(d.map(i=>[u,i.field[i.field.length-1]].join("."))))}}adaptOrder(t,r,n,e){for(let s of e){if(!this.validateField(r,s.field,"order"))continue;let[a,u]=g(s.field),i=this.getFieldAlias(r,n,a)+"."+u;t.addOrderBy(i,s.order)}}adaptWhere(t,r,n,e,s,a,u){let d=(s?n.orWhere:n.andWhere).bind(n);if(e.or&&e.or.length>0)d(new y.Brackets(i=>e.or.forEach(c=>this.adaptWhere(t,r,i,c,!0,a,u))));else if(e.and&&e.and.length>0)d(new y.Brackets(i=>e.and.forEach(c=>this.adaptWhere(t,r,i,c,!1,a,u))));else if(e.field){if(!this.validateField(t,e.field,"where"))return;let i=this.createParam(a,e.field),c=this.mapWhereOperators(t,r,e,i,u);d(c.where,c.params)}}createParam(t,r){let n=r.length>0?r[r.length-1]:"",e,s=0;do e="req_"+n+"_"+s,s++;while(t.includes(e));return t.push(e),e}validateField(t,r,n){if(this.isFieldValid(t,r))return!0;let s={select:"ignore",order:"ignore",where:"deny"},a=this.options.invalidFields?.[n]||s[n];if(a==="ignore")return!1;if(a==="allow-unsafe")return!0;if(a==="deny")throw new Error(`${n} field "${r.join(".")}" is invalid.`);return!1}isFieldValid(t,r){if(r.length===0)return!1;let n=t.metadata,e=[...r],s=e.pop();for(let u of e){let d=n.findRelationWithPropertyPath(u);if(!d)return!1;n=d.inverseEntityMetadata}return!!n.findColumnWithPropertyPathStrict(s)}mapWhereOperators(t,r,n,e,s){let[a,u]=g(n.field),i=this.getFieldAlias(t,r,a)+"."+u,c=n.operator,o=n.value;switch(c){case"eq":return{where:`${i} = :${e}`,params:{[e]:o}};case"neq":return{where:`${i} != :${e}`,params:{[e]:o}};case"gt":return{where:`${i} > :${e}`,params:{[e]:o}};case"gte":return{where:`${i} >= :${e}`,params:{[e]:o}};case"lt":return{where:`${i} < :${e}`,params:{[e]:o}};case"lte":return{where:`${i} <= :${e}`,params:{[e]:o}};case"starts":return{where:`${i} LIKE :${e}`,params:{[e]:`${o}%`}};case"ends":return{where:`${i} LIKE :${e}`,params:{[e]:`%${o}`}};case"contains":return{where:`${i} LIKE :${e}`,params:{[e]:`%${o}%`}};case"not_contains":return{where:`${i} NOT LIKE :${e}`,params:{[e]:`%${o}%`}};case"in":return o=h("IN operator",o,1),{where:`${i} IN (:...${e})`,params:{[e]:o}};case"not_in":return o=h("NOT IN operator",o,1),{where:`${i} NOT IN (:...${e})`,params:{[e]:o}};case"between":let $=h("BETWEEN operator",o,2);return{where:`${i} BETWEEN :${e}_start AND :${e}_end`,params:{[`${e}_start`]:$[0],[`${e}_end`]:$[1]}};case"is_null":return p("IS NULL operator",o),{where:`${i} IS NULL`,params:{}};case"not_null":return p("NOT NULL operator",o),{where:`${i} IS NOT NULL`,params:{}};case"eq_lower":return{where:`LOWER(${i}) = :${e}`,params:{[e]:o}};case"neq_lower":return{where:`LOWER(${i}) != :${e}`,params:{[e]:o}};case"starts_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`${o}%`}};case"ends_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`%${o}`}};case"contains_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`%${o}%`}};case"not_contains_lower":return{where:`${this.createLowerLike(s,i,!0)} :${e}`,params:{[e]:`%${o}%`}};case"in_lower":return h("IN operator",o,1),{where:`LOWER(${i}) IN (...:${e})`,params:{[e]:o}};case"not_in_lower":return h("NOT IN operator",o,1),{where:`LOWER(${i}) NOT IN (...:${e})`,params:{[e]:o}};default:throw new Error(`Unknown operator "${c}"`)}}getFieldAlias(t,r,n){if(n.length===0)return t.name;let e=r.find(s=>m(s.field,n));return e&&e.alias?e.alias:[t.name,...n].join("_")}createLowerLike(t,r,n=!1){return t?n?`${r} NOT ILIKE`:`${r} ILIKE`:n?`LOWER(${r}) NOT LIKE`:`LOWER(${r}) LIKE`}isILikeEnabled(t){let r=this.options.ilike;if(N(r))return r;let n=t.connection.options.type;return n==="postgres"||n==="aurora-postgres"}};0&&(module.exports={TypeOrmQueryAdapter});
|
2
2
|
//# sourceMappingURL=index.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/typeorm/index.ts","../../../src/adapters/typeorm/typeorm.query-adapter.ts","../../../src/utils/functions.ts"],"sourcesContent":["\r\nexport * from './typeorm.query-adapter';\r\n","import { Brackets, ObjectLiteral, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm';\r\nimport { QueryAdapter } from '../../models/query-adapter';\r\nimport {\r\n CrudRequest,\r\n CrudRequestOrder,\r\n CrudRequestRelation,\r\n ParsedRequestSelect\r\n} from '../../models/crud-request';\r\nimport {\r\n CrudRequestWhere,\r\n CrudRequestWhereField,\r\n CrudRequestWhereOperator\r\n} from '../../models/crud-request-where';\r\nimport { GetManyResult } from '../../models/get-many-result';\r\nimport { ensureArray, ensureFalsy } from '../../utils/functions';\r\n\r\n/**\r\n * Adapts queries to TypeORM query builder object\r\n */\r\nexport class TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public build<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E> {\r\n qb = this.createBaseQuery(qb, query);\r\n qb = this.paginateQuery(qb, query);\r\n\r\n return qb;\r\n }\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public async getOne<E extends ObjectLiteral>(qb: SelectQueryBuilder<E | any>, request: CrudRequest): Promise<E | null> {\r\n const query = this.createBaseQuery(qb, request);\r\n const entity = await query.getOne();\r\n\r\n return entity ?? null;\r\n }\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public async getMany<E extends ObjectLiteral>(qb: SelectQueryBuilder<E | any>, request: CrudRequest): Promise<GetManyResult<E>> {\r\n const fullQuery = this.createBaseQuery(qb, request);\r\n const paginatedQuery = this.paginateQuery(fullQuery.clone(), request);\r\n\r\n const data = await paginatedQuery.getMany();\r\n const total = await fullQuery.getCount();\r\n\r\n const offset = request.offset ?? 0;\r\n const limit = request.limit ?? total;\r\n\r\n const count = data.length;\r\n const page = Math.floor(offset / limit) + 1;\r\n const pageCount = Math.ceil(total / limit);\r\n\r\n return {\r\n data,\r\n count,\r\n page,\r\n pageCount,\r\n total,\r\n };\r\n }\r\n\r\n /**\r\n * Creates a query filtered from the parsed request\r\n *\r\n * @param qb The base query builder\r\n * @param query The parsed query\r\n */\r\n protected createBaseQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E> {\r\n const paramsDefined: string[] = [];\r\n\r\n this.adaptSelect(qb, query.select);\r\n this.adaptRelations(qb, query.relations);\r\n this.adaptWhere(qb, query.where, false, paramsDefined);\r\n this.adaptOrder(qb, query.order);\r\n\r\n return qb;\r\n }\r\n\r\n /**\r\n * Paginates a query based on the parsed request\r\n *\r\n * @param qb The query builder\r\n * @param query The parsed query\r\n */\r\n protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E> {\r\n return qb.limit(query.limit).offset(query.offset);\r\n }\r\n\r\n /**\r\n * Adapts a select\r\n *\r\n * @param qb The query builder\r\n * @param select The parsed select fields\r\n */\r\n protected adaptSelect<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, select: ParsedRequestSelect): void {\r\n qb.addSelect(select.map(s => s.field.join('.')));\r\n }\r\n\r\n /**\r\n * Adapts the join relation list\r\n *\r\n * @param qb The query builder\r\n * @param relations The parsed relation list\r\n */\r\n protected adaptRelations<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, relations: CrudRequestRelation[]): void {\r\n for (const relation of relations) {\r\n const path = relation.field.join('.');\r\n const alias = relation.alias || path.replace('.', '_');\r\n\r\n qb.leftJoin(path, alias);\r\n }\r\n }\r\n\r\n /**\r\n * Adapts the order by list\r\n *\r\n * @param qb The query builder\r\n * @param ordering The parsed ordering\r\n */\r\n protected adaptOrder<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, ordering: CrudRequestOrder[]): void {\r\n for (const order of ordering) {\r\n const path = order.field.join('.');\r\n\r\n qb.addOrderBy(path, order.order);\r\n }\r\n }\r\n\r\n /**\r\n * Adapts a where condition\r\n *\r\n * @param qb The query builder\r\n * @param where The quere condition\r\n * @param or Whether this where condition is AND/OR\r\n * @param params The registered parameter name list\r\n */\r\n protected adaptWhere(qb: WhereExpressionBuilder, where: CrudRequestWhere, or: boolean, params: string[]): void {\r\n const addWhere = (or ? qb.orWhere : qb.andWhere).bind(qb);\r\n\r\n if (where.or && where.or.length > 0) {\r\n addWhere(new Brackets(\r\n wqb => where.or!.forEach(item => this.adaptWhere(wqb, item, true, params))\r\n ));\r\n } else if (where.and && where.and.length > 0) {\r\n addWhere(new Brackets(\r\n wqb => where.and!.forEach(item => this.adaptWhere(wqb, item, false, params))\r\n ));\r\n } else if (where.field) {\r\n const param = this.createParam(params, where.field);\r\n const query = this.mapWhereOperators(where as CrudRequestWhereField, param);\r\n\r\n addWhere(query.where, query.params);\r\n }\r\n }\r\n\r\n /**\r\n * Creates a query parameter name based on a field\r\n *\r\n * @param paramsDefined The array the parameter will be registered onto\r\n * @param field The field path\r\n */\r\n protected createParam(paramsDefined: string[], field: string[]): string {\r\n const name = field.length > 0 ? field[field.length - 1] : '';\r\n let param: string;\r\n let iteration: number = 0;\r\n\r\n do {\r\n param = 'req_' + name + '_' + iteration;\r\n iteration++;\r\n } while (paramsDefined.includes(param));\r\n\r\n paramsDefined.push(param);\r\n return param;\r\n }\r\n\r\n /**\r\n * Maps where operators to a pseudo-SQL statement and a parameter map\r\n *\r\n * @param where The where condition\r\n * @param param The parameter name\r\n */\r\n protected mapWhereOperators(where: CrudRequestWhereField, param: string): { where: string, params: ObjectLiteral } {\r\n const field = where.field.join('.');\r\n const operator = where.operator;\r\n let value: unknown = where.value;\r\n\r\n switch (operator) {\r\n case CrudRequestWhereOperator.EQ:\r\n return { where: `${field} = :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NEQ:\r\n return { where: `${field} != :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.GT:\r\n return { where: `${field} > :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.GTE:\r\n return { where: `${field} >= :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.LT:\r\n return { where: `${field} < :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.LTE:\r\n return { where: `${field} <= :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.STARTS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `${value}%` } };\r\n\r\n case CrudRequestWhereOperator.ENDS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `%${value}` } };\r\n\r\n case CrudRequestWhereOperator.CONTAINS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.NOT_CONTAINS:\r\n return { where: `${field} NOT LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.IN:\r\n value = ensureArray('IN operator', value, 1);\r\n\r\n return { where: `${field} IN (:...${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NOT_IN:\r\n value = ensureArray('NOT IN operator', value, 1);\r\n\r\n return { where: `${field} NOT IN (:...${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.BETWEEN:\r\n const arr = ensureArray('BETWEEN operator', value, 2);\r\n\r\n return {\r\n where: `${field} BETWEEN :${param}_start AND :${param}_end`,\r\n params: { [`${param}_start`]: arr[0], [`${param}_end`]: arr[1] },\r\n };\r\n\r\n case CrudRequestWhereOperator.IS_NULL:\r\n ensureFalsy('IS NULL operator', value);\r\n\r\n return { where: `${field} IS NULL`, params: {} };\r\n\r\n case CrudRequestWhereOperator.NOT_NULL:\r\n ensureFalsy('NOT NULL operator', value);\r\n\r\n return { where: `${field} IS NOT NULL`, params: {} };\r\n\r\n case CrudRequestWhereOperator.EQ_LOWER:\r\n return { where: `LOWER(${field}) = :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NEQ_LOWER:\r\n return { where: `LOWER(${field}) != :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.STARTS_LOWER:\r\n return { where: `LOWER(${field}) LIKE :${param}`, params: { [param]: `${value}%` } };\r\n\r\n case CrudRequestWhereOperator.ENDS_LOWER:\r\n return { where: `LOWER(${field}) LIKE :${param}`, params: { [param]: `%${value}` } };\r\n\r\n case CrudRequestWhereOperator.CONTAINS_LOWER:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.NOT_CONTAINS_LOWER:\r\n return { where: `${field} NOT LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.IN_LOWER:\r\n ensureArray('IN operator', value, 1);\r\n\r\n return { where: `${field} IN (...:${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NOT_IN_LOWER:\r\n ensureArray('NOT IN operator', value, 1);\r\n\r\n return { where: `${field} NOT IN (...:${param})`, params: { [param]: value } };\r\n\r\n default:\r\n throw new Error(`Unknown operator \"${operator}\"`);\r\n }\r\n }\r\n\r\n}\r\n","import { CrudRequestFields } from '../models/crud-request';\r\n\r\n/*export function setFieldByPath<T>(obj: ParsedRequestFields<T>, field: string, value: T): void {\r\n const parts = field.split('.');\r\n\r\n while (parts.length > 1) {\r\n const name = parts.shift();\r\n\r\n if (!Array.isArray(obj[name]))\r\n obj[name] = {};\r\n\r\n obj = obj[name] as ParsedRequestFields<T>;\r\n }\r\n\r\n obj[parts.shift()] = value;\r\n}*/\r\n\r\nexport function ensureArray<T>(fieldName: string, data: T[] | any, minLength: number = 0): T[] {\r\n if (!Array.isArray(data) || data.length < minLength)\r\n throw new Error(`${fieldName} must be an array with at least ${minLength} items`);\r\n\r\n return data;\r\n}\r\n\r\nexport function ensureFalsy(fieldName: string, data: any) {\r\n if (data)\r\n throw new Error(`${fieldName} must be null`);\r\n}\r\n\r\nexport function isValid(value: any): value is object {\r\n return value !== null && value !== undefined;\r\n}\r\n"],"mappings":"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","names":["typeorm_exports","__export","TypeormQueryAdapter","__toCommonJS","import_typeorm","ensureArray","fieldName","data","minLength","__name","ensureFalsy","TypeormQueryAdapter","__name","qb","query","request","fullQuery","data","total","offset","limit","count","page","pageCount","paramsDefined","select","s","relations","relation","path","alias","ordering","order","where","or","params","addWhere","wqb","item","param","field","name","iteration","operator","value","ensureArray","arr","ensureFalsy"]}
|
1
|
+
{"version":3,"sources":["../../../src/adapters/typeorm/index.ts","../../../src/adapters/typeorm/typeorm.query-adapter.ts","../../../src/utils/functions.ts","../../../src/utils/field-path.ts"],"sourcesContent":["\r\nexport * from './typeorm.query-adapter';\r\n","import { Brackets, ObjectLiteral, SelectQueryBuilder, WhereExpressionBuilder } from 'typeorm';\r\nimport { Alias } from 'typeorm/query-builder/Alias';\r\nimport { QueryAdapter } from '../../models/query-adapter';\r\nimport { CrudRequest, CrudRequestOrder, CrudRequestRelation, ParsedRequestSelect } from '../../models/crud-request';\r\nimport { CrudRequestWhere, CrudRequestWhereField, CrudRequestWhereOperator } from '../../models/crud-request-where';\r\nimport { GetManyResult } from '../../models/get-many-result';\r\nimport { FieldPath } from '../../models/field-path';\r\nimport { ensureArray, ensureEmpty, getOffset, isValid } from '../../utils/functions';\r\nimport { pathEquals, pathGetBaseAndName, pathHasBase } from '../../utils/field-path';\r\n\r\nexport interface TypeOrmQueryAdapterOptions {\r\n /**\r\n * Whether it will use ILIKE for case-insensitive operations.\r\n *\r\n * If undefined, it will be enabled by default for postgres and aurora-postgres databases\r\n */\r\n ilike?: boolean;\r\n\r\n /**\r\n * What it will do when it finds invalid fields.\r\n *\r\n * By default, `select` and `order` will ignore invalid fields, and `where` will deny invalid fields.\r\n */\r\n invalidFields?: {\r\n /**\r\n * What it will do when it finds invalid fields in `select`.\r\n *\r\n * If \"ignore\", it will remove invalid fields\r\n * If \"deny\", it will throw an exception for invalid fields\r\n * If \"allow-unsafe\", it will not validate any fields. Unsafe: this can allow SQL injection\r\n * If undefined, it will default to \"ignore\"\r\n */\r\n select?: 'ignore' | 'deny' | 'allow-unsafe';\r\n\r\n /**\r\n * What it will do when it finds invalid fields in `order`.\r\n *\r\n * If \"ignore\", it will remove invalid fields\r\n * If \"deny\", it will throw an exception for invalid fields\r\n * If \"allow-unsafe\", it will not validate any fields. Unsafe: this can allow SQL injection\r\n * If undefined, it will default to \"ignore\"\r\n */\r\n order?: 'ignore' | 'deny' | 'allow-unsafe';\r\n\r\n /**\r\n * What it will do when it finds invalid fields in `order`.\r\n *\r\n * If \"ignore\", it will remove invalid fields\r\n * If \"deny\", it will throw an exception for invalid fields\r\n * If \"allow-unsafe\", it will not validate any fields. Unsafe: this can allow SQL injection\r\n * If undefined, it will default to \"deny\"\r\n */\r\n where?: 'ignore' | 'deny' | 'allow-unsafe';\r\n }\r\n}\r\n\r\n/**\r\n * Adapts queries to TypeORM query builder object\r\n */\r\nexport class TypeOrmQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {\r\n\r\n constructor(\r\n private readonly options: TypeOrmQueryAdapterOptions = {},\r\n ) {}\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public build<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E> {\r\n qb = this.createBaseQuery(qb, query);\r\n qb = this.paginateQuery(qb, query);\r\n\r\n return qb;\r\n }\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public async getOne<E extends ObjectLiteral>(qb: SelectQueryBuilder<E | any>, request: CrudRequest): Promise<E | null> {\r\n const query = this.createBaseQuery(qb, request);\r\n const entity = await query.getOne();\r\n\r\n return entity ?? null;\r\n }\r\n\r\n /**\r\n * @inheritDoc\r\n */\r\n public async getMany<E extends ObjectLiteral>(qb: SelectQueryBuilder<E | any>, request: CrudRequest): Promise<GetManyResult<E>> {\r\n const offset = getOffset(request.offset, request.limit, request.page);\r\n\r\n const fullQuery = this.createBaseQuery(qb, request);\r\n const paginatedQuery = this.paginateQuery(fullQuery.clone(), request, offset);\r\n\r\n const data = await paginatedQuery.getMany();\r\n const total = await fullQuery.getCount();\r\n\r\n const limit = request.limit ?? total;\r\n\r\n const count = data.length;\r\n const page = Math.floor(offset / limit) + 1;\r\n const pageCount = Math.ceil(total / limit);\r\n\r\n return {\r\n data,\r\n count,\r\n page,\r\n pageCount,\r\n total,\r\n };\r\n }\r\n\r\n /**\r\n * Creates a query filtered from the parsed request\r\n *\r\n * @param qb The base query builder\r\n * @param query The parsed query\r\n */\r\n protected createBaseQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest): SelectQueryBuilder<E> {\r\n const paramsDefined: string[] = [];\r\n const isILikeEnabled = this.isILikeEnabled(qb);\r\n const mainAlias = qb.expressionMap.mainAlias;\r\n\r\n if (!mainAlias)\r\n throw new Error('No main alias found in query builder');\r\n\r\n this.adaptSelect(qb, mainAlias, query.select);\r\n this.adaptRelations(qb, mainAlias, query.relations, query.select);\r\n this.adaptWhere(mainAlias, query.relations, qb, query.where, false, paramsDefined, isILikeEnabled);\r\n this.adaptOrder(qb, mainAlias, query.relations, query.order);\r\n\r\n return qb;\r\n }\r\n\r\n /**\r\n * Paginates a query based on the parsed request\r\n *\r\n * @param qb The query builder\r\n * @param query The parsed query\r\n * @param offset The parsed query offset\r\n */\r\n protected paginateQuery<E extends ObjectLiteral>(qb: SelectQueryBuilder<E>, query: CrudRequest, offset?: number): SelectQueryBuilder<E> {\r\n return qb.limit(query.limit).offset(offset);\r\n }\r\n\r\n /**\r\n * Adapts a select\r\n *\r\n * @param qb The query builder\r\n * @param alias The base alias\r\n * @param select The parsed select fields\r\n */\r\n protected adaptSelect<E extends ObjectLiteral>(\r\n qb: SelectQueryBuilder<E>,\r\n alias: Alias,\r\n select: ParsedRequestSelect,\r\n ): void {\r\n if (select.length === 0)\r\n return;\r\n\r\n // Only fields that are one level deep\r\n const fields = select\r\n .filter(f => f.field.length === 1)\r\n .filter(f => this.validateField(alias, f.field, 'select'));\r\n\r\n qb.select(fields.map(s => [alias.name, ...s.field].join('.')));\r\n }\r\n\r\n /**\r\n * Adapts the join relation list\r\n *\r\n * @param qb The query builder\r\n * @param baseAlias The base alias\r\n * @param relations The parsed relation list\r\n * @param select The parsed select fields\r\n */\r\n protected adaptRelations<E extends ObjectLiteral>(\r\n qb: SelectQueryBuilder<E>,\r\n baseAlias: Alias,\r\n relations: CrudRequestRelation[],\r\n select: ParsedRequestSelect,\r\n ): void {\r\n for (const relation of relations) {\r\n const path = [baseAlias.name, ...relation.field].join('.');\r\n const alias = relation.alias || [baseAlias.name, ...relation.field].join('_');\r\n\r\n const fields = select\r\n .filter(f => pathHasBase(f.field, relation.field))\r\n .filter(f => this.validateField(baseAlias, f.field, 'select'));\r\n\r\n if (fields.length === 0) {\r\n qb.leftJoinAndSelect(path, alias);\r\n } else {\r\n qb.leftJoin(path, alias);\r\n qb.addSelect(fields.map(f => [alias, f.field[f.field.length - 1]].join('.')));\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Adapts the order by list\r\n *\r\n * @param qb The query builder\r\n * @param alias The base alias\r\n * @param relations The list of relations\r\n * @param ordering The parsed ordering\r\n */\r\n protected adaptOrder<E extends ObjectLiteral>(\r\n qb: SelectQueryBuilder<E>,\r\n alias: Alias,\r\n relations: CrudRequestRelation[],\r\n ordering: CrudRequestOrder[],\r\n ): void {\r\n for (const order of ordering) {\r\n if (!this.validateField(alias, order.field, 'order'))\r\n continue;\r\n\r\n const [fieldBase, fieldName] = pathGetBaseAndName(order.field);\r\n const aliasName = this.getFieldAlias(alias, relations, fieldBase);\r\n\r\n const path = aliasName + '.' + fieldName;\r\n\r\n qb.addOrderBy(path, order.order);\r\n }\r\n }\r\n\r\n /**\r\n * Adapts a where condition\r\n *\r\n * @param alias The query builder alias\r\n * @param relations The list of relations\r\n * @param qb The query builder\r\n * @param where The quere condition\r\n * @param or Whether this where condition is AND/OR\r\n * @param params The registered parameter name list\r\n * @param isILikeEnabled Whether the ILIKE operator can be used\r\n */\r\n protected adaptWhere(\r\n alias: Alias,\r\n relations: CrudRequestRelation[],\r\n qb: WhereExpressionBuilder,\r\n where: CrudRequestWhere,\r\n or: boolean,\r\n params: string[],\r\n isILikeEnabled: boolean,\r\n ): void {\r\n const addWhere = (or ? qb.orWhere : qb.andWhere).bind(qb);\r\n\r\n if (where.or && where.or.length > 0) {\r\n addWhere(new Brackets(\r\n wqb => where.or!.forEach(item => this.adaptWhere(alias, relations, wqb, item, true, params, isILikeEnabled))\r\n ));\r\n } else if (where.and && where.and.length > 0) {\r\n addWhere(new Brackets(\r\n wqb => where.and!.forEach(item => this.adaptWhere(alias, relations, wqb, item, false, params, isILikeEnabled))\r\n ));\r\n } else if (where.field) {\r\n if (!this.validateField(alias, where.field, 'where'))\r\n return;\r\n\r\n const param = this.createParam(params, where.field);\r\n const query = this.mapWhereOperators(alias, relations, where as CrudRequestWhereField, param, isILikeEnabled);\r\n\r\n addWhere(query.where, query.params);\r\n }\r\n }\r\n\r\n /**\r\n * Creates a query parameter name based on a field\r\n *\r\n * @param paramsDefined The array the parameter will be registered onto\r\n * @param field The field path\r\n */\r\n protected createParam(paramsDefined: string[], field: string[]): string {\r\n const name = field.length > 0 ? field[field.length - 1] : '';\r\n let param: string;\r\n let iteration: number = 0;\r\n\r\n do {\r\n param = 'req_' + name + '_' + iteration;\r\n iteration++;\r\n } while (paramsDefined.includes(param));\r\n\r\n paramsDefined.push(param);\r\n return param;\r\n }\r\n\r\n /**\r\n * Checks whether the field is valid\r\n *\r\n * @param alias The base alias\r\n * @param path The field path\r\n * @param source The source where the field validation comes from\r\n */\r\n protected validateField(alias: Alias, path: FieldPath, source: 'select' | 'order' | 'where'): boolean {\r\n const isValid = this.isFieldValid(alias, path);\r\n\r\n if (isValid)\r\n return true;\r\n\r\n const defaults = {\r\n select: 'ignore',\r\n order: 'ignore',\r\n where: 'deny',\r\n };\r\n\r\n const rule = this.options.invalidFields?.[source] || defaults[source];\r\n\r\n if (rule === 'ignore')\r\n return false;\r\n\r\n if (rule === 'allow-unsafe')\r\n return true;\r\n\r\n if (rule === 'deny')\r\n throw new Error(`${source} field \"${path.join('.')}\" is invalid.`);\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Checks whether the field is valid\r\n *\r\n * @param alias The base alias\r\n * @param path The field path\r\n */\r\n protected isFieldValid(alias: Alias, path: FieldPath): boolean {\r\n if (path.length === 0)\r\n return false;\r\n\r\n let metadata = alias.metadata;\r\n\r\n const relationPath = [...path];\r\n const field = relationPath.pop()!;\r\n\r\n for (const part of relationPath) {\r\n const relation = metadata.findRelationWithPropertyPath(part);\r\n\r\n if (!relation)\r\n return false;\r\n\r\n metadata = relation.inverseEntityMetadata;\r\n }\r\n\r\n const column = metadata.findColumnWithPropertyPathStrict(field);\r\n\r\n return !!column;\r\n }\r\n\r\n /**\r\n * Maps where operators to a pseudo-SQL statement and a parameter map\r\n *\r\n * @param alias The query builder alias\r\n * @param relations The list of relations\r\n * @param where The where condition\r\n * @param param The parameter name\r\n * @param isILikeEnabled Whether the ILIKE operator can be used\r\n */\r\n protected mapWhereOperators(\r\n alias: Alias,\r\n relations: CrudRequestRelation[],\r\n where: CrudRequestWhereField,\r\n param: string,\r\n isILikeEnabled: boolean,\r\n ): { where: string, params: ObjectLiteral } {\r\n const [pathBase, pathField] = pathGetBaseAndName(where.field);\r\n const fieldAlias = this.getFieldAlias(alias, relations, pathBase);\r\n\r\n const field = fieldAlias + '.' + pathField;\r\n\r\n const operator = where.operator;\r\n let value: unknown = where.value;\r\n\r\n switch (operator) {\r\n case CrudRequestWhereOperator.EQ:\r\n return { where: `${field} = :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NEQ:\r\n return { where: `${field} != :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.GT:\r\n return { where: `${field} > :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.GTE:\r\n return { where: `${field} >= :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.LT:\r\n return { where: `${field} < :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.LTE:\r\n return { where: `${field} <= :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.STARTS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `${value}%` } };\r\n\r\n case CrudRequestWhereOperator.ENDS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `%${value}` } };\r\n\r\n case CrudRequestWhereOperator.CONTAINS:\r\n return { where: `${field} LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.NOT_CONTAINS:\r\n return { where: `${field} NOT LIKE :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.IN:\r\n value = ensureArray('IN operator', value, 1);\r\n\r\n return { where: `${field} IN (:...${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NOT_IN:\r\n value = ensureArray('NOT IN operator', value, 1);\r\n\r\n return { where: `${field} NOT IN (:...${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.BETWEEN:\r\n const arr = ensureArray('BETWEEN operator', value, 2);\r\n\r\n return {\r\n where: `${field} BETWEEN :${param}_start AND :${param}_end`,\r\n params: { [`${param}_start`]: arr[0], [`${param}_end`]: arr[1] },\r\n };\r\n\r\n case CrudRequestWhereOperator.IS_NULL:\r\n ensureEmpty('IS NULL operator', value);\r\n\r\n return { where: `${field} IS NULL`, params: {} };\r\n\r\n case CrudRequestWhereOperator.NOT_NULL:\r\n ensureEmpty('NOT NULL operator', value);\r\n\r\n return { where: `${field} IS NOT NULL`, params: {} };\r\n\r\n case CrudRequestWhereOperator.EQ_LOWER:\r\n return { where: `LOWER(${field}) = :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NEQ_LOWER:\r\n return { where: `LOWER(${field}) != :${param}`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.STARTS_LOWER:\r\n return { where: `${this.createLowerLike(isILikeEnabled, field)} :${param}`, params: { [param]: `${value}%` } };\r\n\r\n case CrudRequestWhereOperator.ENDS_LOWER:\r\n return { where: `${this.createLowerLike(isILikeEnabled, field)} :${param}`, params: { [param]: `%${value}` } };\r\n\r\n case CrudRequestWhereOperator.CONTAINS_LOWER:\r\n return { where: `${this.createLowerLike(isILikeEnabled, field)} :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.NOT_CONTAINS_LOWER:\r\n return { where: `${this.createLowerLike(isILikeEnabled, field, true)} :${param}`, params: { [param]: `%${value}%` } };\r\n\r\n case CrudRequestWhereOperator.IN_LOWER:\r\n ensureArray('IN operator', value, 1);\r\n\r\n return { where: `LOWER(${field}) IN (...:${param})`, params: { [param]: value } };\r\n\r\n case CrudRequestWhereOperator.NOT_IN_LOWER:\r\n ensureArray('NOT IN operator', value, 1);\r\n\r\n return { where: `LOWER(${field}) NOT IN (...:${param})`, params: { [param]: value } };\r\n\r\n default:\r\n throw new Error(`Unknown operator \"${operator}\"`);\r\n }\r\n }\r\n\r\n /**\r\n * Gets a field alias based on its base path\r\n *\r\n * @param alias The query main alias\r\n * @param relations The relations\r\n * @param base The base path\r\n */\r\n protected getFieldAlias(alias: Alias, relations: CrudRequestRelation[], base: string[]): string {\r\n if (base.length === 0)\r\n return alias.name;\r\n\r\n const relation = relations.find(r => pathEquals(r.field, base));\r\n\r\n if (relation && relation.alias)\r\n return relation.alias;\r\n\r\n return [alias.name, ...base].join('_');\r\n }\r\n\r\n /**\r\n * Creates an ILIKE expression that works on all databases\r\n *\r\n * @param isILikeEnabled Whether ILIKE is supported\r\n * @param field The field name\r\n * @param not Whether the expression is inverted\r\n */\r\n protected createLowerLike(isILikeEnabled: boolean, field: string, not: boolean = false): string {\r\n if (isILikeEnabled)\r\n return not ? `${field} NOT ILIKE` : `${field} ILIKE`;\r\n\r\n return not ? `LOWER(${field}) NOT LIKE` : `LOWER(${field}) LIKE`;\r\n }\r\n\r\n /**\r\n * Checks whether ILIKE expressions are available for the current database\r\n *\r\n * @param qb The query builder\r\n */\r\n protected isILikeEnabled(qb: SelectQueryBuilder<any>): boolean {\r\n const ilikeEnabled = this.options.ilike;\r\n\r\n if (isValid(ilikeEnabled))\r\n return ilikeEnabled;\r\n\r\n const type = qb.connection.options.type;\r\n return type === 'postgres' || type === 'aurora-postgres';\r\n }\r\n\r\n}\r\n","import { CrudRequestFields } from '../models/crud-request';\r\n\r\n/*export function setFieldByPath<T>(obj: ParsedRequestFields<T>, field: string, value: T): void {\r\n const parts = field.split('.');\r\n\r\n while (parts.length > 1) {\r\n const name = parts.shift();\r\n\r\n if (!Array.isArray(obj[name]))\r\n obj[name] = {};\r\n\r\n obj = obj[name] as ParsedRequestFields<T>;\r\n }\r\n\r\n obj[parts.shift()] = value;\r\n}*/\r\n\r\nexport function ensurePrimitive(fieldName: string, data: any) {\r\n if (data === null || data === undefined)\r\n return;\r\n\r\n if (typeof data === 'number' || typeof data === 'string' || typeof data === 'boolean')\r\n return;\r\n\r\n if (data instanceof Date)\r\n return;\r\n\r\n throw new Error(`${fieldName} must be a string, number, boolean or null`);\r\n}\r\n\r\nexport function ensureArray<T>(fieldName: string, data: T[] | any, minLength: number = 0): T[] {\r\n if (!Array.isArray(data) || data.length < minLength)\r\n throw new Error(`${fieldName} must be an array with at least ${minLength} items`);\r\n\r\n return data;\r\n}\r\n\r\nexport function ensureEmpty(fieldName: string, data: any) {\r\n if (isValid(data) && data !== true)\r\n throw new Error(`${fieldName} must be true, null or undefined`);\r\n}\r\n\r\nexport function isValid<T>(value: T | undefined | null): value is T {\r\n return value !== null && value !== undefined;\r\n}\r\n\r\nexport function getOffset(offset: number | undefined, limit?: number, page?: number): number {\r\n return offset ?? (limit && page ? limit * page : 0);\r\n}\r\n","/**\r\n * Checks whether two field paths are equal\r\n *\r\n * E.g. [\"path\", \"to\", \"field\"] is equal to [\"path\", \"to\", \"field\"] but not [\"something\", \"else\"]\r\n */\r\nexport function pathEquals(path1: string[], path2: string[]): boolean {\r\n if (path1.length !== path2.length)\r\n return false;\r\n\r\n return path1.every((p1, i) => path2[i] === p1);\r\n}\r\n\r\n/**\r\n * Checks whether a path starts with another path.\r\n *\r\n * E.g. [\"path\", \"to\", \"field\"] starts with [\"path\"] or [\"path\", \"to\"] but not [\"something\", \"else\"]\r\n */\r\nexport function pathStartsWith(path: string[], start: string[]): boolean {\r\n if (path.length < start.length)\r\n return false;\r\n\r\n return start.every((start, i) => path[i] === start);\r\n}\r\n\r\n/**\r\n * Checks whether the base of a path matches.\r\n *\r\n * E.g. [\"path\", \"to\", \"field\"] has a base of [\"path\", \"to\"] but not [\"path\"]\r\n */\r\nexport function pathHasBase(path: string[], base: string[]): boolean {\r\n if (path.length - 1 !== base.length)\r\n return false;\r\n\r\n return base.every((start, i) => path[i] === start);\r\n}\r\n\r\n/**\r\n * Breaks a path into the base part and the field name part\r\n *\r\n * @param path The full path\r\n */\r\nexport function pathGetBaseAndName(path: string[]): [string[], string] {\r\n if (path.length === 0)\r\n throw new Error('Cannot break an empty path');\r\n\r\n const base = [...path];\r\n const name = base.pop()!;\r\n\r\n return [base, name];\r\n}\r\n\r\n\r\n/**\r\n * Gets the last part of the path: the field name\r\n *\r\n * @param path The full path\r\n */\r\nexport function pathGetFieldName(path: string[]): string {\r\n return path[path.length - 1];\r\n}\r\n"],"mappings":"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","names":["typeorm_exports","__export","TypeOrmQueryAdapter","__toCommonJS","import_typeorm","ensureArray","fieldName","data","minLength","__name","ensureEmpty","isValid","value","getOffset","offset","limit","page","pathEquals","path1","path2","p1","i","__name","pathHasBase","path","base","start","i","__name","pathGetBaseAndName","name","TypeOrmQueryAdapter","options","__name","qb","query","request","offset","getOffset","fullQuery","data","total","limit","count","page","pageCount","paramsDefined","isILikeEnabled","mainAlias","alias","select","fields","f","baseAlias","relations","relation","path","pathHasBase","ordering","order","fieldBase","fieldName","pathGetBaseAndName","where","or","params","addWhere","wqb","item","param","field","name","iteration","source","defaults","rule","metadata","relationPath","part","pathBase","pathField","operator","value","ensureArray","arr","ensureEmpty","base","r","pathEquals","not","ilikeEnabled","isValid","type"]}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
var T=Object.defineProperty;var
|
1
|
+
var T=Object.defineProperty;var f=(l,t)=>T(l,"name",{value:t,configurable:!0});import{Brackets as w}from"typeorm";function h(l,t,r=0){if(!Array.isArray(t)||t.length<r)throw new Error(`${l} must be an array with at least ${r} items`);return t}f(h,"ensureArray");function E(l,t){if(p(t)&&t!==!0)throw new Error(`${l} must be true, null or undefined`)}f(E,"ensureEmpty");function p(l){return l!=null}f(p,"isValid");function y(l,t,r){return l??(t&&r?t*r:0)}f(y,"getOffset");function L(l,t){return l.length!==t.length?!1:l.every((r,n)=>t[n]===r)}f(L,"pathEquals");function $(l,t){return l.length-1!==t.length?!1:t.every((r,n)=>l[n]===r)}f($,"pathHasBase");function N(l){if(l.length===0)throw new Error("Cannot break an empty path");let t=[...l],r=t.pop();return[t,r]}f(N,"pathGetBaseAndName");var m=class{constructor(t={}){this.options=t}static{f(this,"TypeOrmQueryAdapter")}build(t,r){return t=this.createBaseQuery(t,r),t=this.paginateQuery(t,r),t}async getOne(t,r){return await this.createBaseQuery(t,r).getOne()??null}async getMany(t,r){let n=y(r.offset,r.limit,r.page),e=this.createBaseQuery(t,r),a=await this.paginateQuery(e.clone(),r,n).getMany(),u=await e.getCount(),d=r.limit??u,i=a.length,c=Math.floor(n/d)+1,o=Math.ceil(u/d);return{data:a,count:i,page:c,pageCount:o,total:u}}createBaseQuery(t,r){let n=[],e=this.isILikeEnabled(t),s=t.expressionMap.mainAlias;if(!s)throw new Error("No main alias found in query builder");return this.adaptSelect(t,s,r.select),this.adaptRelations(t,s,r.relations,r.select),this.adaptWhere(s,r.relations,t,r.where,!1,n,e),this.adaptOrder(t,s,r.relations,r.order),t}paginateQuery(t,r,n){return t.limit(r.limit).offset(n)}adaptSelect(t,r,n){if(n.length===0)return;let e=n.filter(s=>s.field.length===1).filter(s=>this.validateField(r,s.field,"select"));t.select(e.map(s=>[r.name,...s.field].join(".")))}adaptRelations(t,r,n,e){for(let s of n){let a=[r.name,...s.field].join("."),u=s.alias||[r.name,...s.field].join("_"),d=e.filter(i=>$(i.field,s.field)).filter(i=>this.validateField(r,i.field,"select"));d.length===0?t.leftJoinAndSelect(a,u):(t.leftJoin(a,u),t.addSelect(d.map(i=>[u,i.field[i.field.length-1]].join("."))))}}adaptOrder(t,r,n,e){for(let s of e){if(!this.validateField(r,s.field,"order"))continue;let[a,u]=N(s.field),i=this.getFieldAlias(r,n,a)+"."+u;t.addOrderBy(i,s.order)}}adaptWhere(t,r,n,e,s,a,u){let d=(s?n.orWhere:n.andWhere).bind(n);if(e.or&&e.or.length>0)d(new w(i=>e.or.forEach(c=>this.adaptWhere(t,r,i,c,!0,a,u))));else if(e.and&&e.and.length>0)d(new w(i=>e.and.forEach(c=>this.adaptWhere(t,r,i,c,!1,a,u))));else if(e.field){if(!this.validateField(t,e.field,"where"))return;let i=this.createParam(a,e.field),c=this.mapWhereOperators(t,r,e,i,u);d(c.where,c.params)}}createParam(t,r){let n=r.length>0?r[r.length-1]:"",e,s=0;do e="req_"+n+"_"+s,s++;while(t.includes(e));return t.push(e),e}validateField(t,r,n){if(this.isFieldValid(t,r))return!0;let s={select:"ignore",order:"ignore",where:"deny"},a=this.options.invalidFields?.[n]||s[n];if(a==="ignore")return!1;if(a==="allow-unsafe")return!0;if(a==="deny")throw new Error(`${n} field "${r.join(".")}" is invalid.`);return!1}isFieldValid(t,r){if(r.length===0)return!1;let n=t.metadata,e=[...r],s=e.pop();for(let u of e){let d=n.findRelationWithPropertyPath(u);if(!d)return!1;n=d.inverseEntityMetadata}return!!n.findColumnWithPropertyPathStrict(s)}mapWhereOperators(t,r,n,e,s){let[a,u]=N(n.field),i=this.getFieldAlias(t,r,a)+"."+u,c=n.operator,o=n.value;switch(c){case"eq":return{where:`${i} = :${e}`,params:{[e]:o}};case"neq":return{where:`${i} != :${e}`,params:{[e]:o}};case"gt":return{where:`${i} > :${e}`,params:{[e]:o}};case"gte":return{where:`${i} >= :${e}`,params:{[e]:o}};case"lt":return{where:`${i} < :${e}`,params:{[e]:o}};case"lte":return{where:`${i} <= :${e}`,params:{[e]:o}};case"starts":return{where:`${i} LIKE :${e}`,params:{[e]:`${o}%`}};case"ends":return{where:`${i} LIKE :${e}`,params:{[e]:`%${o}`}};case"contains":return{where:`${i} LIKE :${e}`,params:{[e]:`%${o}%`}};case"not_contains":return{where:`${i} NOT LIKE :${e}`,params:{[e]:`%${o}%`}};case"in":return o=h("IN operator",o,1),{where:`${i} IN (:...${e})`,params:{[e]:o}};case"not_in":return o=h("NOT IN operator",o,1),{where:`${i} NOT IN (:...${e})`,params:{[e]:o}};case"between":let g=h("BETWEEN operator",o,2);return{where:`${i} BETWEEN :${e}_start AND :${e}_end`,params:{[`${e}_start`]:g[0],[`${e}_end`]:g[1]}};case"is_null":return E("IS NULL operator",o),{where:`${i} IS NULL`,params:{}};case"not_null":return E("NOT NULL operator",o),{where:`${i} IS NOT NULL`,params:{}};case"eq_lower":return{where:`LOWER(${i}) = :${e}`,params:{[e]:o}};case"neq_lower":return{where:`LOWER(${i}) != :${e}`,params:{[e]:o}};case"starts_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`${o}%`}};case"ends_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`%${o}`}};case"contains_lower":return{where:`${this.createLowerLike(s,i)} :${e}`,params:{[e]:`%${o}%`}};case"not_contains_lower":return{where:`${this.createLowerLike(s,i,!0)} :${e}`,params:{[e]:`%${o}%`}};case"in_lower":return h("IN operator",o,1),{where:`LOWER(${i}) IN (...:${e})`,params:{[e]:o}};case"not_in_lower":return h("NOT IN operator",o,1),{where:`LOWER(${i}) NOT IN (...:${e})`,params:{[e]:o}};default:throw new Error(`Unknown operator "${c}"`)}}getFieldAlias(t,r,n){if(n.length===0)return t.name;let e=r.find(s=>L(s.field,n));return e&&e.alias?e.alias:[t.name,...n].join("_")}createLowerLike(t,r,n=!1){return t?n?`${r} NOT ILIKE`:`${r} ILIKE`:n?`LOWER(${r}) NOT LIKE`:`LOWER(${r}) LIKE`}isILikeEnabled(t){let r=this.options.ilike;if(p(r))return r;let n=t.connection.options.type;return n==="postgres"||n==="aurora-postgres"}};export{m as TypeOrmQueryAdapter};
|
2
2
|
//# sourceMappingURL=index.mjs.map
|