@angelps/prisma-query-builder 0.1.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.
- package/README.md +709 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/valibot.adapter.d.ts +14 -0
- package/dist/adapters/valibot.adapter.d.ts.map +1 -0
- package/dist/adapters/valibot.adapter.js +21 -0
- package/dist/adapters/valibot.adapter.js.map +1 -0
- package/dist/adapters/zod.adapter.d.ts +29 -0
- package/dist/adapters/zod.adapter.d.ts.map +1 -0
- package/dist/adapters/zod.adapter.js +42 -0
- package/dist/adapters/zod.adapter.js.map +1 -0
- package/dist/controllers/generic.controller.d.ts +79 -0
- package/dist/controllers/generic.controller.d.ts.map +1 -0
- package/dist/controllers/generic.controller.js +279 -0
- package/dist/controllers/generic.controller.js.map +1 -0
- package/dist/controllers/index.d.ts +2 -0
- package/dist/controllers/index.d.ts.map +1 -0
- package/dist/controllers/index.js +2 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/errors/app-errors.d.ts +17 -0
- package/dist/errors/app-errors.d.ts.map +1 -0
- package/dist/errors/app-errors.js +28 -0
- package/dist/errors/app-errors.js.map +1 -0
- package/dist/errors/error-messages.d.ts +80 -0
- package/dist/errors/error-messages.d.ts.map +1 -0
- package/dist/errors/error-messages.js +75 -0
- package/dist/errors/error-messages.js.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/query-builder/helpers/order-by.helper.d.ts +4 -0
- package/dist/query-builder/helpers/order-by.helper.d.ts.map +1 -0
- package/dist/query-builder/helpers/order-by.helper.js +24 -0
- package/dist/query-builder/helpers/order-by.helper.js.map +1 -0
- package/dist/query-builder/helpers/pagination.helper.d.ts +6 -0
- package/dist/query-builder/helpers/pagination.helper.d.ts.map +1 -0
- package/dist/query-builder/helpers/pagination.helper.js +9 -0
- package/dist/query-builder/helpers/pagination.helper.js.map +1 -0
- package/dist/query-builder/helpers/where.helper.d.ts +5 -0
- package/dist/query-builder/helpers/where.helper.d.ts.map +1 -0
- package/dist/query-builder/helpers/where.helper.js +356 -0
- package/dist/query-builder/helpers/where.helper.js.map +1 -0
- package/dist/query-builder/index.d.ts +3 -0
- package/dist/query-builder/index.d.ts.map +1 -0
- package/dist/query-builder/index.js +3 -0
- package/dist/query-builder/index.js.map +1 -0
- package/dist/query-builder/query-builder.d.ts +56 -0
- package/dist/query-builder/query-builder.d.ts.map +1 -0
- package/dist/query-builder/query-builder.js +149 -0
- package/dist/query-builder/query-builder.js.map +1 -0
- package/dist/query-builder/query-builder.types.d.ts +83 -0
- package/dist/query-builder/query-builder.types.d.ts.map +1 -0
- package/dist/query-builder/query-builder.types.js +2 -0
- package/dist/query-builder/query-builder.types.js.map +1 -0
- package/dist/repositories/crud.repository.prisma.d.ts +44 -0
- package/dist/repositories/crud.repository.prisma.d.ts.map +1 -0
- package/dist/repositories/crud.repository.prisma.js +246 -0
- package/dist/repositories/crud.repository.prisma.js.map +1 -0
- package/dist/repositories/index.d.ts +2 -0
- package/dist/repositories/index.d.ts.map +1 -0
- package/dist/repositories/index.js +2 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/services/audit.service.d.ts +32 -0
- package/dist/services/audit.service.d.ts.map +1 -0
- package/dist/services/audit.service.js +57 -0
- package/dist/services/audit.service.js.map +1 -0
- package/dist/services/error-handler.service.d.ts +34 -0
- package/dist/services/error-handler.service.d.ts.map +1 -0
- package/dist/services/error-handler.service.js +159 -0
- package/dist/services/error-handler.service.js.map +1 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +3 -0
- package/dist/services/index.js.map +1 -0
- package/dist/types/crud-config.d.ts +20 -0
- package/dist/types/crud-config.d.ts.map +1 -0
- package/dist/types/crud-config.js +2 -0
- package/dist/types/crud-config.js.map +1 -0
- package/dist/types/generic-repository.d.ts +36 -0
- package/dist/types/generic-repository.d.ts.map +1 -0
- package/dist/types/generic-repository.js +2 -0
- package/dist/types/generic-repository.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/logger.d.ts +17 -0
- package/dist/types/logger.d.ts.map +1 -0
- package/dist/types/logger.js +8 -0
- package/dist/types/logger.js.map +1 -0
- package/dist/types/pagination.d.ts +11 -0
- package/dist/types/pagination.d.ts.map +1 -0
- package/dist/types/pagination.js +2 -0
- package/dist/types/pagination.js.map +1 -0
- package/dist/types/prisma-delegate.types.d.ts +36 -0
- package/dist/types/prisma-delegate.types.d.ts.map +1 -0
- package/dist/types/prisma-delegate.types.js +15 -0
- package/dist/types/prisma-delegate.types.js.map +1 -0
- package/dist/types/query-params.d.ts +40 -0
- package/dist/types/query-params.d.ts.map +1 -0
- package/dist/types/query-params.js +2 -0
- package/dist/types/query-params.js.map +1 -0
- package/dist/types/schema-adapter.d.ts +19 -0
- package/dist/types/schema-adapter.d.ts.map +1 -0
- package/dist/types/schema-adapter.js +2 -0
- package/dist/types/schema-adapter.js.map +1 -0
- package/dist/utils/date.utils.d.ts +13 -0
- package/dist/utils/date.utils.d.ts.map +1 -0
- package/dist/utils/date.utils.js +75 -0
- package/dist/utils/date.utils.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/phone.utils.d.ts +7 -0
- package/dist/utils/phone.utils.d.ts.map +1 -0
- package/dist/utils/phone.utils.js +15 -0
- package/dist/utils/phone.utils.js.map +1 -0
- package/dist/utils/response.utils.d.ts +5 -0
- package/dist/utils/response.utils.d.ts.map +1 -0
- package/dist/utils/response.utils.js +13 -0
- package/dist/utils/response.utils.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SchemaAdapter } from '../types/schema-adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Valibot schema adapter — default validation strategy.
|
|
4
|
+
*
|
|
5
|
+
* Wraps Valibot's `parse()` so that CrudRepository doesn't import
|
|
6
|
+
* valibot directly, making validation pluggable.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ValibotAdapter implements SchemaAdapter {
|
|
9
|
+
parse<T = unknown>(schema: unknown, data: unknown): T;
|
|
10
|
+
isValidSchema(schema: unknown): boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Singleton instance for convenience. */
|
|
13
|
+
export declare const valibotAdapter: ValibotAdapter;
|
|
14
|
+
//# sourceMappingURL=valibot.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valibot.adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/valibot.adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;IAIrD,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAQxC;AAED,0CAA0C;AAC1C,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parse } from 'valibot';
|
|
2
|
+
/**
|
|
3
|
+
* Valibot schema adapter — default validation strategy.
|
|
4
|
+
*
|
|
5
|
+
* Wraps Valibot's `parse()` so that CrudRepository doesn't import
|
|
6
|
+
* valibot directly, making validation pluggable.
|
|
7
|
+
*/
|
|
8
|
+
export class ValibotAdapter {
|
|
9
|
+
parse(schema, data) {
|
|
10
|
+
return parse(schema, data);
|
|
11
|
+
}
|
|
12
|
+
isValidSchema(schema) {
|
|
13
|
+
return (!!schema &&
|
|
14
|
+
typeof schema === 'object' &&
|
|
15
|
+
'type' in schema &&
|
|
16
|
+
typeof schema['type'] === 'string');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Singleton instance for convenience. */
|
|
20
|
+
export const valibotAdapter = new ValibotAdapter();
|
|
21
|
+
//# sourceMappingURL=valibot.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valibot.adapter.js","sourceRoot":"","sources":["../../src/adapters/valibot.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACzB,KAAK,CAAc,MAAe,EAAE,IAAa;QAC/C,OAAO,KAAK,CAAC,MAAa,EAAE,IAAI,CAAM,CAAC;IACzC,CAAC;IAED,aAAa,CAAC,MAAe;QAC3B,OAAO,CACL,CAAC,CAAC,MAAM;YACR,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,IAAK,MAAiB;YAC5B,OAAQ,MAAkC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAChE,CAAC;IACJ,CAAC;CACF;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SchemaAdapter } from '../types/schema-adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema adapter.
|
|
4
|
+
*
|
|
5
|
+
* Allows consumers using Zod instead of Valibot to pass their schemas
|
|
6
|
+
* to CrudRepository without changing the repository code.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { z } from 'zod';
|
|
11
|
+
* import { ZodAdapter } from '@angelps/prisma-query-builder';
|
|
12
|
+
*
|
|
13
|
+
* class UserRepo extends CrudRepository<typeof prisma.user> {
|
|
14
|
+
* createSchema = z.object({ name: z.string().min(2), email: z.string().email() });
|
|
15
|
+
* updateSchema = z.object({ name: z.string().min(2) });
|
|
16
|
+
*
|
|
17
|
+
* constructor() {
|
|
18
|
+
* super(prisma.user, config, options, { schemaAdapter: new ZodAdapter() });
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class ZodAdapter implements SchemaAdapter {
|
|
24
|
+
parse<T = unknown>(schema: unknown, data: unknown): T;
|
|
25
|
+
isValidSchema(schema: unknown): boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Singleton instance for convenience. */
|
|
28
|
+
export declare const zodAdapter: ZodAdapter;
|
|
29
|
+
//# sourceMappingURL=zod.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/zod.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC9C,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;IAarD,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAQxC;AAED,0CAA0C;AAC1C,eAAO,MAAM,UAAU,YAAmB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema adapter.
|
|
3
|
+
*
|
|
4
|
+
* Allows consumers using Zod instead of Valibot to pass their schemas
|
|
5
|
+
* to CrudRepository without changing the repository code.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { z } from 'zod';
|
|
10
|
+
* import { ZodAdapter } from '@angelps/prisma-query-builder';
|
|
11
|
+
*
|
|
12
|
+
* class UserRepo extends CrudRepository<typeof prisma.user> {
|
|
13
|
+
* createSchema = z.object({ name: z.string().min(2), email: z.string().email() });
|
|
14
|
+
* updateSchema = z.object({ name: z.string().min(2) });
|
|
15
|
+
*
|
|
16
|
+
* constructor() {
|
|
17
|
+
* super(prisma.user, config, options, { schemaAdapter: new ZodAdapter() });
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class ZodAdapter {
|
|
23
|
+
parse(schema, data) {
|
|
24
|
+
// Zod schemas have a `.parse()` method
|
|
25
|
+
if (schema &&
|
|
26
|
+
typeof schema === 'object' &&
|
|
27
|
+
'parse' in schema &&
|
|
28
|
+
typeof schema['parse'] === 'function') {
|
|
29
|
+
return schema.parse(data);
|
|
30
|
+
}
|
|
31
|
+
throw new Error('ZodAdapter: provided schema does not have a .parse() method');
|
|
32
|
+
}
|
|
33
|
+
isValidSchema(schema) {
|
|
34
|
+
return (!!schema &&
|
|
35
|
+
typeof schema === 'object' &&
|
|
36
|
+
'parse' in schema &&
|
|
37
|
+
typeof schema['parse'] === 'function');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Singleton instance for convenience. */
|
|
41
|
+
export const zodAdapter = new ZodAdapter();
|
|
42
|
+
//# sourceMappingURL=zod.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.adapter.js","sourceRoot":"","sources":["../../src/adapters/zod.adapter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,UAAU;IACrB,KAAK,CAAc,MAAe,EAAE,IAAa;QAC/C,uCAAuC;QACvC,IACE,MAAM;YACN,OAAO,MAAM,KAAK,QAAQ;YAC1B,OAAO,IAAI,MAAM;YACjB,OAAQ,MAAkC,CAAC,OAAO,CAAC,KAAK,UAAU,EAClE,CAAC;YACD,OAAQ,MAAsC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,aAAa,CAAC,MAAe;QAC3B,OAAO,CACL,CAAC,CAAC,MAAM;YACR,OAAO,MAAM,KAAK,QAAQ;YAC1B,OAAO,IAAK,MAAiB;YAC7B,OAAQ,MAAkC,CAAC,OAAO,CAAC,KAAK,UAAU,CACnE,CAAC;IACJ,CAAC;CACF;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from 'express';
|
|
2
|
+
import type { QueryParams } from '../types/query-params.js';
|
|
3
|
+
import { ErrorHandlerService } from '../services/error-handler.service.js';
|
|
4
|
+
import type { IAuditService } from '../services/audit.service.js';
|
|
5
|
+
import type { IGenericRepository, RepositoryOptions } from '../types/generic-repository.js';
|
|
6
|
+
/** Maps a field from `req.user` to a query param field. */
|
|
7
|
+
export type UserFieldInjection = {
|
|
8
|
+
/** Field path on `req.user` (e.g. "branchIds", "companyIds", "tenantId") */
|
|
9
|
+
userField: string;
|
|
10
|
+
/** Field name to inject into query params (e.g. "branchId", "companyId") */
|
|
11
|
+
queryField: string;
|
|
12
|
+
};
|
|
13
|
+
/** Lifecycle hooks for controller operations. */
|
|
14
|
+
export type ControllerHooks<T = any> = {
|
|
15
|
+
beforeCreate?: (req: Request, data: unknown) => unknown | Promise<unknown>;
|
|
16
|
+
afterCreate?: (req: Request, result: T) => void | Promise<void>;
|
|
17
|
+
beforeUpdate?: (req: Request, id: number, data: unknown) => unknown | Promise<unknown>;
|
|
18
|
+
afterUpdate?: (req: Request, id: number) => void | Promise<void>;
|
|
19
|
+
beforeDelete?: (req: Request, id: number) => void | Promise<void>;
|
|
20
|
+
afterDelete?: (req: Request, id: number) => void | Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export type GenericControllerConfig<T = any> = {
|
|
23
|
+
entityName?: string;
|
|
24
|
+
audit?: boolean;
|
|
25
|
+
auditService?: IAuditService;
|
|
26
|
+
/**
|
|
27
|
+
* Configurable field injection from `req.user` into query params.
|
|
28
|
+
*
|
|
29
|
+
* Replaces the hardcoded `filterByUserBranch` / `filterByUserCompany` flags.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* {
|
|
34
|
+
* injectFromUser: [
|
|
35
|
+
* { userField: 'branchIds', queryField: 'branchId' },
|
|
36
|
+
* { userField: 'companyIds', queryField: 'companyId' },
|
|
37
|
+
* { userField: 'tenantId', queryField: 'tenantId' },
|
|
38
|
+
* ]
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
injectFromUser?: UserFieldInjection[];
|
|
43
|
+
/** Lifecycle hooks executed before/after CRUD operations. */
|
|
44
|
+
hooks?: ControllerHooks<T>;
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated Use `injectFromUser: [{ userField: 'branchIds', queryField: 'branchId' }]` instead.
|
|
47
|
+
*/
|
|
48
|
+
filterByUserBranch?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated Use `injectFromUser: [{ userField: 'companyIds', queryField: 'companyId' }]` instead.
|
|
51
|
+
*/
|
|
52
|
+
filterByUserCompany?: boolean;
|
|
53
|
+
};
|
|
54
|
+
export declare class GenericController<T> {
|
|
55
|
+
protected readonly repository: IGenericRepository<T>;
|
|
56
|
+
protected readonly entity: string;
|
|
57
|
+
protected readonly auditEnabled: boolean;
|
|
58
|
+
protected readonly auditSvc?: IAuditService;
|
|
59
|
+
protected readonly injections: UserFieldInjection[];
|
|
60
|
+
protected readonly hooks: ControllerHooks<T>;
|
|
61
|
+
errorHandlerService: ErrorHandlerService;
|
|
62
|
+
constructor(repository: IGenericRepository<T>, entity: string, config?: GenericControllerConfig<T>);
|
|
63
|
+
protected getRepoOptions(req: Request): RepositoryOptions;
|
|
64
|
+
/**
|
|
65
|
+
* Inject user fields into query params based on the configured injections.
|
|
66
|
+
*/
|
|
67
|
+
protected injectUserFields(req: Request, queryParams: QueryParams): QueryParams;
|
|
68
|
+
getAll(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
69
|
+
getById(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
70
|
+
create(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
71
|
+
update(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
72
|
+
delete(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
73
|
+
protected validateIfResourceExists(id: number, options?: RepositoryOptions): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Método genérico para ejecutar operaciones con auditoría automática
|
|
76
|
+
*/
|
|
77
|
+
protected executeWithAudit(req: Request, res: Response, next: NextFunction, operation: (id: number, options?: RepositoryOptions) => Promise<void>, action: 'UPDATE' | 'DELETE' | 'CREATE', successMessage?: string, statusCode?: number): Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=generic.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/generic.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { ErrorMessages } from '../errors/error-messages.js';
|
|
2
|
+
import { ErrorHandlerService } from '../services/error-handler.service.js';
|
|
3
|
+
import { apiResponse, apiPaginationResponse } from '../utils/response.utils.js';
|
|
4
|
+
export class GenericController {
|
|
5
|
+
repository;
|
|
6
|
+
entity;
|
|
7
|
+
auditEnabled;
|
|
8
|
+
auditSvc;
|
|
9
|
+
injections;
|
|
10
|
+
hooks;
|
|
11
|
+
errorHandlerService = new ErrorHandlerService();
|
|
12
|
+
constructor(repository, entity, config = {}) {
|
|
13
|
+
this.repository = repository;
|
|
14
|
+
this.entity = config.entityName ?? entity;
|
|
15
|
+
this.auditEnabled = config.audit ?? false;
|
|
16
|
+
this.auditSvc = config.auditService;
|
|
17
|
+
this.hooks = config.hooks ?? {};
|
|
18
|
+
// Build injections list — merge explicit config with deprecated flags
|
|
19
|
+
const injections = [...(config.injectFromUser ?? [])];
|
|
20
|
+
// Backwards compat: translate deprecated flags into injections
|
|
21
|
+
if (config.filterByUserBranch) {
|
|
22
|
+
const alreadyHas = injections.some((i) => i.queryField === 'branchId');
|
|
23
|
+
if (!alreadyHas) {
|
|
24
|
+
injections.push({ userField: 'branchIds', queryField: 'branchId' });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (config.filterByUserCompany) {
|
|
28
|
+
const alreadyHas = injections.some((i) => i.queryField === 'companyId');
|
|
29
|
+
if (!alreadyHas) {
|
|
30
|
+
injections.push({ userField: 'companyIds', queryField: 'companyId' });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.injections = injections;
|
|
34
|
+
}
|
|
35
|
+
getRepoOptions(req) {
|
|
36
|
+
const userId = req.user?.id;
|
|
37
|
+
const audit = req.audit;
|
|
38
|
+
return {
|
|
39
|
+
...(typeof userId === 'number' ? { userId } : {}),
|
|
40
|
+
...(audit?.requestId ? { requestId: audit.requestId } : {}),
|
|
41
|
+
...(audit?.ip ? { ip: audit.ip } : {}),
|
|
42
|
+
...(audit?.userAgent ? { userAgent: audit.userAgent } : {}),
|
|
43
|
+
...(audit?.path ? { path: audit.path } : {}),
|
|
44
|
+
...(audit?.method ? { method: audit.method } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Inject user fields into query params based on the configured injections.
|
|
49
|
+
*/
|
|
50
|
+
injectUserFields(req, queryParams) {
|
|
51
|
+
if (this.injections.length === 0)
|
|
52
|
+
return queryParams;
|
|
53
|
+
const result = { ...queryParams };
|
|
54
|
+
const user = req.user;
|
|
55
|
+
if (!user)
|
|
56
|
+
return result;
|
|
57
|
+
for (const { userField, queryField } of this.injections) {
|
|
58
|
+
const value = user[userField];
|
|
59
|
+
if (value !== undefined) {
|
|
60
|
+
result[queryField] = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
async getAll(req, res, next) {
|
|
66
|
+
try {
|
|
67
|
+
const queryParams = req.query;
|
|
68
|
+
const options = this.getRepoOptions(req);
|
|
69
|
+
const enrichedParams = this.injectUserFields(req, queryParams);
|
|
70
|
+
const data = await this.repository.findAll(enrichedParams, options);
|
|
71
|
+
apiPaginationResponse(res, data, 'Resources retrieved successfully', 200);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.errorHandlerService.genericErrorHandler({
|
|
75
|
+
error: error,
|
|
76
|
+
res,
|
|
77
|
+
next,
|
|
78
|
+
entity: this.entity,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async getById(req, res, next) {
|
|
83
|
+
try {
|
|
84
|
+
const id = Number(req.params.id);
|
|
85
|
+
if (Number.isNaN(id)) {
|
|
86
|
+
apiResponse(res, null, 'Invalid id', 400);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const options = this.getRepoOptions(req);
|
|
90
|
+
const data = await this.repository.findById(id, options);
|
|
91
|
+
if (!data)
|
|
92
|
+
throw new Error(ErrorMessages.RESOURCE_NOT_FOUND.message);
|
|
93
|
+
apiResponse(res, data, 'Resource retrieved successfully', 200);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
this.errorHandlerService.genericErrorHandler({
|
|
97
|
+
error: error,
|
|
98
|
+
res,
|
|
99
|
+
next,
|
|
100
|
+
entity: this.entity,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async create(req, res, next) {
|
|
105
|
+
try {
|
|
106
|
+
const options = this.getRepoOptions(req);
|
|
107
|
+
// Lifecycle hook: beforeCreate
|
|
108
|
+
let data = req.body;
|
|
109
|
+
if (this.hooks.beforeCreate) {
|
|
110
|
+
data = await this.hooks.beforeCreate(req, data);
|
|
111
|
+
}
|
|
112
|
+
const created = await this.repository.create(data, options);
|
|
113
|
+
// Lifecycle hook: afterCreate
|
|
114
|
+
if (this.hooks.afterCreate) {
|
|
115
|
+
await this.hooks.afterCreate(req, created);
|
|
116
|
+
}
|
|
117
|
+
if (this.auditEnabled && this.auditSvc) {
|
|
118
|
+
await this.auditSvc.log({
|
|
119
|
+
action: 'CREATE',
|
|
120
|
+
entity: this.entity,
|
|
121
|
+
entityId: created?.id ?? null,
|
|
122
|
+
after: created,
|
|
123
|
+
metadata: { source: 'generic-controller' },
|
|
124
|
+
options,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
apiResponse(res, created, `${this.entity} created successfully`, 201);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
this.errorHandlerService.genericErrorHandler({
|
|
131
|
+
error: error,
|
|
132
|
+
res,
|
|
133
|
+
next,
|
|
134
|
+
entity: this.entity,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async update(req, res, next) {
|
|
139
|
+
try {
|
|
140
|
+
const id = Number(req.params.id);
|
|
141
|
+
if (Number.isNaN(id)) {
|
|
142
|
+
apiResponse(res, null, 'Invalid id', 400);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const options = this.getRepoOptions(req);
|
|
146
|
+
// Always validate existence; capture snapshot only for audit
|
|
147
|
+
const existing = await this.repository.findById(id, options);
|
|
148
|
+
if (!existing) {
|
|
149
|
+
throw new Error(ErrorMessages.RESOURCE_NOT_FOUND.message);
|
|
150
|
+
}
|
|
151
|
+
const before = this.auditEnabled ? existing : null;
|
|
152
|
+
// Lifecycle hook: beforeUpdate
|
|
153
|
+
let data = req.body;
|
|
154
|
+
if (this.hooks.beforeUpdate) {
|
|
155
|
+
data = await this.hooks.beforeUpdate(req, id, data);
|
|
156
|
+
}
|
|
157
|
+
await this.repository.update(id, data, options);
|
|
158
|
+
// Lifecycle hook: afterUpdate
|
|
159
|
+
if (this.hooks.afterUpdate) {
|
|
160
|
+
await this.hooks.afterUpdate(req, id);
|
|
161
|
+
}
|
|
162
|
+
const after = this.auditEnabled
|
|
163
|
+
? await this.repository.findById(id, options)
|
|
164
|
+
: null;
|
|
165
|
+
if (this.auditEnabled && this.auditSvc) {
|
|
166
|
+
await this.auditSvc.log({
|
|
167
|
+
action: 'UPDATE',
|
|
168
|
+
entity: this.entity,
|
|
169
|
+
entityId: id,
|
|
170
|
+
before,
|
|
171
|
+
after,
|
|
172
|
+
metadata: { source: 'generic-controller' },
|
|
173
|
+
options,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
apiResponse(res, null, `${this.entity} updated successfully`, 204);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
this.errorHandlerService.genericErrorHandler({
|
|
180
|
+
error: error,
|
|
181
|
+
res,
|
|
182
|
+
next,
|
|
183
|
+
entity: this.entity,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async delete(req, res, next) {
|
|
188
|
+
try {
|
|
189
|
+
const id = Number(req.params.id);
|
|
190
|
+
if (Number.isNaN(id)) {
|
|
191
|
+
apiResponse(res, null, 'Invalid id', 400);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const options = this.getRepoOptions(req);
|
|
195
|
+
const before = this.auditEnabled
|
|
196
|
+
? await this.repository.findById(id, options)
|
|
197
|
+
: null;
|
|
198
|
+
await this.validateIfResourceExists(id, options);
|
|
199
|
+
// Lifecycle hook: beforeDelete
|
|
200
|
+
if (this.hooks.beforeDelete) {
|
|
201
|
+
await this.hooks.beforeDelete(req, id);
|
|
202
|
+
}
|
|
203
|
+
await this.repository.delete(id, options);
|
|
204
|
+
// Lifecycle hook: afterDelete
|
|
205
|
+
if (this.hooks.afterDelete) {
|
|
206
|
+
await this.hooks.afterDelete(req, id);
|
|
207
|
+
}
|
|
208
|
+
if (this.auditEnabled && this.auditSvc) {
|
|
209
|
+
await this.auditSvc.log({
|
|
210
|
+
action: 'DELETE',
|
|
211
|
+
entity: this.entity,
|
|
212
|
+
entityId: id,
|
|
213
|
+
before,
|
|
214
|
+
metadata: { source: 'generic-controller', softDelete: true },
|
|
215
|
+
options,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
apiResponse(res, null, undefined, 204);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
this.errorHandlerService.genericErrorHandler({
|
|
222
|
+
error: error,
|
|
223
|
+
res,
|
|
224
|
+
next,
|
|
225
|
+
entity: this.entity,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async validateIfResourceExists(id, options) {
|
|
230
|
+
const item = await this.repository.findById(id, options);
|
|
231
|
+
if (!item)
|
|
232
|
+
throw new Error(ErrorMessages.RESOURCE_NOT_FOUND.message);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Método genérico para ejecutar operaciones con auditoría automática
|
|
236
|
+
*/
|
|
237
|
+
async executeWithAudit(req, res, next, operation, action, successMessage, statusCode = 200) {
|
|
238
|
+
try {
|
|
239
|
+
const id = Number(req.params.id);
|
|
240
|
+
if (Number.isNaN(id)) {
|
|
241
|
+
apiResponse(res, null, 'Invalid id', 400);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const options = this.getRepoOptions(req);
|
|
245
|
+
const before = this.auditEnabled
|
|
246
|
+
? await this.repository.findById(id, options)
|
|
247
|
+
: null;
|
|
248
|
+
if (!before && (action === 'UPDATE' || action === 'DELETE')) {
|
|
249
|
+
throw new Error(ErrorMessages.RESOURCE_NOT_FOUND.message);
|
|
250
|
+
}
|
|
251
|
+
await operation(id, options);
|
|
252
|
+
const after = this.auditEnabled
|
|
253
|
+
? await this.repository.findById(id, options)
|
|
254
|
+
: null;
|
|
255
|
+
if (this.auditEnabled && this.auditSvc) {
|
|
256
|
+
await this.auditSvc.log({
|
|
257
|
+
action,
|
|
258
|
+
entity: this.entity,
|
|
259
|
+
entityId: id,
|
|
260
|
+
before,
|
|
261
|
+
after,
|
|
262
|
+
metadata: { source: 'generic-controller' },
|
|
263
|
+
options,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
apiResponse(res, null, successMessage ??
|
|
267
|
+
`${this.entity} ${action.toLocaleLowerCase()} successfully`, statusCode);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
this.errorHandlerService.genericErrorHandler({
|
|
271
|
+
error: error,
|
|
272
|
+
res,
|
|
273
|
+
next,
|
|
274
|
+
entity: this.entity,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=generic.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic.controller.js","sourceRoot":"","sources":["../../src/controllers/generic.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class AppError extends Error {
|
|
2
|
+
readonly statusCode: number;
|
|
3
|
+
constructor(message: string, statusCode: number);
|
|
4
|
+
}
|
|
5
|
+
/** 409 Conflict — el recurso ya existe o el slot está ocupado */
|
|
6
|
+
export declare class ConflictError extends AppError {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
/** 400 Bad Request — regla de negocio inválida */
|
|
10
|
+
export declare class BadRequestError extends AppError {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/** 404 Not Found */
|
|
14
|
+
export declare class NotFoundError extends AppError {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=app-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-errors.d.ts","sourceRoot":"","sources":["../../src/errors/app-errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;aAGf,UAAU,EAAE,MAAM;gBADlC,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM;CAMrC;AAED,iEAAiE;AACjE,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM;CAG5B;AAED,kDAAkD;AAClD,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM;CAG5B;AAED,oBAAoB;AACpB,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM;CAG5B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export class AppError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
constructor(message, statusCode) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.statusCode = statusCode;
|
|
6
|
+
this.name = this.constructor.name;
|
|
7
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** 409 Conflict — el recurso ya existe o el slot está ocupado */
|
|
11
|
+
export class ConflictError extends AppError {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message, 409);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** 400 Bad Request — regla de negocio inválida */
|
|
17
|
+
export class BadRequestError extends AppError {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message, 400);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** 404 Not Found */
|
|
23
|
+
export class NotFoundError extends AppError {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message, 404);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=app-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-errors.js","sourceRoot":"","sources":["../../src/errors/app-errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IAFlB,YACE,OAAe,EACC,UAAkB;QAElC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,iEAAiE;AACjE,MAAM,OAAO,aAAc,SAAQ,QAAQ;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACtB,CAAC;CACF;AAED,kDAAkD;AAClD,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACtB,CAAC;CACF;AAED,oBAAoB;AACpB,MAAM,OAAO,aAAc,SAAQ,QAAQ;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACtB,CAAC;CACF"}
|