@ptc-org/nestjs-query-typeorm 0.32.0 → 0.32.1

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 (47) hide show
  1. package/package.json +3 -3
  2. package/src/common/index.d.ts +1 -0
  3. package/src/common/index.js +5 -0
  4. package/src/common/index.js.map +1 -0
  5. package/src/common/randomString.d.ts +1 -0
  6. package/src/common/randomString.js +10 -0
  7. package/src/common/randomString.js.map +1 -0
  8. package/src/index.d.ts +2 -0
  9. package/src/index.js +5 -2
  10. package/src/index.js.map +1 -0
  11. package/src/lib/query-typeorm.d.ts +1 -0
  12. package/src/lib/query-typeorm.js +8 -0
  13. package/src/lib/query-typeorm.js.map +1 -0
  14. package/src/module.d.ts +6 -0
  15. package/src/module.js +19 -0
  16. package/src/module.js.map +1 -0
  17. package/src/providers.d.ts +4 -0
  18. package/src/providers.js +18 -0
  19. package/src/providers.js.map +1 -0
  20. package/src/query/aggregate.builder.d.ts +32 -0
  21. package/src/query/aggregate.builder.js +116 -0
  22. package/src/query/aggregate.builder.js.map +1 -0
  23. package/src/query/filter-query.builder.d.ts +129 -0
  24. package/src/query/filter-query.builder.js +216 -0
  25. package/src/query/filter-query.builder.js.map +1 -0
  26. package/src/query/index.d.ts +5 -0
  27. package/src/query/index.js +9 -0
  28. package/src/query/index.js.map +1 -0
  29. package/src/query/relation-query.builder.d.ts +69 -0
  30. package/src/query/relation-query.builder.js +293 -0
  31. package/src/query/relation-query.builder.js.map +1 -0
  32. package/src/query/sql-comparison.builder.d.ts +42 -0
  33. package/src/query/sql-comparison.builder.js +157 -0
  34. package/src/query/sql-comparison.builder.js.map +1 -0
  35. package/src/query/where.builder.d.ts +60 -0
  36. package/src/query/where.builder.js +102 -0
  37. package/src/query/where.builder.js.map +1 -0
  38. package/src/services/index.d.ts +1 -0
  39. package/src/services/index.js +5 -0
  40. package/src/services/index.js.map +1 -0
  41. package/src/services/relation-query.service.d.ts +132 -0
  42. package/src/services/relation-query.service.js +266 -0
  43. package/src/services/relation-query.service.js.map +1 -0
  44. package/src/services/typeorm-query.service.d.ts +179 -0
  45. package/src/services/typeorm-query.service.js +282 -0
  46. package/src/services/typeorm-query.service.js.map +1 -0
  47. package/CHANGELOG.md +0 -527
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptc-org/nestjs-query-typeorm",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "description": "Typeorm adapter for @nestjs-query/core",
5
5
  "author": "doug-martin <doug@dougamartin.com>",
6
6
  "homepage": "https://github.com/doug-martin/nestjs-query#readme",
@@ -12,7 +12,7 @@
12
12
  "test": "__tests__"
13
13
  },
14
14
  "files": [
15
- "dist/src/**"
15
+ "src/**"
16
16
  ],
17
17
  "publishConfig": {
18
18
  "access": "public"
@@ -30,7 +30,7 @@
30
30
  "@nestjs/typeorm": "^8.0.0",
31
31
  "class-transformer": "^0.2.3 || 0.3.1 || 0.4",
32
32
  "typeorm": "^0.2.25",
33
- "@ptc-org/nestjs-query-core": "0.30.1"
33
+ "@ptc-org/nestjs-query-core": "0.30.2"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@nestjs/common": "8.4.0",
@@ -0,0 +1 @@
1
+ export * from './randomString';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ (0, tslib_1.__exportStar)(require("./randomString"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/query-typeorm/src/common/index.ts"],"names":[],"mappings":";;;AAAA,8DAA+B"}
@@ -0,0 +1 @@
1
+ export declare function randomString(): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.randomString = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const replacer = /-/g;
6
+ function randomString() {
7
+ return (0, uuid_1.v4)().replace(replacer, '');
8
+ }
9
+ exports.randomString = randomString;
10
+ //# sourceMappingURL=randomString.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"randomString.js","sourceRoot":"","sources":["../../../../../packages/query-typeorm/src/common/randomString.ts"],"names":[],"mappings":";;;AAAA,+BAA0B;AAE1B,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB,SAAgB,YAAY;IAC1B,OAAO,IAAA,SAAE,GAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAFD,oCAEC"}
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { TypeOrmQueryService, TypeOrmQueryServiceOpts } from './services';
2
+ export { NestjsQueryTypeOrmModule } from './module';
package/src/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- (0, tslib_1.__exportStar)(require("./lib/query-typeorm"), exports);
3
+ exports.NestjsQueryTypeOrmModule = exports.TypeOrmQueryService = void 0;
4
+ var services_1 = require("./services");
5
+ Object.defineProperty(exports, "TypeOrmQueryService", { enumerable: true, get: function () { return services_1.TypeOrmQueryService; } });
6
+ var module_1 = require("./module");
7
+ Object.defineProperty(exports, "NestjsQueryTypeOrmModule", { enumerable: true, get: function () { return module_1.NestjsQueryTypeOrmModule; } });
5
8
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/query-typeorm/src/index.ts"],"names":[],"mappings":";;;AAAA,uCAA0E;AAAjE,+GAAA,mBAAmB,OAAA;AAC5B,mCAAoD;AAA3C,kHAAA,wBAAwB,OAAA"}
@@ -0,0 +1 @@
1
+ export declare function queryTypeorm(): string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryTypeorm = void 0;
4
+ function queryTypeorm() {
5
+ return 'query-typeorm';
6
+ }
7
+ exports.queryTypeorm = queryTypeorm;
8
+ //# sourceMappingURL=query-typeorm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-typeorm.js","sourceRoot":"","sources":["../../../../../packages/query-typeorm/src/lib/query-typeorm.ts"],"names":[],"mappings":";;;AAAA,SAAgB,YAAY;IAC1B,OAAO,eAAe,CAAC;AACzB,CAAC;AAFD,oCAEC"}
@@ -0,0 +1,6 @@
1
+ import { Class } from '@ptc-org/nestjs-query-core';
2
+ import { DynamicModule } from '@nestjs/common';
3
+ import { Connection, ConnectionOptions } from 'typeorm';
4
+ export declare class NestjsQueryTypeOrmModule {
5
+ static forFeature(entities: Class<unknown>[], connection?: Connection | ConnectionOptions | string): DynamicModule;
6
+ }
package/src/module.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NestjsQueryTypeOrmModule = void 0;
4
+ const typeorm_1 = require("@nestjs/typeorm");
5
+ const providers_1 = require("./providers");
6
+ class NestjsQueryTypeOrmModule {
7
+ static forFeature(entities, connection) {
8
+ const queryServiceProviders = (0, providers_1.createTypeOrmQueryServiceProviders)(entities, connection);
9
+ const typeOrmModule = typeorm_1.TypeOrmModule.forFeature(entities, connection);
10
+ return {
11
+ imports: [typeOrmModule],
12
+ module: NestjsQueryTypeOrmModule,
13
+ providers: [...queryServiceProviders],
14
+ exports: [...queryServiceProviders, typeOrmModule],
15
+ };
16
+ }
17
+ }
18
+ exports.NestjsQueryTypeOrmModule = NestjsQueryTypeOrmModule;
19
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../packages/query-typeorm/src/module.ts"],"names":[],"mappings":";;;AACA,6CAAgD;AAGhD,2CAAiE;AAEjE,MAAa,wBAAwB;IACnC,MAAM,CAAC,UAAU,CAAC,QAA0B,EAAE,UAAoD;QAChG,MAAM,qBAAqB,GAAG,IAAA,8CAAkC,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACvF,MAAM,aAAa,GAAG,uBAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACrE,OAAO;YACL,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,MAAM,EAAE,wBAAwB;YAChC,SAAS,EAAE,CAAC,GAAG,qBAAqB,CAAC;YACrC,OAAO,EAAE,CAAC,GAAG,qBAAqB,EAAE,aAAa,CAAC;SACnD,CAAC;IACJ,CAAC;CACF;AAXD,4DAWC"}
@@ -0,0 +1,4 @@
1
+ import { Class } from '@ptc-org/nestjs-query-core';
2
+ import { FactoryProvider } from '@nestjs/common';
3
+ import { Connection, ConnectionOptions } from 'typeorm';
4
+ export declare const createTypeOrmQueryServiceProviders: (entities: Class<unknown>[], connection?: Connection | ConnectionOptions | string) => FactoryProvider[];
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTypeOrmQueryServiceProviders = void 0;
4
+ const nestjs_query_core_1 = require("@ptc-org/nestjs-query-core");
5
+ const typeorm_1 = require("@nestjs/typeorm");
6
+ const services_1 = require("./services");
7
+ function createTypeOrmQueryServiceProvider(EntityClass, connection) {
8
+ return {
9
+ provide: (0, nestjs_query_core_1.getQueryServiceToken)(EntityClass),
10
+ useFactory(repo) {
11
+ return new services_1.TypeOrmQueryService(repo);
12
+ },
13
+ inject: [(0, typeorm_1.getRepositoryToken)(EntityClass, connection)],
14
+ };
15
+ }
16
+ const createTypeOrmQueryServiceProviders = (entities, connection) => entities.map((entity) => createTypeOrmQueryServiceProvider(entity, connection));
17
+ exports.createTypeOrmQueryServiceProviders = createTypeOrmQueryServiceProviders;
18
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../../packages/query-typeorm/src/providers.ts"],"names":[],"mappings":";;;AAAA,kEAAyE;AAEzE,6CAAqD;AAErD,yCAAiD;AAEjD,SAAS,iCAAiC,CACxC,WAA0B,EAC1B,UAAoD;IAEpD,OAAO;QACL,OAAO,EAAE,IAAA,wCAAoB,EAAC,WAAW,CAAC;QAC1C,UAAU,CAAC,IAAwB;YACjC,OAAO,IAAI,8BAAmB,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,EAAE,CAAC,IAAA,4BAAkB,EAAC,WAAW,EAAE,UAAU,CAAC,CAAC;KACtD,CAAC;AACJ,CAAC;AAEM,MAAM,kCAAkC,GAAG,CAChD,QAA0B,EAC1B,UAAoD,EACjC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,iCAAiC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAH3F,QAAA,kCAAkC,sCAGyD"}
@@ -0,0 +1,32 @@
1
+ import { SelectQueryBuilder } from 'typeorm';
2
+ import { AggregateQuery, AggregateResponse } from '@ptc-org/nestjs-query-core';
3
+ declare enum AggregateFuncs {
4
+ AVG = "AVG",
5
+ SUM = "SUM",
6
+ COUNT = "COUNT",
7
+ MAX = "MAX",
8
+ MIN = "MIN"
9
+ }
10
+ /**
11
+ * @internal
12
+ * Builds a WHERE clause from a Filter.
13
+ */
14
+ export declare class AggregateBuilder<Entity> {
15
+ static asyncConvertToAggregateResponse<Entity>(responsePromise: Promise<Record<string, unknown>[]>): Promise<AggregateResponse<Entity>[]>;
16
+ static getAggregateSelects<Entity>(query: AggregateQuery<Entity>): string[];
17
+ private static getAggregateGroupBySelects;
18
+ private static getAggregateFuncSelects;
19
+ static getAggregateAlias<Entity>(func: AggregateFuncs, field: keyof Entity): string;
20
+ static getGroupByAlias<Entity>(field: keyof Entity): string;
21
+ static convertToAggregateResponse<Entity>(rawAggregates: Record<string, unknown>[]): AggregateResponse<Entity>[];
22
+ /**
23
+ * Builds a aggregate SELECT clause from a aggregate.
24
+ * @param qb - the `typeorm` SelectQueryBuilder
25
+ * @param aggregate - the aggregates to select.
26
+ * @param alias - optional alias to use to qualify an identifier
27
+ */
28
+ build<Qb extends SelectQueryBuilder<Entity>>(qb: Qb, aggregate: AggregateQuery<Entity>, alias?: string): Qb;
29
+ private createAggSelect;
30
+ private createGroupBySelect;
31
+ }
32
+ export {};
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AggregateBuilder = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const camel_case_1 = require("camel-case");
6
+ var AggregateFuncs;
7
+ (function (AggregateFuncs) {
8
+ AggregateFuncs["AVG"] = "AVG";
9
+ AggregateFuncs["SUM"] = "SUM";
10
+ AggregateFuncs["COUNT"] = "COUNT";
11
+ AggregateFuncs["MAX"] = "MAX";
12
+ AggregateFuncs["MIN"] = "MIN";
13
+ })(AggregateFuncs || (AggregateFuncs = {}));
14
+ const AGG_REGEXP = /(AVG|SUM|COUNT|MAX|MIN|GROUP_BY)_(.*)/;
15
+ /**
16
+ * @internal
17
+ * Builds a WHERE clause from a Filter.
18
+ */
19
+ class AggregateBuilder {
20
+ // eslint-disable-next-line @typescript-eslint/no-shadow
21
+ static async asyncConvertToAggregateResponse(responsePromise) {
22
+ const aggResponse = await responsePromise;
23
+ return this.convertToAggregateResponse(aggResponse);
24
+ }
25
+ // eslint-disable-next-line @typescript-eslint/no-shadow
26
+ static getAggregateSelects(query) {
27
+ return [...this.getAggregateGroupBySelects(query), ...this.getAggregateFuncSelects(query)];
28
+ }
29
+ // eslint-disable-next-line @typescript-eslint/no-shadow
30
+ static getAggregateGroupBySelects(query) {
31
+ return (query.groupBy ?? []).map((f) => this.getGroupByAlias(f));
32
+ }
33
+ // eslint-disable-next-line @typescript-eslint/no-shadow
34
+ static getAggregateFuncSelects(query) {
35
+ const aggs = [
36
+ [AggregateFuncs.COUNT, query.count],
37
+ [AggregateFuncs.SUM, query.sum],
38
+ [AggregateFuncs.AVG, query.avg],
39
+ [AggregateFuncs.MAX, query.max],
40
+ [AggregateFuncs.MIN, query.min],
41
+ ];
42
+ return aggs.reduce((cols, [func, fields]) => {
43
+ const aliases = (fields ?? []).map((f) => this.getAggregateAlias(func, f));
44
+ return [...cols, ...aliases];
45
+ }, []);
46
+ }
47
+ // eslint-disable-next-line @typescript-eslint/no-shadow
48
+ static getAggregateAlias(func, field) {
49
+ return `${func}_${field}`;
50
+ }
51
+ // eslint-disable-next-line @typescript-eslint/no-shadow
52
+ static getGroupByAlias(field) {
53
+ return `GROUP_BY_${field}`;
54
+ }
55
+ // eslint-disable-next-line @typescript-eslint/no-shadow
56
+ static convertToAggregateResponse(rawAggregates) {
57
+ return rawAggregates.map((response) => {
58
+ return Object.keys(response).reduce((agg, resultField) => {
59
+ const matchResult = AGG_REGEXP.exec(resultField);
60
+ if (!matchResult) {
61
+ throw new Error('Unknown aggregate column encountered.');
62
+ }
63
+ const [matchedFunc, matchedFieldName] = matchResult.slice(1);
64
+ const aggFunc = (0, camel_case_1.camelCase)(matchedFunc.toLowerCase());
65
+ const fieldName = matchedFieldName;
66
+ const aggResult = agg[aggFunc] || {};
67
+ return {
68
+ ...agg,
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
70
+ [aggFunc]: { ...aggResult, [fieldName]: response[resultField] },
71
+ };
72
+ }, {});
73
+ });
74
+ }
75
+ /**
76
+ * Builds a aggregate SELECT clause from a aggregate.
77
+ * @param qb - the `typeorm` SelectQueryBuilder
78
+ * @param aggregate - the aggregates to select.
79
+ * @param alias - optional alias to use to qualify an identifier
80
+ */
81
+ build(qb, aggregate, alias) {
82
+ const selects = [
83
+ ...this.createGroupBySelect(aggregate.groupBy, alias),
84
+ ...this.createAggSelect(AggregateFuncs.COUNT, aggregate.count, alias),
85
+ ...this.createAggSelect(AggregateFuncs.SUM, aggregate.sum, alias),
86
+ ...this.createAggSelect(AggregateFuncs.AVG, aggregate.avg, alias),
87
+ ...this.createAggSelect(AggregateFuncs.MAX, aggregate.max, alias),
88
+ ...this.createAggSelect(AggregateFuncs.MIN, aggregate.min, alias),
89
+ ];
90
+ if (!selects.length) {
91
+ throw new common_1.BadRequestException('No aggregate fields found.');
92
+ }
93
+ const [head, ...tail] = selects;
94
+ return tail.reduce((acc, [select, selectAlias]) => acc.addSelect(select, selectAlias), qb.select(head[0], head[1]));
95
+ }
96
+ createAggSelect(func, fields, alias) {
97
+ if (!fields) {
98
+ return [];
99
+ }
100
+ return fields.map((field) => {
101
+ const col = alias ? `${alias}.${field}` : field;
102
+ return [`${func}(${col})`, AggregateBuilder.getAggregateAlias(func, field)];
103
+ });
104
+ }
105
+ createGroupBySelect(fields, alias) {
106
+ if (!fields) {
107
+ return [];
108
+ }
109
+ return fields.map((field) => {
110
+ const col = alias ? `${alias}.${field}` : field;
111
+ return [`${col}`, AggregateBuilder.getGroupByAlias(field)];
112
+ });
113
+ }
114
+ }
115
+ exports.AggregateBuilder = AggregateBuilder;
116
+ //# sourceMappingURL=aggregate.builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.builder.js","sourceRoot":"","sources":["../../../../../packages/query-typeorm/src/query/aggregate.builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import { Filter, Paging, Query, SortField, AggregateQuery } from '@ptc-org/nestjs-query-core';
2
+ import { DeleteQueryBuilder, QueryBuilder, Repository, SelectQueryBuilder, UpdateQueryBuilder, WhereExpression, EntityMetadata } from 'typeorm';
3
+ import { SoftDeleteQueryBuilder } from 'typeorm/query-builder/SoftDeleteQueryBuilder';
4
+ import { AggregateBuilder } from './aggregate.builder';
5
+ import { WhereBuilder } from './where.builder';
6
+ /**
7
+ * @internal
8
+ *
9
+ * Interface that for Typeorm query builders that are sortable.
10
+ */
11
+ interface Sortable<Entity> extends QueryBuilder<Entity> {
12
+ addOrderBy(sort: string, order?: 'ASC' | 'DESC', nulls?: 'NULLS FIRST' | 'NULLS LAST'): this;
13
+ }
14
+ interface Groupable<Entity> extends QueryBuilder<Entity> {
15
+ addGroupBy(groupBy: string): this;
16
+ }
17
+ /**
18
+ * @internal
19
+ *
20
+ * Interface for `typeorm` query builders that are pageable.
21
+ */
22
+ interface Pageable<Entity> extends QueryBuilder<Entity> {
23
+ limit(limit?: number): this;
24
+ offset(offset?: number): this;
25
+ skip(skip?: number): this;
26
+ take(take?: number): this;
27
+ }
28
+ /**
29
+ * @internal
30
+ *
31
+ * Nested record type
32
+ */
33
+ export interface NestedRecord<E = unknown> {
34
+ [keys: string]: NestedRecord<E>;
35
+ }
36
+ /**
37
+ * @internal
38
+ *
39
+ * Class that will convert a Query into a `typeorm` Query Builder.
40
+ */
41
+ export declare class FilterQueryBuilder<Entity> {
42
+ readonly repo: Repository<Entity>;
43
+ readonly whereBuilder: WhereBuilder<Entity>;
44
+ readonly aggregateBuilder: AggregateBuilder<Entity>;
45
+ constructor(repo: Repository<Entity>, whereBuilder?: WhereBuilder<Entity>, aggregateBuilder?: AggregateBuilder<Entity>);
46
+ /**
47
+ * Create a `typeorm` SelectQueryBuilder with `WHERE`, `ORDER BY` and `LIMIT/OFFSET` clauses.
48
+ *
49
+ * @param query - the query to apply.
50
+ */
51
+ select(query: Query<Entity>): SelectQueryBuilder<Entity>;
52
+ selectById(id: string | number | (string | number)[], query: Query<Entity>): SelectQueryBuilder<Entity>;
53
+ aggregate(query: Query<Entity>, aggregate: AggregateQuery<Entity>): SelectQueryBuilder<Entity>;
54
+ /**
55
+ * Create a `typeorm` DeleteQueryBuilder with a WHERE clause.
56
+ *
57
+ * @param query - the query to apply.
58
+ */
59
+ delete(query: Query<Entity>): DeleteQueryBuilder<Entity>;
60
+ /**
61
+ * Create a `typeorm` DeleteQueryBuilder with a WHERE clause.
62
+ *
63
+ * @param query - the query to apply.
64
+ */
65
+ softDelete(query: Query<Entity>): SoftDeleteQueryBuilder<Entity>;
66
+ /**
67
+ * Create a `typeorm` UpdateQueryBuilder with `WHERE` and `ORDER BY` clauses
68
+ *
69
+ * @param query - the query to apply.
70
+ */
71
+ update(query: Query<Entity>): UpdateQueryBuilder<Entity>;
72
+ /**
73
+ * Applies paging to a Pageable `typeorm` query builder
74
+ * @param qb - the `typeorm` QueryBuilder
75
+ * @param paging - the Paging options.
76
+ * @param useSkipTake - if skip/take should be used instead of limit/offset.
77
+ */
78
+ applyPaging<P extends Pageable<Entity>>(qb: P, paging?: Paging, useSkipTake?: boolean): P;
79
+ /**
80
+ * Applies the filter from a Query to a `typeorm` QueryBuilder.
81
+ *
82
+ * @param qb - the `typeorm` QueryBuilder.
83
+ * @param aggregate - the aggregates to select.
84
+ * @param alias - optional alias to use to qualify an identifier
85
+ */
86
+ applyAggregate<Qb extends SelectQueryBuilder<Entity>>(qb: Qb, aggregate: AggregateQuery<Entity>, alias?: string): Qb;
87
+ /**
88
+ * Applies the filter from a Query to a `typeorm` QueryBuilder.
89
+ *
90
+ * @param qb - the `typeorm` QueryBuilder.
91
+ * @param filter - the filter.
92
+ * @param alias - optional alias to use to qualify an identifier
93
+ */
94
+ applyFilter<Where extends WhereExpression>(qb: Where, filter?: Filter<Entity>, alias?: string): Where;
95
+ /**
96
+ * Applies the ORDER BY clause to a `typeorm` QueryBuilder.
97
+ * @param qb - the `typeorm` QueryBuilder.
98
+ * @param sorts - an array of SortFields to create the ORDER BY clause.
99
+ * @param alias - optional alias to use to qualify an identifier
100
+ */
101
+ applySorting<T extends Sortable<Entity>>(qb: T, sorts?: SortField<Entity>[], alias?: string): T;
102
+ applyGroupBy<T extends Groupable<Entity>>(qb: T, groupBy?: (keyof Entity)[], alias?: string): T;
103
+ applyAggregateSorting<T extends Sortable<Entity>>(qb: T, groupBy?: (keyof Entity)[], alias?: string): T;
104
+ /**
105
+ * Create a `typeorm` SelectQueryBuilder which can be used as an entry point to create update, delete or insert
106
+ * QueryBuilders.
107
+ */
108
+ private createQueryBuilder;
109
+ /**
110
+ * Gets relations referenced in the filter and adds joins for them to the query builder
111
+ * @param qb - the `typeorm` QueryBuilder.
112
+ * @param relationsMap - the relations map.
113
+ *
114
+ * @returns the query builder for chaining
115
+ */
116
+ applyRelationJoinsRecursive(qb: SelectQueryBuilder<Entity>, relationsMap?: NestedRecord, alias?: string): SelectQueryBuilder<Entity>;
117
+ /**
118
+ * Checks if a filter references any relations.
119
+ * @param filter
120
+ * @private
121
+ *
122
+ * @returns true if there are any referenced relations
123
+ */
124
+ filterHasRelations(filter?: Filter<Entity>): boolean;
125
+ private getReferencedRelations;
126
+ getReferencedRelationsRecursive(metadata: EntityMetadata, filter?: Filter<unknown>): NestedRecord;
127
+ private get relationNames();
128
+ }
129
+ export {};
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilterQueryBuilder = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const nestjs_query_core_1 = require("@ptc-org/nestjs-query-core");
6
+ const aggregate_builder_1 = require("./aggregate.builder");
7
+ const where_builder_1 = require("./where.builder");
8
+ const lodash_merge_1 = (0, tslib_1.__importDefault)(require("lodash.merge"));
9
+ /**
10
+ * @internal
11
+ *
12
+ * Class that will convert a Query into a `typeorm` Query Builder.
13
+ */
14
+ class FilterQueryBuilder {
15
+ constructor(repo, whereBuilder = new where_builder_1.WhereBuilder(), aggregateBuilder = new aggregate_builder_1.AggregateBuilder()) {
16
+ this.repo = repo;
17
+ this.whereBuilder = whereBuilder;
18
+ this.aggregateBuilder = aggregateBuilder;
19
+ }
20
+ /**
21
+ * Create a `typeorm` SelectQueryBuilder with `WHERE`, `ORDER BY` and `LIMIT/OFFSET` clauses.
22
+ *
23
+ * @param query - the query to apply.
24
+ */
25
+ select(query) {
26
+ const hasRelations = this.filterHasRelations(query.filter);
27
+ let qb = this.createQueryBuilder();
28
+ qb = hasRelations
29
+ ? this.applyRelationJoinsRecursive(qb, this.getReferencedRelationsRecursive(this.repo.metadata, query.filter))
30
+ : qb;
31
+ qb = this.applyFilter(qb, query.filter, qb.alias);
32
+ qb = this.applySorting(qb, query.sorting, qb.alias);
33
+ qb = this.applyPaging(qb, query.paging, hasRelations);
34
+ return qb;
35
+ }
36
+ selectById(id, query) {
37
+ const hasRelations = this.filterHasRelations(query.filter);
38
+ let qb = this.createQueryBuilder();
39
+ qb = hasRelations
40
+ ? this.applyRelationJoinsRecursive(qb, this.getReferencedRelationsRecursive(this.repo.metadata, query.filter))
41
+ : qb;
42
+ qb = qb.andWhereInIds(id);
43
+ qb = this.applyFilter(qb, query.filter, qb.alias);
44
+ qb = this.applySorting(qb, query.sorting, qb.alias);
45
+ qb = this.applyPaging(qb, query.paging, hasRelations);
46
+ return qb;
47
+ }
48
+ aggregate(query, aggregate) {
49
+ let qb = this.createQueryBuilder();
50
+ qb = this.applyAggregate(qb, aggregate, qb.alias);
51
+ qb = this.applyFilter(qb, query.filter, qb.alias);
52
+ qb = this.applyAggregateSorting(qb, aggregate.groupBy, qb.alias);
53
+ qb = this.applyGroupBy(qb, aggregate.groupBy, qb.alias);
54
+ return qb;
55
+ }
56
+ /**
57
+ * Create a `typeorm` DeleteQueryBuilder with a WHERE clause.
58
+ *
59
+ * @param query - the query to apply.
60
+ */
61
+ delete(query) {
62
+ return this.applyFilter(this.repo.createQueryBuilder().delete(), query.filter);
63
+ }
64
+ /**
65
+ * Create a `typeorm` DeleteQueryBuilder with a WHERE clause.
66
+ *
67
+ * @param query - the query to apply.
68
+ */
69
+ softDelete(query) {
70
+ return this.applyFilter(this.repo.createQueryBuilder().softDelete(), query.filter);
71
+ }
72
+ /**
73
+ * Create a `typeorm` UpdateQueryBuilder with `WHERE` and `ORDER BY` clauses
74
+ *
75
+ * @param query - the query to apply.
76
+ */
77
+ update(query) {
78
+ const qb = this.applyFilter(this.repo.createQueryBuilder().update(), query.filter);
79
+ return this.applySorting(qb, query.sorting);
80
+ }
81
+ /**
82
+ * Applies paging to a Pageable `typeorm` query builder
83
+ * @param qb - the `typeorm` QueryBuilder
84
+ * @param paging - the Paging options.
85
+ * @param useSkipTake - if skip/take should be used instead of limit/offset.
86
+ */
87
+ applyPaging(qb, paging, useSkipTake) {
88
+ if (!paging) {
89
+ return qb;
90
+ }
91
+ if (useSkipTake) {
92
+ return qb.take(paging.limit).skip(paging.offset);
93
+ }
94
+ return qb.limit(paging.limit).offset(paging.offset);
95
+ }
96
+ /**
97
+ * Applies the filter from a Query to a `typeorm` QueryBuilder.
98
+ *
99
+ * @param qb - the `typeorm` QueryBuilder.
100
+ * @param aggregate - the aggregates to select.
101
+ * @param alias - optional alias to use to qualify an identifier
102
+ */
103
+ applyAggregate(qb, aggregate, alias) {
104
+ return this.aggregateBuilder.build(qb, aggregate, alias);
105
+ }
106
+ /**
107
+ * Applies the filter from a Query to a `typeorm` QueryBuilder.
108
+ *
109
+ * @param qb - the `typeorm` QueryBuilder.
110
+ * @param filter - the filter.
111
+ * @param alias - optional alias to use to qualify an identifier
112
+ */
113
+ applyFilter(qb, filter, alias) {
114
+ if (!filter) {
115
+ return qb;
116
+ }
117
+ return this.whereBuilder.build(qb, filter, this.getReferencedRelationsRecursive(this.repo.metadata, filter), alias);
118
+ }
119
+ /**
120
+ * Applies the ORDER BY clause to a `typeorm` QueryBuilder.
121
+ * @param qb - the `typeorm` QueryBuilder.
122
+ * @param sorts - an array of SortFields to create the ORDER BY clause.
123
+ * @param alias - optional alias to use to qualify an identifier
124
+ */
125
+ applySorting(qb, sorts, alias) {
126
+ if (!sorts) {
127
+ return qb;
128
+ }
129
+ return sorts.reduce((prevQb, { field, direction, nulls }) => {
130
+ const col = alias ? `${alias}.${field}` : `${field}`;
131
+ return prevQb.addOrderBy(col, direction, nulls);
132
+ }, qb);
133
+ }
134
+ applyGroupBy(qb, groupBy, alias) {
135
+ if (!groupBy) {
136
+ return qb;
137
+ }
138
+ return groupBy.reduce((prevQb, group) => {
139
+ const col = alias ? `${alias}.${group}` : `${group}`;
140
+ return prevQb.addGroupBy(col);
141
+ }, qb);
142
+ }
143
+ applyAggregateSorting(qb, groupBy, alias) {
144
+ if (!groupBy) {
145
+ return qb;
146
+ }
147
+ return groupBy.reduce((prevQb, field) => {
148
+ const col = alias ? `${alias}.${field}` : `${field}`;
149
+ return prevQb.addOrderBy(col, 'ASC');
150
+ }, qb);
151
+ }
152
+ /**
153
+ * Create a `typeorm` SelectQueryBuilder which can be used as an entry point to create update, delete or insert
154
+ * QueryBuilders.
155
+ */
156
+ createQueryBuilder() {
157
+ return this.repo.createQueryBuilder();
158
+ }
159
+ /**
160
+ * Gets relations referenced in the filter and adds joins for them to the query builder
161
+ * @param qb - the `typeorm` QueryBuilder.
162
+ * @param relationsMap - the relations map.
163
+ *
164
+ * @returns the query builder for chaining
165
+ */
166
+ applyRelationJoinsRecursive(qb, relationsMap, alias) {
167
+ if (!relationsMap) {
168
+ return qb;
169
+ }
170
+ const referencedRelations = Object.keys(relationsMap);
171
+ return referencedRelations.reduce((rqb, relation) => {
172
+ return this.applyRelationJoinsRecursive(rqb.leftJoin(`${alias ?? rqb.alias}.${relation}`, relation), relationsMap[relation], relation);
173
+ }, qb);
174
+ }
175
+ /**
176
+ * Checks if a filter references any relations.
177
+ * @param filter
178
+ * @private
179
+ *
180
+ * @returns true if there are any referenced relations
181
+ */
182
+ filterHasRelations(filter) {
183
+ if (!filter) {
184
+ return false;
185
+ }
186
+ return this.getReferencedRelations(filter).length > 0;
187
+ }
188
+ getReferencedRelations(filter) {
189
+ const { relationNames } = this;
190
+ const referencedFields = (0, nestjs_query_core_1.getFilterFields)(filter);
191
+ return referencedFields.filter((f) => relationNames.includes(f));
192
+ }
193
+ getReferencedRelationsRecursive(metadata, filter = {}) {
194
+ const referencedFields = Array.from(new Set(Object.keys(filter)));
195
+ return referencedFields.reduce((prev, curr) => {
196
+ const currFilterValue = filter[curr];
197
+ if ((curr === 'and' || curr === 'or') && currFilterValue) {
198
+ for (const subFilter of currFilterValue) {
199
+ prev = (0, lodash_merge_1.default)(prev, this.getReferencedRelationsRecursive(metadata, subFilter));
200
+ }
201
+ }
202
+ const referencedRelation = metadata.relations.find((r) => r.propertyName === curr);
203
+ if (!referencedRelation)
204
+ return prev;
205
+ return {
206
+ ...prev,
207
+ [curr]: (0, lodash_merge_1.default)(prev[curr], this.getReferencedRelationsRecursive(referencedRelation.inverseEntityMetadata, currFilterValue)),
208
+ };
209
+ }, {});
210
+ }
211
+ get relationNames() {
212
+ return this.repo.metadata.relations.map((r) => r.propertyName);
213
+ }
214
+ }
215
+ exports.FilterQueryBuilder = FilterQueryBuilder;
216
+ //# sourceMappingURL=filter-query.builder.js.map