@mee4dy/crud-nestjs 1.0.3 → 1.0.5
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/dist/services/crud-params-adapter.service.d.ts +1 -0
- package/dist/services/crud-params-adapter.service.js +9 -1
- package/dist/services/crud-params-adapter.service.js.map +1 -1
- package/dist/types/crud-params.types.d.ts +2 -0
- package/dist/types/crud-response.types.d.ts +1 -0
- package/dist/utils/merge.util.js +4 -0
- package/dist/utils/merge.util.js.map +1 -1
- package/dist/utils/replace-pk.util.js +1 -1
- package/dist/utils/replace-pk.util.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +51 -0
|
@@ -14,7 +14,8 @@ class CrudParamsAdapterService {
|
|
|
14
14
|
const limit = this.getLimit();
|
|
15
15
|
const offset = this.getOffset();
|
|
16
16
|
const include = this.getInclude();
|
|
17
|
-
|
|
17
|
+
const repositoryParams = this.getRepositoryParams();
|
|
18
|
+
const baseOptions = {
|
|
18
19
|
attributes,
|
|
19
20
|
include,
|
|
20
21
|
where,
|
|
@@ -23,6 +24,13 @@ class CrudParamsAdapterService {
|
|
|
23
24
|
limit,
|
|
24
25
|
offset,
|
|
25
26
|
};
|
|
27
|
+
return {
|
|
28
|
+
...baseOptions,
|
|
29
|
+
...repositoryParams,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getRepositoryParams() {
|
|
33
|
+
return this.params.repositoryParams || {};
|
|
26
34
|
}
|
|
27
35
|
getInclude(joinList = this.params.join) {
|
|
28
36
|
const result = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud-params-adapter.service.js","sourceRoot":"","sources":["../../src/services/crud-params-adapter.service.ts"],"names":[],"mappings":";;;AAAA,yCAA0D;AAa1D,MAAa,wBAAwB;IACnC,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAEnC,KAAK;QACV,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"crud-params-adapter.service.js","sourceRoot":"","sources":["../../src/services/crud-params-adapter.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FindOptions } from 'sequelize';
|
|
1
2
|
import { Literal } from 'sequelize/types/utils';
|
|
2
3
|
export type CrudField = string;
|
|
3
4
|
export type CrudLimit = number;
|
|
@@ -37,4 +38,5 @@ export type CrudParams = {
|
|
|
37
38
|
groups?: CrudGroup[];
|
|
38
39
|
limit?: CrudLimit;
|
|
39
40
|
offset?: CrudOffset;
|
|
41
|
+
repositoryParams?: Partial<FindOptions>;
|
|
40
42
|
};
|
package/dist/utils/merge.util.js
CHANGED
|
@@ -40,6 +40,10 @@ function merge(objA, objB) {
|
|
|
40
40
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
41
41
|
return [...a, ...b];
|
|
42
42
|
}
|
|
43
|
+
// Special handling for objects with Symbol keys (Sequelize Op)
|
|
44
|
+
if (_.isObject(b) && Object.getOwnPropertySymbols(b).length > 0) {
|
|
45
|
+
return { ...a, ...b };
|
|
46
|
+
}
|
|
43
47
|
});
|
|
44
48
|
}
|
|
45
49
|
//# sourceMappingURL=merge.util.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.util.js","sourceRoot":"","sources":["../../src/utils/merge.util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,
|
|
1
|
+
{"version":3,"file":"merge.util.js","sourceRoot":"","sources":["../../src/utils/merge.util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,sBAWC;AAbD,0CAA4B;AAE5B,SAAgB,KAAK,CAAC,IAAI,EAAE,IAAI;IAC9B,OAAO,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACtB,CAAC;QAED,+DAA+D;QAC/D,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChE,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -7,7 +7,7 @@ function replacePkRecursive(obj, pk) {
|
|
|
7
7
|
}
|
|
8
8
|
if (typeof obj === 'object' && obj !== null) {
|
|
9
9
|
const isPlainObject = Object.getPrototypeOf(obj) === Object.prototype;
|
|
10
|
-
if (!isPlainObject) {
|
|
10
|
+
if (!isPlainObject || Object.getOwnPropertySymbols(obj).length > 0) {
|
|
11
11
|
return obj;
|
|
12
12
|
}
|
|
13
13
|
const result = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-pk.util.js","sourceRoot":"","sources":["../../src/utils/replace-pk.util.ts"],"names":[],"mappings":";;AAAA,gDA4BC;AA5BD,SAAgB,kBAAkB,CAAC,GAAQ,EAAE,EAAU;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,SAAS,CAAC;QAEtE,IAAI,CAAC,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"replace-pk.util.js","sourceRoot":"","sources":["../../src/utils/replace-pk.util.ts"],"names":[],"mappings":";;AAAA,gDA4BC;AA5BD,SAAgB,kBAAkB,CAAC,GAAQ,EAAE,EAAU;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,SAAS,CAAC;QAEtE,IAAI,CAAC,aAAa,IAAI,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnE,OAAO,GAAG,CAAC;QACb,CAAC;QAED,MAAM,MAAM,GAAQ,EAAE,CAAC;QAEvB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAEvC,MAAM,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -111,6 +111,7 @@ interface CrudParams {
|
|
|
111
111
|
groups?: string[]; // Группировка (GROUP BY)
|
|
112
112
|
limit?: number; // Лимит записей
|
|
113
113
|
offset?: number; // Смещение для пагинации
|
|
114
|
+
repositoryParams?: Partial<FindOptions>; // Прямые параметры Sequelize
|
|
114
115
|
}
|
|
115
116
|
```
|
|
116
117
|
|
|
@@ -259,6 +260,56 @@ const join = [
|
|
|
259
260
|
];
|
|
260
261
|
```
|
|
261
262
|
|
|
263
|
+
### Прямые параметры Sequelize (repositoryParams)
|
|
264
|
+
|
|
265
|
+
Поле `repositoryParams` позволяет передавать любые параметры напрямую в Sequelize для формирования сложных кастомных запросов.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// В коде:
|
|
269
|
+
const repositoryParams = {
|
|
270
|
+
subQuery: false,
|
|
271
|
+
distinct: true,
|
|
272
|
+
lock: true,
|
|
273
|
+
paranoid: false,
|
|
274
|
+
// любые другие параметры Sequelize FindOptions
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Примеры использования:**
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// Отключение soft delete для конкретного запроса
|
|
282
|
+
const params: CrudParams = {
|
|
283
|
+
filters: { user_id: 1 },
|
|
284
|
+
repositoryParams: {
|
|
285
|
+
paranoid: false,
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// Использование блокировки для критических операций
|
|
290
|
+
const params: CrudParams = {
|
|
291
|
+
filters: { id: 123 },
|
|
292
|
+
repositoryParams: {
|
|
293
|
+
lock: true,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Сложные запросы с подзапросами
|
|
298
|
+
const params: CrudParams = {
|
|
299
|
+
repositoryParams: {
|
|
300
|
+
subQuery: false,
|
|
301
|
+
distinct: true,
|
|
302
|
+
attributes: {
|
|
303
|
+
include: [
|
|
304
|
+
[Sequelize.literal('(SELECT COUNT(*) FROM comments WHERE comments.post_id = Posts.id)'), 'comments_count'],
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Важно:** Параметры из `repositoryParams` имеют приоритет над параметрами, сгенерированными из других полей `CrudParams`.
|
|
312
|
+
|
|
262
313
|
## Примеры контроллеров
|
|
263
314
|
|
|
264
315
|
### Минимальный контроллер
|