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.
Files changed (38) hide show
  1. package/README.md +37 -11
  2. package/dist/adapters/typeorm/index.d.mts +104 -10
  3. package/dist/adapters/typeorm/index.d.ts +104 -10
  4. package/dist/adapters/typeorm/index.js +1 -1
  5. package/dist/adapters/typeorm/index.js.map +1 -1
  6. package/dist/adapters/typeorm/index.mjs +1 -1
  7. package/dist/adapters/typeorm/index.mjs.map +1 -1
  8. package/dist/{parsed-request-where.builder-DME55XmN.d.ts → crud-request-where.builder-B5241Aht.d.ts} +7 -7
  9. package/dist/{parsed-request-where.builder-DRZUAxu4.d.mts → crud-request-where.builder-BwWLx0Bh.d.mts} +7 -7
  10. package/dist/{crud-request-CvDKp6Iy.d.mts → crud-request-x16CuDRF.d.mts} +1 -0
  11. package/dist/{crud-request-CvDKp6Iy.d.ts → crud-request-x16CuDRF.d.ts} +1 -0
  12. package/dist/filters/index.d.mts +11 -2
  13. package/dist/filters/index.d.ts +11 -2
  14. package/dist/filters/index.js +1 -1
  15. package/dist/filters/index.js.map +1 -1
  16. package/dist/filters/index.mjs +1 -1
  17. package/dist/filters/index.mjs.map +1 -1
  18. package/dist/helpers/nestjs/index.d.mts +2 -2
  19. package/dist/helpers/nestjs/index.d.ts +2 -2
  20. package/dist/helpers/nestjs/index.js.map +1 -1
  21. package/dist/helpers/nestjs/index.mjs.map +1 -1
  22. package/dist/index.d.mts +4 -4
  23. package/dist/index.d.ts +4 -4
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +1 -1
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/parsers/crud/index.d.mts +34 -9
  29. package/dist/parsers/crud/index.d.ts +34 -9
  30. package/dist/parsers/crud/index.js +1 -1
  31. package/dist/parsers/crud/index.js.map +1 -1
  32. package/dist/parsers/crud/index.mjs +1 -1
  33. package/dist/parsers/crud/index.mjs.map +1 -1
  34. package/dist/{query-adapter-Vebxws3V.d.ts → query-adapter-CEcyFcWr.d.ts} +1 -1
  35. package/dist/{query-adapter-BliD9hJN.d.mts → query-adapter-CeTK3yxp.d.mts} +1 -1
  36. package/dist/{request-parser-WaQBZsYG.d.mts → request-parser-BMkszvGr.d.mts} +1 -1
  37. package/dist/{request-parser-B-fK5GnP.d.ts → request-parser-BxVulcsX.d.ts} +1 -1
  38. 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 @crud-query-parser/core
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
- This parser fully compatible with `@nestjsx/crud`
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 { Q as QueryAdapter, G as GetManyResult } from '../../query-adapter-BliD9hJN.mjs';
3
- import { c as CrudRequest, P as ParsedRequestSelect, a as CrudRequestRelation, b as CrudRequestOrder, d as CrudRequestWhere, g as CrudRequestWhereField } from '../../crud-request-CvDKp6Iy.mjs';
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 TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {
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 { TypeormQueryAdapter };
178
+ export { TypeOrmQueryAdapter, type TypeOrmQueryAdapterOptions };
@@ -1,11 +1,56 @@
1
1
  import { SelectQueryBuilder, ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
2
- import { Q as QueryAdapter, G as GetManyResult } from '../../query-adapter-Vebxws3V.js';
3
- import { c as CrudRequest, P as ParsedRequestSelect, a as CrudRequestRelation, b as CrudRequestOrder, d as CrudRequestWhere, g as CrudRequestWhereField } from '../../crud-request-CvDKp6Iy.js';
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 TypeormQueryAdapter implements QueryAdapter<SelectQueryBuilder<any>, ObjectLiteral> {
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 { TypeormQueryAdapter };
178
+ export { TypeOrmQueryAdapter, type TypeOrmQueryAdapterOptions };
@@ -1,2 +1,2 @@
1
- "use strict";var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var u=(i,t)=>c(i,"name",{value:t,configurable:!0});var O=(i,t)=>{for(var e in t)c(i,e,{get:t[e],enumerable:!0})},S=(i,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of _(t))!y.call(i,s)&&s!==e&&c(i,s,{get:()=>t[s],enumerable:!(r=f(t,s))||r.enumerable});return i};var w=i=>S(c({},"__esModule",{value:!0}),i);var R={};O(R,{TypeormQueryAdapter:()=>N});module.exports=w(R);var E=require("typeorm");function a(i,t,e=0){if(!Array.isArray(t)||t.length<e)throw new Error(`${i} must be an array with at least ${e} items`);return t}u(a,"ensureArray");function d(i,t){if(t)throw new Error(`${i} must be null`)}u(d,"ensureFalsy");var N=class{static{u(this,"TypeormQueryAdapter")}build(t,e){return t=this.createBaseQuery(t,e),t=this.paginateQuery(t,e),t}async getOne(t,e){return await this.createBaseQuery(t,e).getOne()??null}async getMany(t,e){let r=this.createBaseQuery(t,e),n=await this.paginateQuery(r.clone(),e).getMany(),o=await r.getCount(),l=e.offset??0,$=e.limit??o,L=n.length,h=Math.floor(l/$)+1,T=Math.ceil(o/$);return{data:n,count:L,page:h,pageCount:T,total:o}}createBaseQuery(t,e){let r=[];return this.adaptSelect(t,e.select),this.adaptRelations(t,e.relations),this.adaptWhere(t,e.where,!1,r),this.adaptOrder(t,e.order),t}paginateQuery(t,e){return t.limit(e.limit).offset(e.offset)}adaptSelect(t,e){t.addSelect(e.map(r=>r.field.join(".")))}adaptRelations(t,e){for(let r of e){let s=r.field.join("."),n=r.alias||s.replace(".","_");t.leftJoin(s,n)}}adaptOrder(t,e){for(let r of e){let s=r.field.join(".");t.addOrderBy(s,r.order)}}adaptWhere(t,e,r,s){let n=(r?t.orWhere:t.andWhere).bind(t);if(e.or&&e.or.length>0)n(new E.Brackets(o=>e.or.forEach(l=>this.adaptWhere(o,l,!0,s))));else if(e.and&&e.and.length>0)n(new E.Brackets(o=>e.and.forEach(l=>this.adaptWhere(o,l,!1,s))));else if(e.field){let o=this.createParam(s,e.field),l=this.mapWhereOperators(e,o);n(l.where,l.params)}}createParam(t,e){let r=e.length>0?e[e.length-1]:"",s,n=0;do s="req_"+r+"_"+n,n++;while(t.includes(s));return t.push(s),s}mapWhereOperators(t,e){let r=t.field.join("."),s=t.operator,n=t.value;switch(s){case"eq":return{where:`${r} = :${e}`,params:{[e]:n}};case"neq":return{where:`${r} != :${e}`,params:{[e]:n}};case"gt":return{where:`${r} > :${e}`,params:{[e]:n}};case"gte":return{where:`${r} >= :${e}`,params:{[e]:n}};case"lt":return{where:`${r} < :${e}`,params:{[e]:n}};case"lte":return{where:`${r} <= :${e}`,params:{[e]:n}};case"starts":return{where:`${r} LIKE :${e}`,params:{[e]:`${n}%`}};case"ends":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}`}};case"contains":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}%`}};case"not_contains":return{where:`${r} NOT LIKE :${e}`,params:{[e]:`%${n}%`}};case"in":return n=a("IN operator",n,1),{where:`${r} IN (:...${e})`,params:{[e]:n}};case"not_in":return n=a("NOT IN operator",n,1),{where:`${r} NOT IN (:...${e})`,params:{[e]:n}};case"between":let o=a("BETWEEN operator",n,2);return{where:`${r} BETWEEN :${e}_start AND :${e}_end`,params:{[`${e}_start`]:o[0],[`${e}_end`]:o[1]}};case"is_null":return d("IS NULL operator",n),{where:`${r} IS NULL`,params:{}};case"not_null":return d("NOT NULL operator",n),{where:`${r} IS NOT NULL`,params:{}};case"eq_lower":return{where:`LOWER(${r}) = :${e}`,params:{[e]:n}};case"neq_lower":return{where:`LOWER(${r}) != :${e}`,params:{[e]:n}};case"starts_lower":return{where:`LOWER(${r}) LIKE :${e}`,params:{[e]:`${n}%`}};case"ends_lower":return{where:`LOWER(${r}) LIKE :${e}`,params:{[e]:`%${n}`}};case"contains_lower":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}%`}};case"not_contains_lower":return{where:`${r} NOT LIKE :${e}`,params:{[e]:`%${n}%`}};case"in_lower":return a("IN operator",n,1),{where:`${r} IN (...:${e})`,params:{[e]:n}};case"not_in_lower":return a("NOT IN operator",n,1),{where:`${r} NOT IN (...:${e})`,params:{[e]:n}};default:throw new Error(`Unknown operator "${s}"`)}}};0&&(module.exports={TypeormQueryAdapter});
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":"4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,IAAA,eAAAC,EAAAH,GCAA,IAAAI,EAAoF,mBCiB7E,SAASC,EAAeC,EAAmBC,EAAiBC,EAAoB,EAAQ,CAC7F,GAAI,CAAC,MAAM,QAAQD,CAAI,GAAKA,EAAK,OAASC,EACxC,MAAM,IAAI,MAAM,GAAGF,CAAS,mCAAmCE,CAAS,QAAQ,EAElF,OAAOD,CACT,CALgBE,EAAAJ,EAAA,eAOT,SAASK,EAAYJ,EAAmBC,EAAW,CACxD,GAAIA,EACF,MAAM,IAAI,MAAM,GAAGD,CAAS,eAAe,CAC/C,CAHgBG,EAAAC,EAAA,eDLT,IAAMC,EAAN,KAA0F,CAnBjG,MAmBiG,CAAAC,EAAA,4BAKxF,MAA+BC,EAA2BC,EAA2C,CAC1G,OAAAD,EAAK,KAAK,gBAAgBA,EAAIC,CAAK,EACnCD,EAAK,KAAK,cAAcA,EAAIC,CAAK,EAE1BD,CACT,CAKA,MAAa,OAAgCA,EAAiCE,EAAyC,CAIrH,OAFe,MADD,KAAK,gBAAgBF,EAAIE,CAAO,EACnB,OAAO,GAEjB,IACnB,CAKA,MAAa,QAAiCF,EAAiCE,EAAiD,CAC9H,IAAMC,EAAY,KAAK,gBAAgBH,EAAIE,CAAO,EAG5CE,EAAO,MAFU,KAAK,cAAcD,EAAU,MAAM,EAAGD,CAAO,EAElC,QAAQ,EACpCG,EAAQ,MAAMF,EAAU,SAAS,EAEjCG,EAASJ,EAAQ,QAAU,EAC3BK,EAAQL,EAAQ,OAASG,EAEzBG,EAAQJ,EAAK,OACbK,EAAO,KAAK,MAAMH,EAASC,CAAK,EAAI,EACpCG,EAAY,KAAK,KAAKL,EAAQE,CAAK,EAEzC,MAAO,CACL,KAAAH,EACA,MAAAI,EACA,KAAAC,EACA,UAAAC,EACA,MAAAL,CACF,CACF,CAQU,gBAAyCL,EAA2BC,EAA2C,CACvH,IAAMU,EAA0B,CAAC,EAEjC,YAAK,YAAYX,EAAIC,EAAM,MAAM,EACjC,KAAK,eAAeD,EAAIC,EAAM,SAAS,EACvC,KAAK,WAAWD,EAAIC,EAAM,MAAO,GAAOU,CAAa,EACrD,KAAK,WAAWX,EAAIC,EAAM,KAAK,EAExBD,CACT,CAQU,cAAuCA,EAA2BC,EAA2C,CACrH,OAAOD,EAAG,MAAMC,EAAM,KAAK,EAAE,OAAOA,EAAM,MAAM,CAClD,CAQU,YAAqCD,EAA2BY,EAAmC,CAC3GZ,EAAG,UAAUY,EAAO,IAAIC,GAAKA,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC,CACjD,CAQU,eAAwCb,EAA2Bc,EAAwC,CACnH,QAAWC,KAAYD,EAAW,CAChC,IAAME,EAAOD,EAAS,MAAM,KAAK,GAAG,EAC9BE,EAAQF,EAAS,OAASC,EAAK,QAAQ,IAAK,GAAG,EAErDhB,EAAG,SAASgB,EAAMC,CAAK,CACzB,CACF,CAQU,WAAoCjB,EAA2BkB,EAAoC,CAC3G,QAAWC,KAASD,EAAU,CAC5B,IAAMF,EAAOG,EAAM,MAAM,KAAK,GAAG,EAEjCnB,EAAG,WAAWgB,EAAMG,EAAM,KAAK,CACjC,CACF,CAUU,WAAWnB,EAA4BoB,EAAyBC,EAAaC,EAAwB,CAC7G,IAAMC,GAAYF,EAAKrB,EAAG,QAAUA,EAAG,UAAU,KAAKA,CAAE,EAExD,GAAIoB,EAAM,IAAMA,EAAM,GAAG,OAAS,EAChCG,EAAS,IAAI,WACXC,GAAOJ,EAAM,GAAI,QAAQK,GAAQ,KAAK,WAAWD,EAAKC,EAAM,GAAMH,CAAM,CAAC,CAC3E,CAAC,UACQF,EAAM,KAAOA,EAAM,IAAI,OAAS,EACzCG,EAAS,IAAI,WACXC,GAAOJ,EAAM,IAAK,QAAQK,GAAQ,KAAK,WAAWD,EAAKC,EAAM,GAAOH,CAAM,CAAC,CAC7E,CAAC,UACQF,EAAM,MAAO,CACtB,IAAMM,EAAQ,KAAK,YAAYJ,EAAQF,EAAM,KAAK,EAC5CnB,EAAQ,KAAK,kBAAkBmB,EAAgCM,CAAK,EAE1EH,EAAStB,EAAM,MAAOA,EAAM,MAAM,CACpC,CACF,CAQU,YAAYU,EAAyBgB,EAAyB,CACtE,IAAMC,EAAOD,EAAM,OAAS,EAAIA,EAAMA,EAAM,OAAS,CAAC,EAAI,GACtDD,EACAG,EAAoB,EAExB,GACEH,EAAQ,OAASE,EAAO,IAAMC,EAC9BA,UACOlB,EAAc,SAASe,CAAK,GAErC,OAAAf,EAAc,KAAKe,CAAK,EACjBA,CACT,CAQU,kBAAkBN,EAA8BM,EAAyD,CACjH,IAAMC,EAAQP,EAAM,MAAM,KAAK,GAAG,EAC5BU,EAAWV,EAAM,SACnBW,EAAiBX,EAAM,MAE3B,OAAQU,EAAU,CAChB,SACE,MAAO,CAAE,MAAO,GAAGH,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAEtE,SACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAEtE,SACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAEtE,aACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,GAAGK,CAAK,GAAI,CAAE,EAE9E,WACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,EAAG,CAAE,EAE9E,eACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,GAAI,CAAE,EAE/E,mBACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,cAAcD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,GAAI,CAAE,EAEnF,SACE,OAAAA,EAAQC,EAAY,cAAeD,EAAO,CAAC,EAEpC,CAAE,MAAO,GAAGJ,CAAK,YAAYD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE3E,aACE,OAAAA,EAAQC,EAAY,kBAAmBD,EAAO,CAAC,EAExC,CAAE,MAAO,GAAGJ,CAAK,gBAAgBD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE/E,cACE,IAAME,EAAMD,EAAY,mBAAoBD,EAAO,CAAC,EAEpD,MAAO,CACL,MAAO,GAAGJ,CAAK,aAAaD,CAAK,eAAeA,CAAK,OACrD,OAAQ,CAAE,CAAC,GAAGA,CAAK,QAAQ,EAAGO,EAAI,CAAC,EAAG,CAAC,GAAGP,CAAK,MAAM,EAAGO,EAAI,CAAC,CAAE,CACjE,EAEF,cACE,OAAAC,EAAY,mBAAoBH,CAAK,EAE9B,CAAE,MAAO,GAAGJ,CAAK,WAAY,OAAQ,CAAC,CAAE,EAEjD,eACE,OAAAO,EAAY,oBAAqBH,CAAK,EAE/B,CAAE,MAAO,GAAGJ,CAAK,eAAgB,OAAQ,CAAC,CAAE,EAErD,eACE,MAAO,CAAE,MAAO,SAASA,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE5E,gBACE,MAAO,CAAE,MAAO,SAASJ,CAAK,SAASD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE7E,mBACE,MAAO,CAAE,MAAO,SAASJ,CAAK,WAAWD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,GAAGK,CAAK,GAAI,CAAE,EAErF,iBACE,MAAO,CAAE,MAAO,SAASJ,CAAK,WAAWD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,EAAG,CAAE,EAErF,qBACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,GAAI,CAAE,EAE/E,yBACE,MAAO,CAAE,MAAO,GAAGJ,CAAK,cAAcD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIK,CAAK,GAAI,CAAE,EAEnF,eACE,OAAAC,EAAY,cAAeD,EAAO,CAAC,EAE5B,CAAE,MAAO,GAAGJ,CAAK,YAAYD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE3E,mBACE,OAAAC,EAAY,kBAAmBD,EAAO,CAAC,EAEhC,CAAE,MAAO,GAAGJ,CAAK,gBAAgBD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGK,CAAM,CAAE,EAE/E,QACE,MAAM,IAAI,MAAM,qBAAqBD,CAAQ,GAAG,CACpD,CACF,CAEF","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 u=(l,t)=>T(l,"name",{value:t,configurable:!0});import{Brackets as E}from"typeorm";function a(l,t,e=0){if(!Array.isArray(t)||t.length<e)throw new Error(`${l} must be an array with at least ${e} items`);return t}u(a,"ensureArray");function c(l,t){if(t)throw new Error(`${l} must be null`)}u(c,"ensureFalsy");var N=class{static{u(this,"TypeormQueryAdapter")}build(t,e){return t=this.createBaseQuery(t,e),t=this.paginateQuery(t,e),t}async getOne(t,e){return await this.createBaseQuery(t,e).getOne()??null}async getMany(t,e){let r=this.createBaseQuery(t,e),n=await this.paginateQuery(r.clone(),e).getMany(),i=await r.getCount(),o=e.offset??0,d=e.limit??i,$=n.length,L=Math.floor(o/d)+1,h=Math.ceil(i/d);return{data:n,count:$,page:L,pageCount:h,total:i}}createBaseQuery(t,e){let r=[];return this.adaptSelect(t,e.select),this.adaptRelations(t,e.relations),this.adaptWhere(t,e.where,!1,r),this.adaptOrder(t,e.order),t}paginateQuery(t,e){return t.limit(e.limit).offset(e.offset)}adaptSelect(t,e){t.addSelect(e.map(r=>r.field.join(".")))}adaptRelations(t,e){for(let r of e){let s=r.field.join("."),n=r.alias||s.replace(".","_");t.leftJoin(s,n)}}adaptOrder(t,e){for(let r of e){let s=r.field.join(".");t.addOrderBy(s,r.order)}}adaptWhere(t,e,r,s){let n=(r?t.orWhere:t.andWhere).bind(t);if(e.or&&e.or.length>0)n(new E(i=>e.or.forEach(o=>this.adaptWhere(i,o,!0,s))));else if(e.and&&e.and.length>0)n(new E(i=>e.and.forEach(o=>this.adaptWhere(i,o,!1,s))));else if(e.field){let i=this.createParam(s,e.field),o=this.mapWhereOperators(e,i);n(o.where,o.params)}}createParam(t,e){let r=e.length>0?e[e.length-1]:"",s,n=0;do s="req_"+r+"_"+n,n++;while(t.includes(s));return t.push(s),s}mapWhereOperators(t,e){let r=t.field.join("."),s=t.operator,n=t.value;switch(s){case"eq":return{where:`${r} = :${e}`,params:{[e]:n}};case"neq":return{where:`${r} != :${e}`,params:{[e]:n}};case"gt":return{where:`${r} > :${e}`,params:{[e]:n}};case"gte":return{where:`${r} >= :${e}`,params:{[e]:n}};case"lt":return{where:`${r} < :${e}`,params:{[e]:n}};case"lte":return{where:`${r} <= :${e}`,params:{[e]:n}};case"starts":return{where:`${r} LIKE :${e}`,params:{[e]:`${n}%`}};case"ends":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}`}};case"contains":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}%`}};case"not_contains":return{where:`${r} NOT LIKE :${e}`,params:{[e]:`%${n}%`}};case"in":return n=a("IN operator",n,1),{where:`${r} IN (:...${e})`,params:{[e]:n}};case"not_in":return n=a("NOT IN operator",n,1),{where:`${r} NOT IN (:...${e})`,params:{[e]:n}};case"between":let i=a("BETWEEN operator",n,2);return{where:`${r} BETWEEN :${e}_start AND :${e}_end`,params:{[`${e}_start`]:i[0],[`${e}_end`]:i[1]}};case"is_null":return c("IS NULL operator",n),{where:`${r} IS NULL`,params:{}};case"not_null":return c("NOT NULL operator",n),{where:`${r} IS NOT NULL`,params:{}};case"eq_lower":return{where:`LOWER(${r}) = :${e}`,params:{[e]:n}};case"neq_lower":return{where:`LOWER(${r}) != :${e}`,params:{[e]:n}};case"starts_lower":return{where:`LOWER(${r}) LIKE :${e}`,params:{[e]:`${n}%`}};case"ends_lower":return{where:`LOWER(${r}) LIKE :${e}`,params:{[e]:`%${n}`}};case"contains_lower":return{where:`${r} LIKE :${e}`,params:{[e]:`%${n}%`}};case"not_contains_lower":return{where:`${r} NOT LIKE :${e}`,params:{[e]:`%${n}%`}};case"in_lower":return a("IN operator",n,1),{where:`${r} IN (...:${e})`,params:{[e]:n}};case"not_in_lower":return a("NOT IN operator",n,1),{where:`${r} NOT IN (...:${e})`,params:{[e]:n}};default:throw new Error(`Unknown operator "${s}"`)}}};export{N as TypeormQueryAdapter};
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