crud-query-parser 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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":"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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":"4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,IAAA,eAAAC,EAAAH,GCAA,IAAAI,EAAoF,mBC8B7E,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,GAAII,EAAQJ,CAAI,GAAKA,IAAS,GAC5B,MAAM,IAAI,MAAM,GAAGD,CAAS,kCAAkC,CAClE,CAHgBG,EAAAC,EAAA,eAKT,SAASC,EAAWC,EAAyC,CAClE,OAAOA,GAAU,IACnB,CAFgBH,EAAAE,EAAA,WAIT,SAASE,EAAUC,EAA4BC,EAAgBC,EAAuB,CAC3F,OAAOF,IAAWC,GAASC,EAAOD,EAAQC,EAAO,EACnD,CAFgBP,EAAAI,EAAA,aCzCT,SAASI,EAAWC,EAAiBC,EAA0B,CACpE,OAAID,EAAM,SAAWC,EAAM,OAClB,GAEFD,EAAM,MAAM,CAACE,EAAIC,IAAMF,EAAME,CAAC,IAAMD,CAAE,CAC/C,CALgBE,EAAAL,EAAA,cAwBT,SAASM,EAAYC,EAAgBC,EAAyB,CACnE,OAAID,EAAK,OAAS,IAAMC,EAAK,OACpB,GAEFA,EAAK,MAAM,CAACC,EAAOC,IAAMH,EAAKG,CAAC,IAAMD,CAAK,CACnD,CALgBE,EAAAL,EAAA,eAYT,SAASM,EAAmBL,EAAoC,CACrE,GAAIA,EAAK,SAAW,EAClB,MAAM,IAAI,MAAM,4BAA4B,EAE9C,IAAMC,EAAO,CAAC,GAAGD,CAAI,EACfM,EAAOL,EAAK,IAAI,EAEtB,MAAO,CAACA,EAAMK,CAAI,CACpB,CARgBF,EAAAC,EAAA,sBFkBT,IAAME,EAAN,KAA0F,CAE/F,YACmBC,EAAsC,CAAC,EACxD,CADiB,aAAAA,CAChB,CA/DL,MA2DiG,CAAAC,EAAA,4BASxF,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,EAASC,EAAUF,EAAQ,OAAQA,EAAQ,MAAOA,EAAQ,IAAI,EAE9DG,EAAY,KAAK,gBAAgBL,EAAIE,CAAO,EAG5CI,EAAO,MAFU,KAAK,cAAcD,EAAU,MAAM,EAAGH,EAASC,CAAM,EAE1C,QAAQ,EACpCI,EAAQ,MAAMF,EAAU,SAAS,EAEjCG,EAAQN,EAAQ,OAASK,EAEzBE,EAAQH,EAAK,OACbI,EAAO,KAAK,MAAMP,EAASK,CAAK,EAAI,EACpCG,EAAY,KAAK,KAAKJ,EAAQC,CAAK,EAEzC,MAAO,CACL,KAAAF,EACA,MAAAG,EACA,KAAAC,EACA,UAAAC,EACA,MAAAJ,CACF,CACF,CAQU,gBAAyCP,EAA2BC,EAA2C,CACvH,IAAMW,EAA0B,CAAC,EAC3BC,EAAiB,KAAK,eAAeb,CAAE,EACvCc,EAAYd,EAAG,cAAc,UAEnC,GAAI,CAACc,EACH,MAAM,IAAI,MAAM,sCAAsC,EAExD,YAAK,YAAYd,EAAIc,EAAWb,EAAM,MAAM,EAC5C,KAAK,eAAeD,EAAIc,EAAWb,EAAM,UAAWA,EAAM,MAAM,EAChE,KAAK,WAAWa,EAAWb,EAAM,UAAWD,EAAIC,EAAM,MAAO,GAAOW,EAAeC,CAAc,EACjG,KAAK,WAAWb,EAAIc,EAAWb,EAAM,UAAWA,EAAM,KAAK,EAEpDD,CACT,CASU,cAAuCA,EAA2BC,EAAoBE,EAAwC,CACtI,OAAOH,EAAG,MAAMC,EAAM,KAAK,EAAE,OAAOE,CAAM,CAC5C,CASU,YACRH,EACAe,EACAC,EACM,CACN,GAAIA,EAAO,SAAW,EACpB,OAGF,IAAMC,EAASD,EACZ,OAAOE,GAAKA,EAAE,MAAM,SAAW,CAAC,EAChC,OAAOA,GAAK,KAAK,cAAcH,EAAOG,EAAE,MAAO,QAAQ,CAAC,EAE3DlB,EAAG,OAAOiB,EAAO,IAAI,GAAK,CAACF,EAAM,KAAM,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAC/D,CAUU,eACRf,EACAmB,EACAC,EACAJ,EACM,CACN,QAAWK,KAAYD,EAAW,CAChC,IAAME,EAAO,CAACH,EAAU,KAAM,GAAGE,EAAS,KAAK,EAAE,KAAK,GAAG,EACnDN,EAAQM,EAAS,OAAS,CAACF,EAAU,KAAM,GAAGE,EAAS,KAAK,EAAE,KAAK,GAAG,EAEtEJ,EAASD,EACZ,OAAOE,GAAKK,EAAYL,EAAE,MAAOG,EAAS,KAAK,CAAC,EAChD,OAAOH,GAAK,KAAK,cAAcC,EAAWD,EAAE,MAAO,QAAQ,CAAC,EAE3DD,EAAO,SAAW,EACpBjB,EAAG,kBAAkBsB,EAAMP,CAAK,GAEhCf,EAAG,SAASsB,EAAMP,CAAK,EACvBf,EAAG,UAAUiB,EAAO,IAAIC,GAAK,CAACH,EAAOG,EAAE,MAAMA,EAAE,MAAM,OAAS,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAEhF,CACF,CAUU,WACRlB,EACAe,EACAK,EACAI,EACM,CACN,QAAWC,KAASD,EAAU,CAC5B,GAAI,CAAC,KAAK,cAAcT,EAAOU,EAAM,MAAO,OAAO,EACjD,SAEF,GAAM,CAACC,EAAWC,CAAS,EAAIC,EAAmBH,EAAM,KAAK,EAGvDH,EAFY,KAAK,cAAcP,EAAOK,EAAWM,CAAS,EAEvC,IAAMC,EAE/B3B,EAAG,WAAWsB,EAAMG,EAAM,KAAK,CACjC,CACF,CAaU,WACRV,EACAK,EACApB,EACA6B,EACAC,EACAC,EACAlB,EACM,CACN,IAAMmB,GAAYF,EAAK9B,EAAG,QAAUA,EAAG,UAAU,KAAKA,CAAE,EAExD,GAAI6B,EAAM,IAAMA,EAAM,GAAG,OAAS,EAChCG,EAAS,IAAI,WACXC,GAAOJ,EAAM,GAAI,QAAQK,GAAQ,KAAK,WAAWnB,EAAOK,EAAWa,EAAKC,EAAM,GAAMH,EAAQlB,CAAc,CAAC,CAC7G,CAAC,UACQgB,EAAM,KAAOA,EAAM,IAAI,OAAS,EACzCG,EAAS,IAAI,WACXC,GAAOJ,EAAM,IAAK,QAAQK,GAAQ,KAAK,WAAWnB,EAAOK,EAAWa,EAAKC,EAAM,GAAOH,EAAQlB,CAAc,CAAC,CAC/G,CAAC,UACQgB,EAAM,MAAO,CACtB,GAAI,CAAC,KAAK,cAAcd,EAAOc,EAAM,MAAO,OAAO,EACjD,OAEF,IAAMM,EAAQ,KAAK,YAAYJ,EAAQF,EAAM,KAAK,EAC5C5B,EAAQ,KAAK,kBAAkBc,EAAOK,EAAWS,EAAgCM,EAAOtB,CAAc,EAE5GmB,EAAS/B,EAAM,MAAOA,EAAM,MAAM,CACpC,CACF,CAQU,YAAYW,EAAyBwB,EAAyB,CACtE,IAAMC,EAAOD,EAAM,OAAS,EAAIA,EAAMA,EAAM,OAAS,CAAC,EAAI,GACtDD,EACAG,EAAoB,EAExB,GACEH,EAAQ,OAASE,EAAO,IAAMC,EAC9BA,UACO1B,EAAc,SAASuB,CAAK,GAErC,OAAAvB,EAAc,KAAKuB,CAAK,EACjBA,CACT,CASU,cAAcpB,EAAcO,EAAiBiB,EAA+C,CAGpG,GAFgB,KAAK,aAAaxB,EAAOO,CAAI,EAG3C,MAAO,GAET,IAAMkB,EAAW,CACf,OAAQ,SACR,MAAO,SACP,MAAO,MACT,EAEMC,EAAO,KAAK,QAAQ,gBAAgBF,CAAM,GAAKC,EAASD,CAAM,EAEpE,GAAIE,IAAS,SACX,MAAO,GAET,GAAIA,IAAS,eACX,MAAO,GAET,GAAIA,IAAS,OACX,MAAM,IAAI,MAAM,GAAGF,CAAM,WAAWjB,EAAK,KAAK,GAAG,CAAC,eAAe,EAEnE,MAAO,EACT,CAQU,aAAaP,EAAcO,EAA0B,CAC7D,GAAIA,EAAK,SAAW,EAClB,MAAO,GAET,IAAIoB,EAAW3B,EAAM,SAEf4B,EAAe,CAAC,GAAGrB,CAAI,EACvBc,EAAQO,EAAa,IAAI,EAE/B,QAAWC,KAAQD,EAAc,CAC/B,IAAMtB,EAAWqB,EAAS,6BAA6BE,CAAI,EAE3D,GAAI,CAACvB,EACH,MAAO,GAETqB,EAAWrB,EAAS,qBACtB,CAIA,MAAO,CAAC,CAFOqB,EAAS,iCAAiCN,CAAK,CAGhE,CAWU,kBACRrB,EACAK,EACAS,EACAM,EACAtB,EAC0C,CAC1C,GAAM,CAACgC,EAAUC,CAAS,EAAIlB,EAAmBC,EAAM,KAAK,EAGtDO,EAFa,KAAK,cAAcrB,EAAOK,EAAWyB,CAAQ,EAErC,IAAMC,EAE3BC,EAAWlB,EAAM,SACnBmB,EAAiBnB,EAAM,MAE3B,OAAQkB,EAAU,CAChB,SACE,MAAO,CAAE,MAAO,GAAGX,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAEtE,SACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAEtE,SACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,OAAOD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAErE,UACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAEtE,aACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,GAAGa,CAAK,GAAI,CAAE,EAE9E,WACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,EAAG,CAAE,EAE9E,eACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,UAAUD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,GAAI,CAAE,EAE/E,mBACE,MAAO,CAAE,MAAO,GAAGZ,CAAK,cAAcD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,GAAI,CAAE,EAEnF,SACE,OAAAA,EAAQC,EAAY,cAAeD,EAAO,CAAC,EAEpC,CAAE,MAAO,GAAGZ,CAAK,YAAYD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAE3E,aACE,OAAAA,EAAQC,EAAY,kBAAmBD,EAAO,CAAC,EAExC,CAAE,MAAO,GAAGZ,CAAK,gBAAgBD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAE/E,cACE,IAAME,EAAMD,EAAY,mBAAoBD,EAAO,CAAC,EAEpD,MAAO,CACL,MAAO,GAAGZ,CAAK,aAAaD,CAAK,eAAeA,CAAK,OACrD,OAAQ,CAAE,CAAC,GAAGA,CAAK,QAAQ,EAAGe,EAAI,CAAC,EAAG,CAAC,GAAGf,CAAK,MAAM,EAAGe,EAAI,CAAC,CAAE,CACjE,EAEF,cACE,OAAAC,EAAY,mBAAoBH,CAAK,EAE9B,CAAE,MAAO,GAAGZ,CAAK,WAAY,OAAQ,CAAC,CAAE,EAEjD,eACE,OAAAe,EAAY,oBAAqBH,CAAK,EAE/B,CAAE,MAAO,GAAGZ,CAAK,eAAgB,OAAQ,CAAC,CAAE,EAErD,eACE,MAAO,CAAE,MAAO,SAASA,CAAK,QAAQD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAE5E,gBACE,MAAO,CAAE,MAAO,SAASZ,CAAK,SAASD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAE7E,mBACE,MAAO,CAAE,MAAO,GAAG,KAAK,gBAAgBnC,EAAgBuB,CAAK,CAAC,KAAKD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,GAAGa,CAAK,GAAI,CAAE,EAE/G,iBACE,MAAO,CAAE,MAAO,GAAG,KAAK,gBAAgBnC,EAAgBuB,CAAK,CAAC,KAAKD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,EAAG,CAAE,EAE/G,qBACE,MAAO,CAAE,MAAO,GAAG,KAAK,gBAAgBnC,EAAgBuB,CAAK,CAAC,KAAKD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,GAAI,CAAE,EAEhH,yBACE,MAAO,CAAE,MAAO,GAAG,KAAK,gBAAgBnC,EAAgBuB,EAAO,EAAI,CAAC,KAAKD,CAAK,GAAI,OAAQ,CAAE,CAACA,CAAK,EAAG,IAAIa,CAAK,GAAI,CAAE,EAEtH,eACE,OAAAC,EAAY,cAAeD,EAAO,CAAC,EAE5B,CAAE,MAAO,SAASZ,CAAK,aAAaD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAElF,mBACE,OAAAC,EAAY,kBAAmBD,EAAO,CAAC,EAEhC,CAAE,MAAO,SAASZ,CAAK,iBAAiBD,CAAK,IAAK,OAAQ,CAAE,CAACA,CAAK,EAAGa,CAAM,CAAE,EAEtF,QACE,MAAM,IAAI,MAAM,qBAAqBD,CAAQ,GAAG,CACpD,CACF,CASU,cAAchC,EAAcK,EAAkCgC,EAAwB,CAC9F,GAAIA,EAAK,SAAW,EAClB,OAAOrC,EAAM,KAEf,IAAMM,EAAWD,EAAU,KAAKiC,GAAKC,EAAWD,EAAE,MAAOD,CAAI,CAAC,EAE9D,OAAI/B,GAAYA,EAAS,MAChBA,EAAS,MAEX,CAACN,EAAM,KAAM,GAAGqC,CAAI,EAAE,KAAK,GAAG,CACvC,CASU,gBAAgBvC,EAAyBuB,EAAemB,EAAe,GAAe,CAC9F,OAAI1C,EACK0C,EAAM,GAAGnB,CAAK,aAAe,GAAGA,CAAK,SAEvCmB,EAAM,SAASnB,CAAK,aAAe,SAASA,CAAK,QAC1D,CAOU,eAAepC,EAAsC,CAC7D,IAAMwD,EAAe,KAAK,QAAQ,MAElC,GAAIC,EAAQD,CAAY,EACtB,OAAOA,EAET,IAAME,EAAO1D,EAAG,WAAW,QAAQ,KACnC,OAAO0D,IAAS,YAAcA,IAAS,iBACzC,CAEF","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