@nest-util/nest-crud 0.0.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 +22 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/lib/controllers/nest-crud.controller.d.ts +25 -0
- package/dist/lib/controllers/nest-crud.controller.d.ts.map +1 -0
- package/dist/lib/controllers/nest-crud.controller.js +159 -0
- package/dist/lib/decorators/response-message.decorator.d.ts +9 -0
- package/dist/lib/decorators/response-message.decorator.d.ts.map +1 -0
- package/dist/lib/decorators/response-message.decorator.js +10 -0
- package/dist/lib/dtos/filter.dto.d.ts +4 -0
- package/dist/lib/dtos/filter.dto.d.ts.map +1 -0
- package/dist/lib/dtos/filter.dto.js +30 -0
- package/dist/lib/dtos/pagination.dto.d.ts +7 -0
- package/dist/lib/dtos/pagination.dto.d.ts.map +1 -0
- package/dist/lib/dtos/pagination.dto.js +54 -0
- package/dist/lib/helpers/exception-filter.helper.d.ts +6 -0
- package/dist/lib/helpers/exception-filter.helper.d.ts.map +1 -0
- package/dist/lib/helpers/exception-filter.helper.js +35 -0
- package/dist/lib/helpers/filter.helper.d.ts +3 -0
- package/dist/lib/helpers/filter.helper.d.ts.map +1 -0
- package/dist/lib/helpers/filter.helper.js +148 -0
- package/dist/lib/helpers/pagination.helper.d.ts +7 -0
- package/dist/lib/helpers/pagination.helper.d.ts.map +1 -0
- package/dist/lib/helpers/pagination.helper.js +15 -0
- package/dist/lib/interceptors/response.interceptor.d.ts +9 -0
- package/dist/lib/interceptors/response.interceptor.d.ts.map +1 -0
- package/dist/lib/interceptors/response.interceptor.js +39 -0
- package/dist/lib/interfaces/crud.interface.d.ts +23 -0
- package/dist/lib/interfaces/crud.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/crud.interface.js +2 -0
- package/dist/lib/nest-crud.module.d.ts +3 -0
- package/dist/lib/nest-crud.module.d.ts.map +1 -0
- package/dist/lib/nest-crud.module.js +15 -0
- package/dist/lib/services/nest-crud.service.d.ts +69 -0
- package/dist/lib/services/nest-crud.service.d.ts.map +1 -0
- package/dist/lib/services/nest-crud.service.js +154 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# nest-crud
|
|
2
|
+
|
|
3
|
+
This library was generated with [Nx](https://nx.dev).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
To install this library in your project, use the permanent URL from the latest GitHub Release:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add https://github.com/nigussolomon/nest-util/releases/download/latest/nest-util-nest-crud-0.0.1.tgz
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> [!TIP]
|
|
14
|
+
> This tarball contains only the compiled code and its specific dependencies, making it as clean as a standard npm package.
|
|
15
|
+
|
|
16
|
+
## Building
|
|
17
|
+
|
|
18
|
+
Run `nx build nest-crud` to build the library.
|
|
19
|
+
|
|
20
|
+
## Running unit tests
|
|
21
|
+
|
|
22
|
+
Run `nx test nest-crud` to execute the unit tests via [Jest](https://jestjs.io).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './lib/nest-crud.module';
|
|
2
|
+
export * from './lib/services/nest-crud.service';
|
|
3
|
+
export * from './lib/controllers/nest-crud.controller';
|
|
4
|
+
export * from './lib/dtos/filter.dto';
|
|
5
|
+
export * from './lib/dtos/pagination.dto';
|
|
6
|
+
export * from './lib/decorators/response-message.decorator';
|
|
7
|
+
export * from './lib/interceptors/response.interceptor';
|
|
8
|
+
export * from './lib/interfaces/crud.interface';
|
|
9
|
+
export * from './lib/helpers/exception-filter.helper';
|
|
10
|
+
export { Audit, AuditLogEntity } from '@nest-util/nest-audit';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,yCAAyC,CAAC;AACxD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuditLogEntity = exports.Audit = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
tslib_1.__exportStar(require("./lib/nest-crud.module"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/services/nest-crud.service"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./lib/controllers/nest-crud.controller"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./lib/dtos/filter.dto"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./lib/dtos/pagination.dto"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./lib/decorators/response-message.decorator"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./lib/interceptors/response.interceptor"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./lib/interfaces/crud.interface"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./lib/helpers/exception-filter.helper"), exports);
|
|
14
|
+
var nest_audit_1 = require("@nest-util/nest-audit");
|
|
15
|
+
Object.defineProperty(exports, "Audit", { enumerable: true, get: function () { return nest_audit_1.Audit; } });
|
|
16
|
+
Object.defineProperty(exports, "AuditLogEntity", { enumerable: true, get: function () { return nest_audit_1.AuditLogEntity; } });
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { CrudEndpoint, CrudInterface } from '../interfaces/crud.interface';
|
|
3
|
+
import { PaginationDto } from '../dtos/pagination.dto';
|
|
4
|
+
import { FilterDto } from '../dtos/filter.dto';
|
|
5
|
+
import { ListAuditLogsDto } from '@nest-util/nest-audit';
|
|
6
|
+
export declare const AUTH_PERMISSIONS_METADATA_KEY = "auth:permissions";
|
|
7
|
+
export type CrudEndpointPermissions = string | readonly string[];
|
|
8
|
+
export type CrudPermissionsMap = Partial<Record<CrudEndpoint, CrudEndpointPermissions>>;
|
|
9
|
+
export interface CrudControllerFactoryOptions {
|
|
10
|
+
permissions?: CrudPermissionsMap;
|
|
11
|
+
}
|
|
12
|
+
export interface IBaseController<CD, UD, RD> {
|
|
13
|
+
service: CrudInterface<CD, UD, RD>;
|
|
14
|
+
findAll(query: PaginationDto & FilterDto): Promise<{
|
|
15
|
+
data: RD[];
|
|
16
|
+
meta?: unknown;
|
|
17
|
+
} | RD[]>;
|
|
18
|
+
findOne(id: number): Promise<RD>;
|
|
19
|
+
create(dto: CD): Promise<RD>;
|
|
20
|
+
update(id: number, dto: UD): Promise<RD>;
|
|
21
|
+
remove(id: number): Promise<boolean>;
|
|
22
|
+
findAuditLogs?(query: ListAuditLogsDto): Promise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
export declare function CreateNestedCrudController<CD, UD, RD>(createDto: Type<CD>, updateDto: Type<UD>, responseDto: Type<RD>, options?: CrudControllerFactoryOptions): Type<IBaseController<CD, UD, RD>>;
|
|
25
|
+
//# sourceMappingURL=nest-crud.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest-crud.controller.d.ts","sourceRoot":"","sources":["../../../src/lib/controllers/nest-crud.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,IAAI,EACL,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAS,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,eAAO,MAAM,6BAA6B,qBAAqB,CAAC;AAEhE,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACtC,MAAM,CAAC,YAAY,EAAE,uBAAuB,CAAC,CAC9C,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,MAAM,WAAW,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;IACzC,OAAO,EAAE,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,CACL,KAAK,EAAE,aAAa,GAAG,SAAS,GAC/B,OAAO,CAAC;QAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAyDD,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EACnD,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,EACnB,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,EACnB,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,EACrB,OAAO,CAAC,EAAE,4BAA4B,GACrC,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CA2FnC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AUTH_PERMISSIONS_METADATA_KEY = void 0;
|
|
4
|
+
exports.CreateNestedCrudController = CreateNestedCrudController;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
8
|
+
const response_message_decorator_1 = require("../decorators/response-message.decorator");
|
|
9
|
+
const nest_audit_1 = require("@nest-util/nest-audit");
|
|
10
|
+
exports.AUTH_PERMISSIONS_METADATA_KEY = 'auth:permissions';
|
|
11
|
+
const toPermissionList = (permissionValue) => {
|
|
12
|
+
if (Array.isArray(permissionValue)) {
|
|
13
|
+
return [
|
|
14
|
+
...permissionValue.filter((permission) => Boolean(permission)),
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
return typeof permissionValue === 'string' && permissionValue
|
|
18
|
+
? [permissionValue]
|
|
19
|
+
: [];
|
|
20
|
+
};
|
|
21
|
+
const applyPermissionMetadata = (controllerClass, permissions) => {
|
|
22
|
+
if (!permissions) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const endpoint of Object.keys(permissions)) {
|
|
26
|
+
const permissionValue = permissions[endpoint];
|
|
27
|
+
if (!permissionValue) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const permissionList = toPermissionList(permissionValue);
|
|
31
|
+
if (permissionList.length === 0) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const handler = controllerClass.prototype[endpoint];
|
|
35
|
+
if (typeof handler !== 'function') {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
Reflect.defineMetadata(exports.AUTH_PERMISSIONS_METADATA_KEY, permissionList, handler);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function CreateNestedCrudController(createDto, updateDto, responseDto, options) {
|
|
42
|
+
class BaseController {
|
|
43
|
+
constructor(service) {
|
|
44
|
+
this.service = service;
|
|
45
|
+
}
|
|
46
|
+
ensureEndpointEnabled(endpoint) {
|
|
47
|
+
if (this.service.disabledEndpoints?.includes(endpoint)) {
|
|
48
|
+
throw new common_1.NotFoundException('Resource not found');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
findAll(query) {
|
|
52
|
+
this.ensureEndpointEnabled('findAll');
|
|
53
|
+
return this.service.findAll(query);
|
|
54
|
+
}
|
|
55
|
+
create(dto) {
|
|
56
|
+
this.ensureEndpointEnabled('create');
|
|
57
|
+
return this.service.create(dto);
|
|
58
|
+
}
|
|
59
|
+
update(id, dto) {
|
|
60
|
+
this.ensureEndpointEnabled('update');
|
|
61
|
+
return this.service.update(id, dto);
|
|
62
|
+
}
|
|
63
|
+
remove(id) {
|
|
64
|
+
this.ensureEndpointEnabled('remove');
|
|
65
|
+
return this.service.remove(id);
|
|
66
|
+
}
|
|
67
|
+
findAuditLogs(query) {
|
|
68
|
+
this.ensureEndpointEnabled('findAuditLogs');
|
|
69
|
+
if (!this.service.findAuditLogs) {
|
|
70
|
+
throw new common_1.NotFoundException('Resource not found');
|
|
71
|
+
}
|
|
72
|
+
return this.service.findAuditLogs(query);
|
|
73
|
+
}
|
|
74
|
+
findOne(id) {
|
|
75
|
+
this.ensureEndpointEnabled('findOne');
|
|
76
|
+
return this.service.findOne(id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
tslib_1.__decorate([
|
|
80
|
+
(0, common_1.Get)(),
|
|
81
|
+
(0, response_message_decorator_1.Message)('fetched'),
|
|
82
|
+
(0, swagger_1.ApiResponse)({ type: [responseDto] }),
|
|
83
|
+
(0, swagger_1.ApiQuery)({
|
|
84
|
+
name: 'filter',
|
|
85
|
+
required: false,
|
|
86
|
+
style: 'deepObject',
|
|
87
|
+
explode: true,
|
|
88
|
+
type: 'object',
|
|
89
|
+
description: 'Filters in format filter[field_operator]=value. Operators: eq, ne, cont, notcont, starts, ends, gte, lte, gt, lt, in, nin, isnull. Grouping keys: and, or',
|
|
90
|
+
example: {
|
|
91
|
+
name_cont: 'Bob',
|
|
92
|
+
or: [{ name_eq: 'Bob' }, { name_eq: 'Carol' }],
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
(0, swagger_1.ApiQuery)({ name: 'page', required: false, type: Number }),
|
|
96
|
+
(0, swagger_1.ApiQuery)({ name: 'limit', required: false, type: Number }),
|
|
97
|
+
(0, swagger_1.ApiQuery)({ name: 'orderBy', required: false, type: String }),
|
|
98
|
+
(0, swagger_1.ApiQuery)({
|
|
99
|
+
name: 'orderDirection',
|
|
100
|
+
required: false,
|
|
101
|
+
enum: ['ASC', 'DESC'],
|
|
102
|
+
}),
|
|
103
|
+
tslib_1.__param(0, (0, common_1.Query)()),
|
|
104
|
+
tslib_1.__metadata("design:type", Function),
|
|
105
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
106
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
107
|
+
], BaseController.prototype, "findAll", null);
|
|
108
|
+
tslib_1.__decorate([
|
|
109
|
+
(0, common_1.Post)(),
|
|
110
|
+
(0, response_message_decorator_1.Message)('created'),
|
|
111
|
+
(0, nest_audit_1.Audit)({ action: 'CREATE' }),
|
|
112
|
+
(0, swagger_1.ApiBody)({ type: createDto }),
|
|
113
|
+
(0, swagger_1.ApiResponse)({ type: responseDto }),
|
|
114
|
+
tslib_1.__param(0, (0, common_1.Body)()),
|
|
115
|
+
tslib_1.__metadata("design:type", Function),
|
|
116
|
+
tslib_1.__metadata("design:paramtypes", [Object]),
|
|
117
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
118
|
+
], BaseController.prototype, "create", null);
|
|
119
|
+
tslib_1.__decorate([
|
|
120
|
+
(0, common_1.Patch)(':id'),
|
|
121
|
+
(0, response_message_decorator_1.Message)('updated'),
|
|
122
|
+
(0, nest_audit_1.Audit)({ action: 'UPDATE' }),
|
|
123
|
+
(0, swagger_1.ApiBody)({ type: updateDto }),
|
|
124
|
+
(0, swagger_1.ApiResponse)({ type: responseDto }),
|
|
125
|
+
tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
|
|
126
|
+
tslib_1.__param(1, (0, common_1.Body)()),
|
|
127
|
+
tslib_1.__metadata("design:type", Function),
|
|
128
|
+
tslib_1.__metadata("design:paramtypes", [Number, Object]),
|
|
129
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
130
|
+
], BaseController.prototype, "update", null);
|
|
131
|
+
tslib_1.__decorate([
|
|
132
|
+
(0, common_1.Delete)(':id'),
|
|
133
|
+
(0, response_message_decorator_1.Message)('deleted'),
|
|
134
|
+
(0, nest_audit_1.Audit)({ action: 'DELETE' }),
|
|
135
|
+
tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
|
|
136
|
+
tslib_1.__metadata("design:type", Function),
|
|
137
|
+
tslib_1.__metadata("design:paramtypes", [Number]),
|
|
138
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
139
|
+
], BaseController.prototype, "remove", null);
|
|
140
|
+
tslib_1.__decorate([
|
|
141
|
+
(0, common_1.Get)('auditlogs'),
|
|
142
|
+
(0, response_message_decorator_1.Message)('fetched'),
|
|
143
|
+
tslib_1.__param(0, (0, common_1.Query)()),
|
|
144
|
+
tslib_1.__metadata("design:type", Function),
|
|
145
|
+
tslib_1.__metadata("design:paramtypes", [nest_audit_1.ListAuditLogsDto]),
|
|
146
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
147
|
+
], BaseController.prototype, "findAuditLogs", null);
|
|
148
|
+
tslib_1.__decorate([
|
|
149
|
+
(0, common_1.Get)(':id'),
|
|
150
|
+
(0, response_message_decorator_1.Message)('fetched'),
|
|
151
|
+
(0, swagger_1.ApiResponse)({ type: responseDto }),
|
|
152
|
+
tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
|
|
153
|
+
tslib_1.__metadata("design:type", Function),
|
|
154
|
+
tslib_1.__metadata("design:paramtypes", [Number]),
|
|
155
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
156
|
+
], BaseController.prototype, "findOne", null);
|
|
157
|
+
applyPermissionMetadata(BaseController, options?.permissions);
|
|
158
|
+
return BaseController;
|
|
159
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const MESSAGE_KEY = "customMessage";
|
|
2
|
+
export declare const Message: (message: string) => import("@nestjs/common").CustomDecorator<string>;
|
|
3
|
+
export declare const ENTITY_NAME_KEY = "entityName";
|
|
4
|
+
export interface EntityNames {
|
|
5
|
+
singular: string;
|
|
6
|
+
plural: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const EntityName: (names: string | EntityNames) => import("@nestjs/common").CustomDecorator<string>;
|
|
9
|
+
//# sourceMappingURL=response-message.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-message.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/decorators/response-message.decorator.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAC3C,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,qDAAsC,CAAC;AAE9E,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,GAAG,WAAW,qDAInD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityName = exports.ENTITY_NAME_KEY = exports.Message = exports.MESSAGE_KEY = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
exports.MESSAGE_KEY = 'customMessage';
|
|
6
|
+
const Message = (message) => (0, common_1.SetMetadata)(exports.MESSAGE_KEY, message);
|
|
7
|
+
exports.Message = Message;
|
|
8
|
+
exports.ENTITY_NAME_KEY = 'entityName';
|
|
9
|
+
const EntityName = (names) => (0, common_1.SetMetadata)(exports.ENTITY_NAME_KEY, typeof names === 'string' ? { singular: names, plural: `${names}s` } : names);
|
|
10
|
+
exports.EntityName = EntityName;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.dto.d.ts","sourceRoot":"","sources":["../../../src/lib/dtos/filter.dto.ts"],"names":[],"mappings":"AAGA,qBAAa,SAAS;IAqBpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilterDto = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const class_transformer_1 = require("class-transformer");
|
|
6
|
+
const class_validator_1 = require("class-validator");
|
|
7
|
+
class FilterDto {
|
|
8
|
+
}
|
|
9
|
+
exports.FilterDto = FilterDto;
|
|
10
|
+
tslib_1.__decorate([
|
|
11
|
+
(0, class_validator_1.IsOptional)(),
|
|
12
|
+
(0, class_validator_1.IsObject)(),
|
|
13
|
+
(0, class_transformer_1.Transform)(({ value, obj }) => {
|
|
14
|
+
// 1. If Express already parsed it into an object: { name_cont: 'Alice' }
|
|
15
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
// 2. Fallback: If for some reason it's still a flat object with string keys
|
|
19
|
+
// like { "filter[name_cont]": "Alice" }
|
|
20
|
+
const filters = {};
|
|
21
|
+
Object.keys(obj).forEach((key) => {
|
|
22
|
+
const match = key.match(/^filter\[(.*)\]$/);
|
|
23
|
+
if (match && match[1]) {
|
|
24
|
+
filters[match[1]] = obj[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return Object.keys(filters).length > 0 ? filters : value;
|
|
28
|
+
}),
|
|
29
|
+
tslib_1.__metadata("design:type", Object)
|
|
30
|
+
], FilterDto.prototype, "filter", void 0);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.dto.d.ts","sourceRoot":"","sources":["../../../src/lib/dtos/pagination.dto.ts"],"names":[],"mappings":"AAIA,qBAAa,aAAa;IAUxB,IAAI,CAAC,EAAE,MAAM,CAAK;IAWlB,KAAK,CAAC,EAAE,MAAM,CAAM;IAMpB,OAAO,CAAC,EAAE,MAAM,CAAC;IAQjB,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACjC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PaginationDto = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const class_validator_1 = require("class-validator");
|
|
6
|
+
const class_transformer_1 = require("class-transformer");
|
|
7
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
8
|
+
class PaginationDto {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.page = 1;
|
|
11
|
+
this.limit = 10;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.PaginationDto = PaginationDto;
|
|
15
|
+
tslib_1.__decorate([
|
|
16
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
17
|
+
description: 'Page number',
|
|
18
|
+
minimum: 1,
|
|
19
|
+
default: 1,
|
|
20
|
+
}),
|
|
21
|
+
(0, class_validator_1.IsOptional)(),
|
|
22
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
23
|
+
(0, class_validator_1.IsInt)(),
|
|
24
|
+
(0, class_validator_1.Min)(1),
|
|
25
|
+
tslib_1.__metadata("design:type", Number)
|
|
26
|
+
], PaginationDto.prototype, "page", void 0);
|
|
27
|
+
tslib_1.__decorate([
|
|
28
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
29
|
+
description: 'Items per page',
|
|
30
|
+
minimum: 1,
|
|
31
|
+
default: 10,
|
|
32
|
+
}),
|
|
33
|
+
(0, class_validator_1.IsOptional)(),
|
|
34
|
+
(0, class_transformer_1.Type)(() => Number),
|
|
35
|
+
(0, class_validator_1.IsInt)(),
|
|
36
|
+
(0, class_validator_1.Min)(1),
|
|
37
|
+
tslib_1.__metadata("design:type", Number)
|
|
38
|
+
], PaginationDto.prototype, "limit", void 0);
|
|
39
|
+
tslib_1.__decorate([
|
|
40
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
41
|
+
description: 'Field to order by',
|
|
42
|
+
}),
|
|
43
|
+
(0, class_validator_1.IsOptional)(),
|
|
44
|
+
tslib_1.__metadata("design:type", String)
|
|
45
|
+
], PaginationDto.prototype, "orderBy", void 0);
|
|
46
|
+
tslib_1.__decorate([
|
|
47
|
+
(0, swagger_1.ApiPropertyOptional)({
|
|
48
|
+
description: 'Sort direction',
|
|
49
|
+
enum: ['ASC', 'DESC'],
|
|
50
|
+
default: 'DESC',
|
|
51
|
+
}),
|
|
52
|
+
(0, class_validator_1.IsOptional)(),
|
|
53
|
+
tslib_1.__metadata("design:type", String)
|
|
54
|
+
], PaginationDto.prototype, "orderDirection", void 0);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
|
|
2
|
+
import { QueryFailedError } from 'typeorm';
|
|
3
|
+
export declare class TypeOrmExceptionFilter implements ExceptionFilter {
|
|
4
|
+
catch(exception: QueryFailedError, host: ArgumentsHost): void;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=exception-filter.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exception-filter.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/exception-filter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAU3C,qBACa,sBAAuB,YAAW,eAAe;IAC5D,KAAK,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;CA8B9D"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeOrmExceptionFilter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
|
+
let TypeOrmExceptionFilter = class TypeOrmExceptionFilter {
|
|
8
|
+
catch(exception, host) {
|
|
9
|
+
const ctx = host.switchToHttp();
|
|
10
|
+
const response = ctx.getResponse();
|
|
11
|
+
const driverError = exception.driverError;
|
|
12
|
+
const isUniqueViolation = driverError.code === '23505' || driverError.errno === 1062;
|
|
13
|
+
let status = common_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
14
|
+
let message = 'Internal server error';
|
|
15
|
+
if (isUniqueViolation) {
|
|
16
|
+
status = common_1.HttpStatus.UNPROCESSABLE_ENTITY;
|
|
17
|
+
message = 'Duplicate entry: A record with this value already exists.';
|
|
18
|
+
if (driverError.detail) {
|
|
19
|
+
message = driverError.detail
|
|
20
|
+
.replace('Key ', '')
|
|
21
|
+
.replace(/[()]/g, '')
|
|
22
|
+
.trim();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
response.status(status).json({
|
|
26
|
+
status: 'error',
|
|
27
|
+
message: message,
|
|
28
|
+
statusCode: status,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.TypeOrmExceptionFilter = TypeOrmExceptionFilter;
|
|
33
|
+
exports.TypeOrmExceptionFilter = TypeOrmExceptionFilter = tslib_1.__decorate([
|
|
34
|
+
(0, common_1.Catch)(typeorm_1.QueryFailedError)
|
|
35
|
+
], TypeOrmExceptionFilter);
|
|
@@ -0,0 +1,3 @@
|
|
|
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;
|
|
3
|
+
//# sourceMappingURL=filter.helper.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyFilters = applyFilters;
|
|
4
|
+
const SAFE_FIELD_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
5
|
+
const toArrayValue = (value) => {
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === 'string') {
|
|
10
|
+
return value
|
|
11
|
+
.split(',')
|
|
12
|
+
.map((part) => part.trim())
|
|
13
|
+
.filter((part) => part.length > 0);
|
|
14
|
+
}
|
|
15
|
+
return value === undefined || value === null ? [] : [value];
|
|
16
|
+
};
|
|
17
|
+
const toBooleanValue = (value) => {
|
|
18
|
+
if (typeof value === 'boolean')
|
|
19
|
+
return value;
|
|
20
|
+
if (typeof value === 'number')
|
|
21
|
+
return value !== 0;
|
|
22
|
+
if (typeof value !== 'string')
|
|
23
|
+
return null;
|
|
24
|
+
const normalized = value.trim().toLowerCase();
|
|
25
|
+
if (['true', '1', 'yes'].includes(normalized))
|
|
26
|
+
return true;
|
|
27
|
+
if (['false', '0', 'no'].includes(normalized))
|
|
28
|
+
return false;
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
const parseFilterKey = (rawKey) => {
|
|
32
|
+
const separatorIndex = rawKey.lastIndexOf('_');
|
|
33
|
+
if (separatorIndex <= 0 || separatorIndex === rawKey.length - 1)
|
|
34
|
+
return null;
|
|
35
|
+
const field = rawKey.slice(0, separatorIndex);
|
|
36
|
+
const operator = rawKey.slice(separatorIndex + 1).toLowerCase();
|
|
37
|
+
return { field, operator };
|
|
38
|
+
};
|
|
39
|
+
const buildCondition = (field, operator, value, paramIndex) => {
|
|
40
|
+
const paramKey = `filter_${paramIndex.current++}`;
|
|
41
|
+
switch (operator) {
|
|
42
|
+
case 'eq':
|
|
43
|
+
return { sql: `e.${field} = :${paramKey}`, params: { [paramKey]: value } };
|
|
44
|
+
case 'ne':
|
|
45
|
+
return { sql: `e.${field} != :${paramKey}`, params: { [paramKey]: value } };
|
|
46
|
+
case 'cont':
|
|
47
|
+
return {
|
|
48
|
+
sql: `e.${field} ILIKE :${paramKey}`,
|
|
49
|
+
params: { [paramKey]: `%${value}%` },
|
|
50
|
+
};
|
|
51
|
+
case 'notcont':
|
|
52
|
+
return {
|
|
53
|
+
sql: `e.${field} NOT ILIKE :${paramKey}`,
|
|
54
|
+
params: { [paramKey]: `%${value}%` },
|
|
55
|
+
};
|
|
56
|
+
case 'starts':
|
|
57
|
+
return {
|
|
58
|
+
sql: `e.${field} ILIKE :${paramKey}`,
|
|
59
|
+
params: { [paramKey]: `${value}%` },
|
|
60
|
+
};
|
|
61
|
+
case 'ends':
|
|
62
|
+
return {
|
|
63
|
+
sql: `e.${field} ILIKE :${paramKey}`,
|
|
64
|
+
params: { [paramKey]: `%${value}` },
|
|
65
|
+
};
|
|
66
|
+
case 'gte':
|
|
67
|
+
return { sql: `e.${field} >= :${paramKey}`, params: { [paramKey]: value } };
|
|
68
|
+
case 'lte':
|
|
69
|
+
return { sql: `e.${field} <= :${paramKey}`, params: { [paramKey]: value } };
|
|
70
|
+
case 'gt':
|
|
71
|
+
return { sql: `e.${field} > :${paramKey}`, params: { [paramKey]: value } };
|
|
72
|
+
case 'lt':
|
|
73
|
+
return { sql: `e.${field} < :${paramKey}`, params: { [paramKey]: value } };
|
|
74
|
+
case 'in':
|
|
75
|
+
case 'nin': {
|
|
76
|
+
const values = toArrayValue(value);
|
|
77
|
+
if (values.length === 0)
|
|
78
|
+
return null;
|
|
79
|
+
return {
|
|
80
|
+
sql: operator === 'in'
|
|
81
|
+
? `e.${field} IN (:...${paramKey})`
|
|
82
|
+
: `e.${field} NOT IN (:...${paramKey})`,
|
|
83
|
+
params: { [paramKey]: values },
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
case 'isnull': {
|
|
87
|
+
const isNull = toBooleanValue(value);
|
|
88
|
+
if (isNull === null)
|
|
89
|
+
return null;
|
|
90
|
+
return { sql: isNull ? `e.${field} IS NULL` : `e.${field} IS NOT NULL` };
|
|
91
|
+
}
|
|
92
|
+
default:
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const buildExpression = (node, combinator, allowedFilters, paramIndex, params) => {
|
|
97
|
+
if (!node || typeof node !== 'object')
|
|
98
|
+
return null;
|
|
99
|
+
const conditions = [];
|
|
100
|
+
const entries = Array.isArray(node)
|
|
101
|
+
? node.map((item, index) => [String(index), item])
|
|
102
|
+
: Object.entries(node);
|
|
103
|
+
for (const [rawKey, value] of entries) {
|
|
104
|
+
if (rawKey === 'and' || rawKey === 'or') {
|
|
105
|
+
const nestedCombinator = rawKey;
|
|
106
|
+
const nestedNodes = Array.isArray(value) ? value : [value];
|
|
107
|
+
const nestedExpressions = nestedNodes
|
|
108
|
+
.map((nestedNode) => buildExpression(nestedNode, 'and', allowedFilters, paramIndex, params))
|
|
109
|
+
.filter((sql) => Boolean(sql));
|
|
110
|
+
if (nestedExpressions.length > 0) {
|
|
111
|
+
conditions.push(`(${nestedExpressions.join(` ${nestedCombinator.toUpperCase()} `)})`);
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const parsed = parseFilterKey(rawKey);
|
|
116
|
+
if (!parsed)
|
|
117
|
+
continue;
|
|
118
|
+
const { field, operator } = parsed;
|
|
119
|
+
if (!SAFE_FIELD_PATTERN.test(field))
|
|
120
|
+
continue;
|
|
121
|
+
if (!allowedFilters.includes(field))
|
|
122
|
+
continue;
|
|
123
|
+
const condition = buildCondition(field, operator, value, paramIndex);
|
|
124
|
+
if (!condition)
|
|
125
|
+
continue;
|
|
126
|
+
if (condition.params)
|
|
127
|
+
Object.assign(params, condition.params);
|
|
128
|
+
conditions.push(condition.sql);
|
|
129
|
+
}
|
|
130
|
+
if (conditions.length === 0)
|
|
131
|
+
return null;
|
|
132
|
+
if (conditions.length === 1)
|
|
133
|
+
return conditions[0];
|
|
134
|
+
return `(${conditions.join(` ${combinator.toUpperCase()} `)})`;
|
|
135
|
+
};
|
|
136
|
+
function applyFilters(qb, filters, allowedFilters) {
|
|
137
|
+
if (!filters)
|
|
138
|
+
return;
|
|
139
|
+
const params = {};
|
|
140
|
+
const expression = buildExpression(filters, 'and', allowedFilters.map(String), { current: 0 }, params);
|
|
141
|
+
if (!expression)
|
|
142
|
+
return;
|
|
143
|
+
if (Object.keys(params).length > 0) {
|
|
144
|
+
qb.andWhere(expression, params);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
qb.andWhere(expression);
|
|
148
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm';
|
|
2
|
+
import { PaginationDto } from '../dtos/pagination.dto';
|
|
3
|
+
export declare function applyPagination<Entity extends ObjectLiteral>(qb: SelectQueryBuilder<Entity>, query: PaginationDto): {
|
|
4
|
+
page: number;
|
|
5
|
+
limit: number;
|
|
6
|
+
} | null;
|
|
7
|
+
//# sourceMappingURL=pagination.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/pagination.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAgB,eAAe,CAAC,MAAM,SAAS,aAAa,EAC1D,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAC9B,KAAK,EAAE,aAAa;;;SAgBrB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyPagination = applyPagination;
|
|
4
|
+
function applyPagination(qb, query) {
|
|
5
|
+
const { page, limit } = query;
|
|
6
|
+
if (!page || !limit) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const skip = (page - 1) * limit;
|
|
10
|
+
qb.skip(skip).take(limit);
|
|
11
|
+
return {
|
|
12
|
+
page,
|
|
13
|
+
limit,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { Reflector } from '@nestjs/core';
|
|
4
|
+
export declare class ResponseInterceptor implements NestInterceptor {
|
|
5
|
+
private readonly reflector;
|
|
6
|
+
constructor(reflector: Reflector);
|
|
7
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=response.interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.interceptor.d.ts","sourceRoot":"","sources":["../../../src/lib/interceptors/response.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,qBACa,mBAAoB,YAAW,eAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;CA+B7E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseInterceptor = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const operators_1 = require("rxjs/operators");
|
|
7
|
+
const core_1 = require("@nestjs/core");
|
|
8
|
+
const response_message_decorator_1 = require("../decorators/response-message.decorator");
|
|
9
|
+
let ResponseInterceptor = class ResponseInterceptor {
|
|
10
|
+
constructor(reflector) {
|
|
11
|
+
this.reflector = reflector;
|
|
12
|
+
}
|
|
13
|
+
intercept(context, next) {
|
|
14
|
+
const handler = context.getHandler();
|
|
15
|
+
const controller = context.getClass();
|
|
16
|
+
return next.handle().pipe((0, operators_1.map)((data) => {
|
|
17
|
+
const entityConfig = this.reflector.get(response_message_decorator_1.ENTITY_NAME_KEY, controller);
|
|
18
|
+
const action = this.reflector.get(response_message_decorator_1.MESSAGE_KEY, handler);
|
|
19
|
+
const isList = Array.isArray(data) || Array.isArray(data?.data);
|
|
20
|
+
const name = isList
|
|
21
|
+
? entityConfig?.plural ?? 'Resources'
|
|
22
|
+
: entityConfig?.singular ?? 'Resource';
|
|
23
|
+
const finalMessage = action
|
|
24
|
+
? `${name} ${action} successfully`
|
|
25
|
+
: 'Request successful';
|
|
26
|
+
return {
|
|
27
|
+
message: finalMessage,
|
|
28
|
+
data: data?.data ?? data ?? null,
|
|
29
|
+
meta: data?.meta,
|
|
30
|
+
status: 'success',
|
|
31
|
+
};
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.ResponseInterceptor = ResponseInterceptor;
|
|
36
|
+
exports.ResponseInterceptor = ResponseInterceptor = tslib_1.__decorate([
|
|
37
|
+
(0, common_1.Injectable)(),
|
|
38
|
+
tslib_1.__metadata("design:paramtypes", [core_1.Reflector])
|
|
39
|
+
], ResponseInterceptor);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FilterDto } from '../dtos/filter.dto';
|
|
2
|
+
import { PaginationDto } from '../dtos/pagination.dto';
|
|
3
|
+
export type CrudEndpoint = 'findAll' | 'findOne' | 'create' | 'update' | 'remove' | 'findAuditLogs';
|
|
4
|
+
export interface AuditLogQuery {
|
|
5
|
+
user_id?: string;
|
|
6
|
+
start_date?: string;
|
|
7
|
+
end_date?: string;
|
|
8
|
+
page?: number;
|
|
9
|
+
limit?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface CrudInterface<CreateDto, UpdateDto, ResponseDto> {
|
|
12
|
+
disabledEndpoints?: readonly CrudEndpoint[];
|
|
13
|
+
findAll(query: PaginationDto & FilterDto): Promise<{
|
|
14
|
+
data: ResponseDto[];
|
|
15
|
+
meta?: unknown;
|
|
16
|
+
}>;
|
|
17
|
+
findOne(id: number): Promise<ResponseDto>;
|
|
18
|
+
create(dto: CreateDto): Promise<ResponseDto>;
|
|
19
|
+
update(id: number, dto: UpdateDto): Promise<ResponseDto>;
|
|
20
|
+
remove(id: number): Promise<boolean>;
|
|
21
|
+
findAuditLogs?(query: AuditLogQuery): Promise<unknown>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=crud.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/crud.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,MAAM,YAAY,GACpB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,eAAe,CAAC;AAEpB,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW;IAC9D,iBAAiB,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAE5C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;QACjD,IAAI,EAAE,WAAW,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1C,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,aAAa,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest-crud.module.d.ts","sourceRoot":"","sources":["../../src/lib/nest-crud.module.ts"],"names":[],"mappings":"AAGA,qBAIa,cAAc;CAAG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NestCrudModule = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const nest_crud_service_1 = require("./services/nest-crud.service");
|
|
7
|
+
let NestCrudModule = class NestCrudModule {
|
|
8
|
+
};
|
|
9
|
+
exports.NestCrudModule = NestCrudModule;
|
|
10
|
+
exports.NestCrudModule = NestCrudModule = tslib_1.__decorate([
|
|
11
|
+
(0, common_1.Module)({
|
|
12
|
+
providers: [nest_crud_service_1.NestCrudService],
|
|
13
|
+
exports: [nest_crud_service_1.NestCrudService],
|
|
14
|
+
})
|
|
15
|
+
], NestCrudModule);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
import { ObjectLiteral, Repository } from 'typeorm';
|
|
3
|
+
import { AuditLogEntity } from '@nest-util/nest-audit';
|
|
4
|
+
import { PaginationDto } from '../dtos/pagination.dto';
|
|
5
|
+
import { FilterDto } from '../dtos/filter.dto';
|
|
6
|
+
import { CrudEndpoint, CrudInterface } from '../interfaces/crud.interface';
|
|
7
|
+
export interface CrudServiceOptions<Entity extends ObjectLiteral, ResponseDto> {
|
|
8
|
+
repository: Repository<Entity>;
|
|
9
|
+
allowedFilters?: readonly (keyof Entity)[];
|
|
10
|
+
allowedSortFields?: readonly (keyof Entity)[];
|
|
11
|
+
include?: readonly string[];
|
|
12
|
+
relations?: {
|
|
13
|
+
property: keyof Entity;
|
|
14
|
+
repo: Repository<ObjectLiteral>;
|
|
15
|
+
idField?: string;
|
|
16
|
+
}[];
|
|
17
|
+
toResponseDto?: (entity: Entity | Entity[]) => ResponseDto | ResponseDto[];
|
|
18
|
+
createDtoClass?: Type<unknown>;
|
|
19
|
+
updateDtoClass?: Type<unknown>;
|
|
20
|
+
disabledEndpoints?: readonly CrudEndpoint[];
|
|
21
|
+
}
|
|
22
|
+
export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = Partial<Entity>, UpdateDto = Partial<Entity>, ResponseDto = Entity> implements CrudInterface<CreateDto, UpdateDto, ResponseDto> {
|
|
23
|
+
protected readonly repo: Repository<Entity>;
|
|
24
|
+
protected readonly allowedFilters: readonly (keyof Entity)[];
|
|
25
|
+
protected readonly allowedSortFields: readonly (keyof Entity)[];
|
|
26
|
+
protected readonly include: readonly string[];
|
|
27
|
+
protected readonly relations: {
|
|
28
|
+
property: keyof Entity;
|
|
29
|
+
repo: Repository<ObjectLiteral>;
|
|
30
|
+
idField?: string;
|
|
31
|
+
}[];
|
|
32
|
+
protected readonly toResponseDto?: (entity: Entity | Entity[]) => ResponseDto | ResponseDto[];
|
|
33
|
+
protected readonly createDtoClass?: Type<unknown>;
|
|
34
|
+
protected readonly updateDtoClass?: Type<unknown>;
|
|
35
|
+
readonly disabledEndpoints: readonly CrudEndpoint[];
|
|
36
|
+
constructor(options: CrudServiceOptions<Entity, ResponseDto>);
|
|
37
|
+
private resolveRelations;
|
|
38
|
+
findAll(query: PaginationDto & FilterDto): Promise<{
|
|
39
|
+
data: ResponseDto[];
|
|
40
|
+
meta: {
|
|
41
|
+
total: number;
|
|
42
|
+
page: number;
|
|
43
|
+
limit: number;
|
|
44
|
+
};
|
|
45
|
+
} | {
|
|
46
|
+
data: ResponseDto[];
|
|
47
|
+
meta?: undefined;
|
|
48
|
+
}>;
|
|
49
|
+
findOne(id: number): Promise<ResponseDto>;
|
|
50
|
+
create(payload: CreateDto): Promise<ResponseDto>;
|
|
51
|
+
update(id: number, payload: UpdateDto): Promise<ResponseDto>;
|
|
52
|
+
remove(id: number): Promise<boolean>;
|
|
53
|
+
findAuditLogs(query: {
|
|
54
|
+
user_id?: string;
|
|
55
|
+
start_date?: string;
|
|
56
|
+
end_date?: string;
|
|
57
|
+
page?: number;
|
|
58
|
+
limit?: number;
|
|
59
|
+
}): Promise<{
|
|
60
|
+
data: AuditLogEntity[];
|
|
61
|
+
meta: {
|
|
62
|
+
total: number;
|
|
63
|
+
page: number;
|
|
64
|
+
limit: number;
|
|
65
|
+
totalPages: number;
|
|
66
|
+
};
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=nest-crud.service.d.ts.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NestCrudService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const nest_audit_1 = require("@nest-util/nest-audit");
|
|
7
|
+
const filter_helper_1 = require("../helpers/filter.helper");
|
|
8
|
+
const pagination_helper_1 = require("../helpers/pagination.helper");
|
|
9
|
+
let NestCrudService = class NestCrudService {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.repo = options.repository;
|
|
12
|
+
this.allowedFilters = options.allowedFilters ?? [];
|
|
13
|
+
this.allowedSortFields = options.allowedSortFields ?? [];
|
|
14
|
+
this.include = options.include ?? [];
|
|
15
|
+
this.relations = options.relations ?? [];
|
|
16
|
+
this.toResponseDto = options.toResponseDto;
|
|
17
|
+
this.createDtoClass = options.createDtoClass;
|
|
18
|
+
this.updateDtoClass = options.updateDtoClass;
|
|
19
|
+
this.disabledEndpoints = options.disabledEndpoints ?? [];
|
|
20
|
+
}
|
|
21
|
+
async resolveRelations(payload) {
|
|
22
|
+
if (!this.relations.length)
|
|
23
|
+
return payload;
|
|
24
|
+
for (const relation of this.relations) {
|
|
25
|
+
const idField = relation.idField ?? `${String(relation.property)}Id`;
|
|
26
|
+
if (!(idField in payload))
|
|
27
|
+
continue;
|
|
28
|
+
const id = payload[idField];
|
|
29
|
+
if (!id)
|
|
30
|
+
continue;
|
|
31
|
+
const entity = await relation.repo.findOneBy({
|
|
32
|
+
id,
|
|
33
|
+
});
|
|
34
|
+
if (!entity) {
|
|
35
|
+
throw new common_1.NotFoundException(`${String(relation.property)} not found`);
|
|
36
|
+
}
|
|
37
|
+
payload[String(relation.property)] = entity;
|
|
38
|
+
delete payload[idField];
|
|
39
|
+
}
|
|
40
|
+
return payload;
|
|
41
|
+
}
|
|
42
|
+
async findAll(query) {
|
|
43
|
+
const qb = this.repo.createQueryBuilder('e');
|
|
44
|
+
if (this.include.length > 0) {
|
|
45
|
+
this.include.forEach((relation) => {
|
|
46
|
+
const parts = relation.split('.');
|
|
47
|
+
if (parts.length === 1) {
|
|
48
|
+
qb.leftJoinAndSelect(`e.${parts[0]}`, parts[0]);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const parentAlias = parts.slice(0, -1).join('_');
|
|
52
|
+
const field = parts[parts.length - 1];
|
|
53
|
+
const alias = parts.join('_');
|
|
54
|
+
qb.leftJoinAndSelect(`${parentAlias}.${field}`, alias);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
(0, filter_helper_1.applyFilters)(qb, query.filter, this.allowedFilters);
|
|
59
|
+
const paginationMeta = (0, pagination_helper_1.applyPagination)(qb, query);
|
|
60
|
+
if (query.orderBy) {
|
|
61
|
+
const orderDirection = query.orderDirection === 'ASC' ? 'ASC' : 'DESC';
|
|
62
|
+
if (this.allowedSortFields.length === 0 ||
|
|
63
|
+
this.allowedSortFields.includes(query.orderBy)) {
|
|
64
|
+
qb.orderBy(`e.${query.orderBy}`, orderDirection);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const [entities, total] = await qb.getManyAndCount();
|
|
68
|
+
const data = this.toResponseDto
|
|
69
|
+
? this.toResponseDto(entities)
|
|
70
|
+
: entities;
|
|
71
|
+
return paginationMeta
|
|
72
|
+
? { data, meta: { ...paginationMeta, total } }
|
|
73
|
+
: { data };
|
|
74
|
+
}
|
|
75
|
+
async findOne(id) {
|
|
76
|
+
const entity = await this.repo.findOne({
|
|
77
|
+
where: { id },
|
|
78
|
+
relations: this.include,
|
|
79
|
+
});
|
|
80
|
+
if (!entity) {
|
|
81
|
+
throw new common_1.NotFoundException('Resource not found');
|
|
82
|
+
}
|
|
83
|
+
return this.toResponseDto
|
|
84
|
+
? this.toResponseDto(entity)
|
|
85
|
+
: entity;
|
|
86
|
+
}
|
|
87
|
+
async create(payload) {
|
|
88
|
+
const resolved = await this.resolveRelations(payload);
|
|
89
|
+
const entity = await this.repo.save(resolved);
|
|
90
|
+
return this.toResponseDto
|
|
91
|
+
? this.toResponseDto(entity)
|
|
92
|
+
: entity;
|
|
93
|
+
}
|
|
94
|
+
async update(id, payload) {
|
|
95
|
+
const existing = await this.repo.findOneBy({
|
|
96
|
+
id,
|
|
97
|
+
});
|
|
98
|
+
if (!existing) {
|
|
99
|
+
throw new common_1.NotFoundException('Resource not found');
|
|
100
|
+
}
|
|
101
|
+
const resolved = await this.resolveRelations(payload);
|
|
102
|
+
await this.repo.update(id, resolved);
|
|
103
|
+
return this.findOne(id);
|
|
104
|
+
}
|
|
105
|
+
async remove(id) {
|
|
106
|
+
const result = await this.repo.delete(id);
|
|
107
|
+
if (result.affected === 0) {
|
|
108
|
+
throw new common_1.NotFoundException('Resource not found');
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
async findAuditLogs(query) {
|
|
113
|
+
const page = query.page ?? 1;
|
|
114
|
+
const limit = query.limit ?? 10;
|
|
115
|
+
const qb = this.repo.manager
|
|
116
|
+
.getRepository(nest_audit_1.AuditLogEntity)
|
|
117
|
+
.createQueryBuilder('auditLog')
|
|
118
|
+
.where('auditLog.entity = :entity', {
|
|
119
|
+
entity: this.repo.metadata.name,
|
|
120
|
+
})
|
|
121
|
+
.orderBy('auditLog.createdAt', 'DESC');
|
|
122
|
+
if (query.user_id) {
|
|
123
|
+
qb.andWhere('auditLog.userId = :userId', {
|
|
124
|
+
userId: query.user_id,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (query.start_date) {
|
|
128
|
+
qb.andWhere('auditLog.createdAt >= :startDate', {
|
|
129
|
+
startDate: new Date(query.start_date),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (query.end_date) {
|
|
133
|
+
qb.andWhere('auditLog.createdAt <= :endDate', {
|
|
134
|
+
endDate: new Date(query.end_date),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
qb.skip((page - 1) * limit).take(limit);
|
|
138
|
+
const [data, total] = await qb.getManyAndCount();
|
|
139
|
+
return {
|
|
140
|
+
data,
|
|
141
|
+
meta: {
|
|
142
|
+
total,
|
|
143
|
+
page,
|
|
144
|
+
limit,
|
|
145
|
+
totalPages: Math.ceil(total / limit) || 1,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
exports.NestCrudService = NestCrudService;
|
|
151
|
+
exports.NestCrudService = NestCrudService = tslib_1.__decorate([
|
|
152
|
+
(0, common_1.Injectable)(),
|
|
153
|
+
tslib_1.__metadata("design:paramtypes", [Object])
|
|
154
|
+
], NestCrudService);
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nest-util/nest-crud",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"module": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./package.json": "./package.json",
|
|
9
|
+
".": {
|
|
10
|
+
"@nest-util/source": "./src/index.ts",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"!**/*.tsbuildinfo"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"tslib": "^2.3.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@nest-util/nest-audit": "workspace:*",
|
|
25
|
+
"@nestjs/common": "^11.0.0",
|
|
26
|
+
"@nestjs/core": "^11.0.0",
|
|
27
|
+
"@nestjs/swagger": "^11.2.6",
|
|
28
|
+
"class-transformer": "^0.5.1",
|
|
29
|
+
"class-validator": "^0.14.3",
|
|
30
|
+
"express": "^5.2.1",
|
|
31
|
+
"typeorm": "^0.3.28",
|
|
32
|
+
"rxjs": "^7.8.0"
|
|
33
|
+
}
|
|
34
|
+
}
|