@nest-util/nest-crud 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,61 @@ pnpm add @nest-util/nest-crud@^1.0.7 @nest-util/nest-auth@^1.1.0 typeorm@^1.1.0
21
21
  - Automatic Swagger documentation
22
22
  - TypeORM exception filter for duplicate key errors
23
23
 
24
+ ## Filtering and Sorting
25
+
26
+ ### Filtering
27
+
28
+ Query format: `?filter[field_operator]=value` (requires Express `query parser` set to `extended`).
29
+
30
+ ```typescript
31
+ app.getHttpAdapter().getInstance().set('query parser', 'extended');
32
+ ```
33
+
34
+ Supported operators: `eq`, `ne`, `cont`, `notcont`, `starts`, `ends`, `gte`, `lte`, `gt`, `lt`, `in`, `nin`, `isnull`. Groups via `filter[and][0][field_eq]=...` and `filter[or][0][field_eq]=...`.
35
+
36
+ Filterable fields must be whitelisted with `allowedFilters` in the service options.
37
+
38
+ ### Filtering by nested (related) fields
39
+
40
+ Nested relation fields use dot notation. The relation must be listed in `include` (so the join exists) and the full path must be whitelisted in `allowedFilters`:
41
+
42
+ ```typescript
43
+ super({
44
+ repository,
45
+ include: ['author', 'author.profile'],
46
+ allowedFilters: ['title', 'author.name', 'author.profile.bio'],
47
+ });
48
+ ```
49
+
50
+ ```http
51
+ GET /post?filter[author.name_cont]=John
52
+ GET /post?filter[author.profile.bio_starts]=Software
53
+ ```
54
+
55
+ Nested filter keys with dots resolve against the joined alias (`author.name` → `author.name`, `author.profile.bio` → `author_profile.bio`). A nested filter whose join prefix is missing from `include` is silently skipped.
56
+
57
+ ### Sorting
58
+
59
+ ```http
60
+ GET /post?orderBy=title&orderDirection=ASC
61
+ ```
62
+
63
+ Sort fields are whitelisted with `allowedSortFields`. Nested sorting works the same way:
64
+
65
+ ```typescript
66
+ super({
67
+ repository,
68
+ include: ['author'],
69
+ allowedSortFields: ['id', 'title', 'author.name'],
70
+ });
71
+ ```
72
+
73
+ ```http
74
+ GET /post?orderBy=author.name&orderDirection=DESC
75
+ ```
76
+
77
+ Nested sort paths also require their join prefix to be in `include`. Cursor pagination keeps its fixed `id` ordering.
78
+
24
79
  ## Building
25
80
 
26
81
  Run `nx build nest-crud` to build the library.
@@ -1,3 +1,14 @@
1
1
  import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
2
- export declare function applyFilters<Entity extends ObjectLiteral>(qb: SelectQueryBuilder<Entity>, filters: Record<string, unknown> | undefined, allowedFilters: readonly (keyof Entity)[]): void;
2
+ /**
3
+ * Resolves a filter/sort field to a query-builder target.
4
+ *
5
+ * - Plain fields resolve against the root alias: `name` -> `e.name`.
6
+ * - Nested fields (dot notation) resolve against a joined alias whose path
7
+ * prefix must be present in `include`: `author.name` -> `author.name`,
8
+ * `userRoles.role.name` -> `userRoles_role.name`.
9
+ * - Returns `null` when the field is unsafe or the join prefix is not
10
+ * configured, so callers can skip the condition entirely.
11
+ */
12
+ export declare function resolveQueryTarget(field: string, include?: readonly string[], rootAlias?: string): string | null;
13
+ export declare function applyFilters<Entity extends ObjectLiteral>(qb: SelectQueryBuilder<Entity>, filters: Record<string, unknown> | undefined, allowedFilters: readonly (keyof Entity)[], include?: readonly string[]): void;
3
14
  //# sourceMappingURL=filter.helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/filter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAsL5D,wBAAgB,YAAY,CAAC,MAAM,SAAS,aAAa,EACvD,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,cAAc,EAAE,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,GACxC,IAAI,CAoBN"}
1
+ {"version":3,"file":"filter.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/filter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AA+C5D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,SAAS,MAAM,EAAO,EAC/B,SAAS,SAAM,GACd,MAAM,GAAG,IAAI,CAWf;AA6ID,wBAAgB,YAAY,CAAC,MAAM,SAAS,aAAa,EACvD,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,cAAc,EAAE,SAAS,CAAC,MAAM,MAAM,CAAC,EAAE,EACzC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAqBN"}
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveQueryTarget = resolveQueryTarget;
3
4
  exports.applyFilters = applyFilters;
4
- const SAFE_FIELD_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
5
+ const SAFE_FIELD_PATTERN = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)*$/;
5
6
  const toArrayValue = (value) => {
6
7
  if (Array.isArray(value)) {
7
8
  return value;
@@ -36,41 +37,63 @@ const parseFilterKey = (rawKey) => {
36
37
  const operator = rawKey.slice(separatorIndex + 1).toLowerCase();
37
38
  return { field, operator };
38
39
  };
39
- const buildCondition = (field, operator, value, paramIndex) => {
40
+ /**
41
+ * Resolves a filter/sort field to a query-builder target.
42
+ *
43
+ * - Plain fields resolve against the root alias: `name` -> `e.name`.
44
+ * - Nested fields (dot notation) resolve against a joined alias whose path
45
+ * prefix must be present in `include`: `author.name` -> `author.name`,
46
+ * `userRoles.role.name` -> `userRoles_role.name`.
47
+ * - Returns `null` when the field is unsafe or the join prefix is not
48
+ * configured, so callers can skip the condition entirely.
49
+ */
50
+ function resolveQueryTarget(field, include = [], rootAlias = 'e') {
51
+ if (!SAFE_FIELD_PATTERN.test(field))
52
+ return null;
53
+ const parts = field.split('.');
54
+ if (parts.length === 1)
55
+ return `${rootAlias}.${field}`;
56
+ const joinPath = parts.slice(0, -1).join('.');
57
+ if (!include.includes(joinPath))
58
+ return null;
59
+ const alias = joinPath.replace(/\./g, '_');
60
+ return `${alias}.${parts[parts.length - 1]}`;
61
+ }
62
+ const buildCondition = (target, operator, value, paramIndex) => {
40
63
  const paramKey = `filter_${paramIndex.current++}`;
41
64
  switch (operator) {
42
65
  case 'eq':
43
- return { sql: `e.${field} = :${paramKey}`, params: { [paramKey]: value } };
66
+ return { sql: `${target} = :${paramKey}`, params: { [paramKey]: value } };
44
67
  case 'ne':
45
- return { sql: `e.${field} != :${paramKey}`, params: { [paramKey]: value } };
68
+ return { sql: `${target} != :${paramKey}`, params: { [paramKey]: value } };
46
69
  case 'cont':
47
70
  return {
48
- sql: `e.${field} ILIKE :${paramKey}`,
71
+ sql: `${target} ILIKE :${paramKey}`,
49
72
  params: { [paramKey]: `%${value}%` },
50
73
  };
51
74
  case 'notcont':
52
75
  return {
53
- sql: `e.${field} NOT ILIKE :${paramKey}`,
76
+ sql: `${target} NOT ILIKE :${paramKey}`,
54
77
  params: { [paramKey]: `%${value}%` },
55
78
  };
56
79
  case 'starts':
57
80
  return {
58
- sql: `e.${field} ILIKE :${paramKey}`,
81
+ sql: `${target} ILIKE :${paramKey}`,
59
82
  params: { [paramKey]: `${value}%` },
60
83
  };
61
84
  case 'ends':
62
85
  return {
63
- sql: `e.${field} ILIKE :${paramKey}`,
86
+ sql: `${target} ILIKE :${paramKey}`,
64
87
  params: { [paramKey]: `%${value}` },
65
88
  };
66
89
  case 'gte':
67
- return { sql: `e.${field} >= :${paramKey}`, params: { [paramKey]: value } };
90
+ return { sql: `${target} >= :${paramKey}`, params: { [paramKey]: value } };
68
91
  case 'lte':
69
- return { sql: `e.${field} <= :${paramKey}`, params: { [paramKey]: value } };
92
+ return { sql: `${target} <= :${paramKey}`, params: { [paramKey]: value } };
70
93
  case 'gt':
71
- return { sql: `e.${field} > :${paramKey}`, params: { [paramKey]: value } };
94
+ return { sql: `${target} > :${paramKey}`, params: { [paramKey]: value } };
72
95
  case 'lt':
73
- return { sql: `e.${field} < :${paramKey}`, params: { [paramKey]: value } };
96
+ return { sql: `${target} < :${paramKey}`, params: { [paramKey]: value } };
74
97
  case 'in':
75
98
  case 'nin': {
76
99
  const values = toArrayValue(value);
@@ -78,8 +101,8 @@ const buildCondition = (field, operator, value, paramIndex) => {
78
101
  return null;
79
102
  return {
80
103
  sql: operator === 'in'
81
- ? `e.${field} IN (:...${paramKey})`
82
- : `e.${field} NOT IN (:...${paramKey})`,
104
+ ? `${target} IN (:...${paramKey})`
105
+ : `${target} NOT IN (:...${paramKey})`,
83
106
  params: { [paramKey]: values },
84
107
  };
85
108
  }
@@ -87,13 +110,13 @@ const buildCondition = (field, operator, value, paramIndex) => {
87
110
  const isNull = toBooleanValue(value);
88
111
  if (isNull === null)
89
112
  return null;
90
- return { sql: isNull ? `e.${field} IS NULL` : `e.${field} IS NOT NULL` };
113
+ return { sql: isNull ? `${target} IS NULL` : `${target} IS NOT NULL` };
91
114
  }
92
115
  default:
93
116
  return null;
94
117
  }
95
118
  };
96
- const buildExpression = (node, combinator, allowedFilters, paramIndex, params) => {
119
+ const buildExpression = (node, combinator, allowedFilters, include, paramIndex, params) => {
97
120
  if (!node || typeof node !== 'object')
98
121
  return null;
99
122
  const conditions = [];
@@ -105,7 +128,7 @@ const buildExpression = (node, combinator, allowedFilters, paramIndex, params) =
105
128
  const nestedCombinator = rawKey;
106
129
  const nestedNodes = Array.isArray(value) ? value : [value];
107
130
  const nestedExpressions = nestedNodes
108
- .map((nestedNode) => buildExpression(nestedNode, 'and', allowedFilters, paramIndex, params))
131
+ .map((nestedNode) => buildExpression(nestedNode, 'and', allowedFilters, include, paramIndex, params))
109
132
  .filter((sql) => Boolean(sql));
110
133
  if (nestedExpressions.length > 0) {
111
134
  conditions.push(`(${nestedExpressions.join(` ${nestedCombinator.toUpperCase()} `)})`);
@@ -116,11 +139,12 @@ const buildExpression = (node, combinator, allowedFilters, paramIndex, params) =
116
139
  if (!parsed)
117
140
  continue;
118
141
  const { field, operator } = parsed;
119
- if (!SAFE_FIELD_PATTERN.test(field))
120
- continue;
121
142
  if (!allowedFilters.includes(field))
122
143
  continue;
123
- const condition = buildCondition(field, operator, value, paramIndex);
144
+ const target = resolveQueryTarget(field, include);
145
+ if (!target)
146
+ continue;
147
+ const condition = buildCondition(target, operator, value, paramIndex);
124
148
  if (!condition)
125
149
  continue;
126
150
  if (condition.params)
@@ -133,11 +157,11 @@ const buildExpression = (node, combinator, allowedFilters, paramIndex, params) =
133
157
  return conditions[0];
134
158
  return `(${conditions.join(` ${combinator.toUpperCase()} `)})`;
135
159
  };
136
- function applyFilters(qb, filters, allowedFilters) {
160
+ function applyFilters(qb, filters, allowedFilters, include) {
137
161
  if (!filters)
138
162
  return;
139
163
  const params = {};
140
- const expression = buildExpression(filters, 'and', allowedFilters.map(String), { current: 0 }, params);
164
+ const expression = buildExpression(filters, 'and', allowedFilters.map(String), include ?? [], { current: 0 }, params);
141
165
  if (!expression)
142
166
  return;
143
167
  if (Object.keys(params).length > 0) {
@@ -10,8 +10,8 @@ import { CrudHooks, TransactionConfig } from '../interfaces/hooks.interface';
10
10
  import { FindMineConfig, OwnershipUser } from '../interfaces/find-mine.interface';
11
11
  export interface CrudServiceOptions<Entity extends ObjectLiteral, ResponseDto> extends FindMineConfig<Entity> {
12
12
  repository: Repository<Entity>;
13
- allowedFilters?: readonly (keyof Entity)[];
14
- allowedSortFields?: readonly (keyof Entity)[];
13
+ allowedFilters?: readonly (keyof Entity | (string & {}))[];
14
+ allowedSortFields?: readonly (keyof Entity | (string & {}))[];
15
15
  include?: readonly string[];
16
16
  relations?: {
17
17
  property: keyof Entity;
@@ -28,8 +28,8 @@ export interface CrudServiceOptions<Entity extends ObjectLiteral, ResponseDto> e
28
28
  }
29
29
  export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = Partial<Entity>, UpdateDto = Partial<Entity>, ResponseDto = Entity> implements CrudInterface<CreateDto, UpdateDto, ResponseDto> {
30
30
  protected readonly repo: Repository<Entity>;
31
- protected readonly allowedFilters: readonly (keyof Entity)[];
32
- protected readonly allowedSortFields: readonly (keyof Entity)[];
31
+ protected readonly allowedFilters: readonly (keyof Entity | (string & {}))[];
32
+ protected readonly allowedSortFields: readonly (keyof Entity | (string & {}))[];
33
33
  protected readonly include: readonly string[];
34
34
  protected readonly relations: {
35
35
  property: keyof Entity;
@@ -54,6 +54,7 @@ export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = P
54
54
  private executeHook;
55
55
  private buildRelationsObject;
56
56
  private applyIncludeJoins;
57
+ private applyOrderBy;
57
58
  private isOwnershipConfigured;
58
59
  private canBypassOwnership;
59
60
  private enforceOwnershipFor;
@@ -1 +1 @@
1
- {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"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"}
@@ -95,22 +95,36 @@ let NestCrudService = class NestCrudService {
95
95
  }
96
96
  return result;
97
97
  }
98
- applyIncludeJoins(qb) {
98
+ applyIncludeJoins(qb, withSelect = true) {
99
99
  if (this.include.length === 0)
100
100
  return;
101
+ const join = withSelect
102
+ ? (path, alias) => qb.leftJoinAndSelect(path, alias)
103
+ : (path, alias) => qb.leftJoin(path, alias);
101
104
  this.include.forEach((relation) => {
102
105
  const parts = relation.split('.');
103
106
  if (parts.length === 1) {
104
- qb.leftJoinAndSelect(`e.${parts[0]}`, parts[0]);
107
+ join(`e.${parts[0]}`, parts[0]);
105
108
  }
106
109
  else {
107
110
  const parentAlias = parts.slice(0, -1).join('_');
108
111
  const field = parts[parts.length - 1];
109
112
  const alias = parts.join('_');
110
- qb.leftJoinAndSelect(`${parentAlias}.${field}`, alias);
113
+ join(`${parentAlias}.${field}`, alias);
111
114
  }
112
115
  });
113
116
  }
117
+ applyOrderBy(qb, orderBy, orderDirection) {
118
+ if (!orderBy)
119
+ return;
120
+ const target = (0, filter_helper_1.resolveQueryTarget)(orderBy, this.include.map(String), 'e');
121
+ if (!target)
122
+ return;
123
+ if (this.allowedSortFields.length === 0 ||
124
+ this.allowedSortFields.includes(orderBy)) {
125
+ qb.orderBy(target, orderDirection);
126
+ }
127
+ }
114
128
  isOwnershipConfigured() {
115
129
  return Boolean(this.userOwnershipField || this.findMineQuery);
116
130
  }
@@ -156,15 +170,9 @@ let NestCrudService = class NestCrudService {
156
170
  async findAll(query) {
157
171
  const qb = this.repo.createQueryBuilder('e');
158
172
  this.applyIncludeJoins(qb);
159
- (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters);
173
+ (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters, this.include);
160
174
  const paginationMeta = (0, pagination_helper_1.applyPagination)(qb, query);
161
- if (query.orderBy) {
162
- const orderDirection = query.orderDirection === 'ASC' ? 'ASC' : 'DESC';
163
- if (this.allowedSortFields.length === 0 ||
164
- this.allowedSortFields.includes(query.orderBy)) {
165
- qb.orderBy(`e.${query.orderBy}`, orderDirection);
166
- }
167
- }
175
+ this.applyOrderBy(qb, query.orderBy, query.orderDirection === 'ASC' ? 'ASC' : 'DESC');
168
176
  const [entities, total] = await qb.getManyAndCount();
169
177
  const data = this.toResponseDto
170
178
  ? this.toResponseDto(entities)
@@ -180,15 +188,9 @@ let NestCrudService = class NestCrudService {
180
188
  const qb = this.repo.createQueryBuilder('e');
181
189
  this.applyOwnershipCondition(qb, userId);
182
190
  this.applyIncludeJoins(qb);
183
- (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters);
191
+ (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters, this.include);
184
192
  const paginationMeta = (0, pagination_helper_1.applyPagination)(qb, query);
185
- if (query.orderBy) {
186
- const orderDirection = query.orderDirection === 'ASC' ? 'ASC' : 'DESC';
187
- if (this.allowedSortFields.length === 0 ||
188
- this.allowedSortFields.includes(query.orderBy)) {
189
- qb.orderBy(`e.${query.orderBy}`, orderDirection);
190
- }
191
- }
193
+ this.applyOrderBy(qb, query.orderBy, query.orderDirection === 'ASC' ? 'ASC' : 'DESC');
192
194
  const [entities, total] = await qb.getManyAndCount();
193
195
  const data = this.toResponseDto
194
196
  ? this.toResponseDto(entities)
@@ -205,7 +207,7 @@ let NestCrudService = class NestCrudService {
205
207
  // Join relations
206
208
  this.applyIncludeJoins(qb);
207
209
  // Apply filters
208
- (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters);
210
+ (0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters, this.include);
209
211
  // Apply cursor filter
210
212
  if (query.cursor) {
211
213
  const decoded = (0, cursor_pagination_helper_1.decodeCursor)(query.cursor, strategy);
@@ -225,15 +227,8 @@ let NestCrudService = class NestCrudService {
225
227
  if (query.includeTotal) {
226
228
  // Build a clean count query (reuse same filters but no cursor/order/take)
227
229
  const countQb = this.repo.createQueryBuilder('e');
228
- if (this.include.length > 0) {
229
- this.include.forEach((relation) => {
230
- const parts = relation.split('.');
231
- if (parts.length === 1) {
232
- countQb.leftJoin(`e.${parts[0]}`, parts[0]);
233
- }
234
- });
235
- }
236
- (0, filter_helper_1.applyFilters)(countQb, query.filter, this.allowedFilters);
230
+ this.applyIncludeJoins(countQb, false);
231
+ (0, filter_helper_1.applyFilters)(countQb, query.filter, this.allowedFilters, this.include);
237
232
  total = await countQb.getCount();
238
233
  }
239
234
  const response = this.toResponseDto
@@ -1 +1 @@
1
- {"version":3,"file":"crud-service.test-suites.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/crud-service.test-suites.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtE,wBAAgB,gBAAgB,CAC9B,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EAAE,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,eAAe,CA6VxF"}
1
+ {"version":3,"file":"crud-service.test-suites.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/crud-service.test-suites.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtE,wBAAgB,gBAAgB,CAC9B,OAAO,SAAS,aAAa,EAC7B,UAAU,EACV,UAAU,EACV,YAAY,EACZ,MAAM,EAAE,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,eAAe,CA6axF"}
@@ -59,6 +59,44 @@ function crudServiceTests(config) {
59
59
  });
60
60
  expect(lastQb.andWhere).toHaveBeenCalled();
61
61
  });
62
+ it('should apply nested filters via joined aliases', async () => {
63
+ const nestedFilters = (config.allowedFilters ?? []).filter((field) => String(field).includes('.'));
64
+ if (nestedFilters.length === 0)
65
+ return;
66
+ lastQb = (0, mock_repository_1.createMockQb)();
67
+ lastQb.getManyAndCount.mockResolvedValue([[], 0]);
68
+ repository.createQueryBuilder.mockReturnValue(lastQb);
69
+ const nestedField = String(nestedFilters[0]);
70
+ await service.findAll({
71
+ page: 1,
72
+ limit: 10,
73
+ filter: { [`${nestedField}_cont`]: 'test' },
74
+ });
75
+ const [sql] = lastQb.andWhere.mock.calls[0];
76
+ const parts = nestedField.split('.');
77
+ const alias = parts.slice(0, -1).join('_');
78
+ const column = parts[parts.length - 1];
79
+ expect(sql).toContain(`${alias}.${column} ILIKE`);
80
+ });
81
+ it('should sort by nested fields via joined aliases', async () => {
82
+ const nestedSorts = (config.allowedSortFields ?? []).filter((field) => String(field).includes('.'));
83
+ if (nestedSorts.length === 0)
84
+ return;
85
+ lastQb = (0, mock_repository_1.createMockQb)();
86
+ lastQb.getManyAndCount.mockResolvedValue([[], 0]);
87
+ repository.createQueryBuilder.mockReturnValue(lastQb);
88
+ const nestedField = String(nestedSorts[0]);
89
+ await service.findAll({
90
+ page: 1,
91
+ limit: 10,
92
+ orderBy: nestedField,
93
+ orderDirection: 'ASC',
94
+ });
95
+ const parts = nestedField.split('.');
96
+ const alias = parts.slice(0, -1).join('_');
97
+ const column = parts[parts.length - 1];
98
+ expect(lastQb.orderBy).toHaveBeenCalledWith(`${alias}.${column}`, 'ASC');
99
+ });
62
100
  it('should join include relations via leftJoinAndSelect', async () => {
63
101
  if (!config.include || config.include.length === 0)
64
102
  return;
@@ -246,6 +284,26 @@ function crudServiceTests(config) {
246
284
  });
247
285
  expect(result.meta).toHaveProperty('total');
248
286
  });
287
+ it('should join nested relations on the count query when includeTotal is true', async () => {
288
+ const nestedIncludes = (config.include ?? []).filter((relation) => relation.includes('.'));
289
+ if (nestedIncludes.length === 0)
290
+ return;
291
+ lastQb = (0, mock_repository_1.createMockQb)();
292
+ lastQb.getMany.mockResolvedValue([]);
293
+ repository.createQueryBuilder.mockReturnValue(lastQb);
294
+ const countQb = (0, mock_repository_1.createMockQb)();
295
+ countQb.getCount.mockResolvedValue(0);
296
+ repository.createQueryBuilder.mockReturnValueOnce(lastQb);
297
+ repository.createQueryBuilder.mockReturnValueOnce(countQb);
298
+ await service.findAllWithCursor({ limit: 10, includeTotal: true });
299
+ for (const relation of nestedIncludes) {
300
+ const parts = relation.split('.');
301
+ const parentAlias = parts.slice(0, -1).join('_');
302
+ const field = parts[parts.length - 1];
303
+ const alias = parts.join('_');
304
+ expect(countQb.leftJoin).toHaveBeenCalledWith(`${parentAlias}.${field}`, alias);
305
+ }
306
+ });
249
307
  });
250
308
  describe('findAuditLogs', () => {
251
309
  it('should query audit logs with pagination', async () => {
@@ -8,8 +8,8 @@ export interface CrudTestConfig<TEntity extends ObjectLiteral, TCreateDto, TUpda
8
8
  createDto?: Type<TCreateDto>;
9
9
  updateDto?: Type<TUpdateDto>;
10
10
  responseDto?: Type<TResponseDto>;
11
- allowedFilters?: readonly (keyof TEntity)[];
12
- allowedSortFields?: readonly (keyof TEntity)[];
11
+ allowedFilters?: readonly (keyof TEntity | (string & {}))[];
12
+ allowedSortFields?: readonly (keyof TEntity | (string & {}))[];
13
13
  include?: readonly string[];
14
14
  userOwnershipField?: keyof TEntity;
15
15
  findMineQuery?: (qb: any, userId: string | number) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"testing.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testing.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testing.interface.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-util/nest-crud",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",