@koalarx/nest 1.19.0 → 3.0.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/CHANGELOG.md +15 -0
- package/package.json +5 -37
- package/src/core/backgroud-services/cron-service/cron-job.handler.base.ts +66 -0
- package/src/core/backgroud-services/cron-service/cron-job.handler.spec.ts +38 -0
- package/src/core/backgroud-services/event-service/event-class.ts +5 -0
- package/src/core/backgroud-services/event-service/event-handler.base.ts +17 -0
- package/src/core/backgroud-services/event-service/event-is-trigger.ts +3 -0
- package/src/core/backgroud-services/event-service/event-job.ts +28 -0
- package/src/core/backgroud-services/event-service/event-queue.spec.ts +47 -0
- package/src/core/backgroud-services/event-service/event-queue.ts +107 -0
- package/src/core/constants/query-params.ts +7 -0
- package/src/core/controllers/base.controller.ts +9 -0
- package/src/core/controllers/controller.decorator.ts +10 -0
- package/src/core/controllers/created-registre-response.base.ts +17 -0
- package/src/core/controllers/list-response.base.ts +8 -0
- package/src/core/controllers/pagination.request.ts +41 -0
- package/src/core/controllers/router-config.base.ts +14 -0
- package/src/core/controllers/schemas/boolean.schema.ts +10 -0
- package/src/core/controllers/schemas/document-number.schema.ts +23 -0
- package/src/core/controllers/schemas/email.schema.ts +13 -0
- package/src/core/controllers/schemas/list-query.schema.ts +17 -0
- package/src/core/controllers/schemas/native-enum.schema.ts +34 -0
- package/src/core/controllers/schemas/set-mask-document-number.schema.ts +13 -0
- package/src/core/database/entity.base.ts +95 -0
- package/src/core/database/entity.decorator.spec.ts +71 -0
- package/src/core/database/entity.decorator.ts +39 -0
- package/src/core/database/prisma-client-with-custom-transaction.interface.ts +13 -0
- package/src/core/database/prisma-resolver.ts +99 -0
- package/src/core/database/prisma-transactional-client.ts +43 -0
- package/src/core/database/prisma.service.ts +136 -0
- package/src/core/database/repository.base.ts +548 -0
- package/src/core/dtos/pagination.dto.ts +35 -0
- package/src/core/errors/bad-request.error.ts +8 -0
- package/src/core/errors/conflict.error.ts +7 -0
- package/src/core/errors/error.base.ts +5 -0
- package/src/core/errors/no-content.error.ts +8 -0
- package/src/core/errors/not-allowed.error.ts +8 -0
- package/src/core/errors/resource-not-found.error.ts +8 -0
- package/{core/errors/use-case-error.d.ts → src/core/errors/use-case-error.ts} +1 -1
- package/src/core/errors/user-already-exist.error.ts +7 -0
- package/src/core/errors/wrong-credentials.error.ts +7 -0
- package/src/core/health-check/health-check.controller.ts +13 -0
- package/src/core/health-check/health-check.module.ts +7 -0
- package/src/core/index.ts +56 -0
- package/src/core/koala-app.ts +379 -0
- package/src/core/koala-global-vars.ts +8 -0
- package/src/core/koala-nest-database.module.ts +65 -0
- package/src/core/koala-nest-http.module.ts +44 -0
- package/src/core/koala-nest.module.ts +67 -0
- package/src/core/mapping/auto-mapping-class-context.ts +28 -0
- package/src/core/mapping/auto-mapping-context.ts +26 -0
- package/src/core/mapping/auto-mapping-list.ts +154 -0
- package/src/core/mapping/auto-mapping-profile.ts +3 -0
- package/src/core/mapping/auto-mapping.decorator.ts +54 -0
- package/src/core/mapping/auto-mapping.module.ts +17 -0
- package/src/core/mapping/auto-mapping.service.ts +187 -0
- package/src/core/mapping/create-map.ts +11 -0
- package/src/core/mapping/for-member.ts +16 -0
- package/src/core/request-overflow/request-handler.base.ts +8 -0
- package/src/core/request-overflow/request-result.spec.ts +23 -0
- package/src/core/request-overflow/request-result.ts +41 -0
- package/src/core/request-overflow/request-validator.base.ts +33 -0
- package/src/core/security/strategies/api-key.strategy.ts +45 -0
- package/src/core/utils/assing-object.ts +9 -0
- package/src/core/utils/env.config.ts +17 -0
- package/src/core/utils/filter-request-params.ts +23 -0
- package/src/core/utils/find-on-list.ts +18 -0
- package/src/core/utils/get-type-by-prop.ts +9 -0
- package/src/core/utils/instanciate-class-with-dependencies-injection.ts +12 -0
- package/src/core/utils/interfaces/icomparable.ts +6 -0
- package/src/core/utils/list.spec.ts +81 -0
- package/src/core/utils/list.ts +223 -0
- package/src/core/utils/promise-all.ts +24 -0
- package/src/core/utils/set-mask-document-number.ts +13 -0
- package/src/core/validators/file-validator.ts +113 -0
- package/src/decorators/api-exclude-endpoint-diff-develop.decorator.ts +15 -0
- package/src/decorators/api-property-enum.decorator.ts +58 -0
- package/src/decorators/api-property-only-develop.decorator.ts +6 -0
- package/src/decorators/cookies.decorator.ts +8 -0
- package/src/decorators/is-public.decorator.ts +5 -0
- package/src/decorators/upload.decorator.ts +31 -0
- package/src/env/env.module.ts +8 -0
- package/src/env/env.service.ts +12 -0
- package/src/env/env.ts +14 -0
- package/src/filters/domain-errors.filter.ts +97 -0
- package/src/filters/global-exception.filter.ts +60 -0
- package/src/filters/prisma-validation-exception.filter.ts +73 -0
- package/src/filters/zod-errors.filter.ts +48 -0
- package/src/services/logging/ilogging.service.ts +17 -0
- package/src/services/logging/logging.service.ts +10 -0
- package/src/services/redis/iredis.service.ts +11 -0
- package/src/services/redis/redis.service.ts +70 -0
- package/src/services/redlock/ired-lock.service.ts +4 -0
- package/src/services/redlock/red-lock.service.ts +36 -0
- package/src/test/koala-app-test-dependencies.ts +15 -0
- package/src/test/koala-app-test.ts +103 -0
- package/src/test/repositories/in-memory-base.repository.ts +90 -0
- package/src/test/services/fake-logging.service.ts +7 -0
- package/src/test/services/fake-red-lock.service.ts +11 -0
- package/src/test/utils/create-e2e-database.ts +55 -0
- package/src/test/utils/drop-e2e-database.ts +36 -0
- package/src/test/utils/wait-for.ts +31 -0
- package/tsconfig.lib.json +11 -0
- package/LICENSE +0 -21
- package/README.md +0 -499
- package/core/backgroud-services/cron-service/cron-job.handler.base.d.ts +0 -16
- package/core/backgroud-services/cron-service/cron-job.handler.base.js +0 -49
- package/core/backgroud-services/event-service/event-class.d.ts +0 -5
- package/core/backgroud-services/event-service/event-class.js +0 -11
- package/core/backgroud-services/event-service/event-handler.base.d.ts +0 -8
- package/core/backgroud-services/event-service/event-handler.base.js +0 -14
- package/core/backgroud-services/event-service/event-is-trigger.d.ts +0 -3
- package/core/backgroud-services/event-service/event-is-trigger.js +0 -7
- package/core/backgroud-services/event-service/event-job.d.ts +0 -13
- package/core/backgroud-services/event-service/event-job.js +0 -21
- package/core/backgroud-services/event-service/event-queue.d.ts +0 -17
- package/core/backgroud-services/event-service/event-queue.js +0 -62
- package/core/constants/query-params.d.ts +0 -6
- package/core/constants/query-params.js +0 -8
- package/core/controllers/base.controller.d.ts +0 -4
- package/core/controllers/base.controller.js +0 -6
- package/core/controllers/controller.decorator.d.ts +0 -2
- package/core/controllers/controller.decorator.js +0 -11
- package/core/controllers/created-registre-response.base.d.ts +0 -10
- package/core/controllers/created-registre-response.base.js +0 -35
- package/core/controllers/list-response.base.d.ts +0 -4
- package/core/controllers/list-response.base.js +0 -21
- package/core/controllers/pagination.request.d.ts +0 -10
- package/core/controllers/pagination.request.js +0 -56
- package/core/controllers/router-config.base.d.ts +0 -7
- package/core/controllers/router-config.base.js +0 -18
- package/core/controllers/schemas/boolean.schema.d.ts +0 -2
- package/core/controllers/schemas/boolean.schema.js +0 -12
- package/core/controllers/schemas/document-number.schema.d.ts +0 -1
- package/core/controllers/schemas/document-number.schema.js +0 -26
- package/core/controllers/schemas/email.schema.d.ts +0 -1
- package/core/controllers/schemas/email.schema.js +0 -13
- package/core/controllers/schemas/list-query.schema.d.ts +0 -17
- package/core/controllers/schemas/list-query.schema.js +0 -19
- package/core/controllers/schemas/native-enum.schema.d.ts +0 -7
- package/core/controllers/schemas/native-enum.schema.js +0 -28
- package/core/controllers/schemas/set-mask-document-number.schema.d.ts +0 -1
- package/core/controllers/schemas/set-mask-document-number.schema.js +0 -13
- package/core/database/entity.base.d.ts +0 -20
- package/core/database/entity.base.js +0 -71
- package/core/database/entity.decorator.d.ts +0 -13
- package/core/database/entity.decorator.js +0 -23
- package/core/database/prisma-client-with-custom-transaction.interface.d.ts +0 -8
- package/core/database/prisma-client-with-custom-transaction.interface.js +0 -2
- package/core/database/prisma-resolver.d.ts +0 -2
- package/core/database/prisma-resolver.js +0 -74
- package/core/database/prisma-transactional-client.d.ts +0 -11
- package/core/database/prisma-transactional-client.js +0 -25
- package/core/database/prisma.service.d.ts +0 -24
- package/core/database/prisma.service.js +0 -104
- package/core/database/repository.base.d.ts +0 -44
- package/core/database/repository.base.js +0 -360
- package/core/dtos/pagination.dto.d.ts +0 -9
- package/core/dtos/pagination.dto.js +0 -49
- package/core/errors/bad-request.error.d.ts +0 -5
- package/core/errors/bad-request.error.js +0 -10
- package/core/errors/conflict.error.d.ts +0 -4
- package/core/errors/conflict.error.js +0 -10
- package/core/errors/error.base.d.ts +0 -4
- package/core/errors/error.base.js +0 -11
- package/core/errors/no-content.error.d.ts +0 -5
- package/core/errors/no-content.error.js +0 -10
- package/core/errors/not-allowed.error.d.ts +0 -5
- package/core/errors/not-allowed.error.js +0 -10
- package/core/errors/resource-not-found.error.d.ts +0 -5
- package/core/errors/resource-not-found.error.js +0 -10
- package/core/errors/use-case-error.js +0 -2
- package/core/errors/user-already-exist.error.d.ts +0 -4
- package/core/errors/user-already-exist.error.js +0 -10
- package/core/errors/wrong-credentials.error.d.ts +0 -4
- package/core/errors/wrong-credentials.error.js +0 -10
- package/core/health-check/health-check.controller.d.ts +0 -5
- package/core/health-check/health-check.controller.js +0 -32
- package/core/health-check/health-check.module.d.ts +0 -2
- package/core/health-check/health-check.module.js +0 -19
- package/core/index.d.ts +0 -18
- package/core/index.js +0 -7
- package/core/koala-app.d.ts +0 -64
- package/core/koala-app.js +0 -252
- package/core/koala-global-vars.d.ts +0 -7
- package/core/koala-global-vars.js +0 -9
- package/core/koala-nest-database.module.d.ts +0 -16
- package/core/koala-nest-database.module.js +0 -52
- package/core/koala-nest-http.module.d.ts +0 -13
- package/core/koala-nest-http.module.js +0 -37
- package/core/koala-nest.module.d.ts +0 -17
- package/core/koala-nest.module.js +0 -66
- package/core/mapping/auto-mapping-class-context.d.ts +0 -16
- package/core/mapping/auto-mapping-class-context.js +0 -18
- package/core/mapping/auto-mapping-context.d.ts +0 -11
- package/core/mapping/auto-mapping-context.js +0 -24
- package/core/mapping/auto-mapping-list.d.ts +0 -27
- package/core/mapping/auto-mapping-list.js +0 -94
- package/core/mapping/auto-mapping-profile.d.ts +0 -3
- package/core/mapping/auto-mapping-profile.js +0 -6
- package/core/mapping/auto-mapping.decorator.d.ts +0 -9
- package/core/mapping/auto-mapping.decorator.js +0 -27
- package/core/mapping/auto-mapping.module.d.ts +0 -5
- package/core/mapping/auto-mapping.module.js +0 -29
- package/core/mapping/auto-mapping.service.d.ts +0 -14
- package/core/mapping/auto-mapping.service.js +0 -140
- package/core/mapping/create-map.d.ts +0 -3
- package/core/mapping/create-map.js +0 -7
- package/core/mapping/for-member.d.ts +0 -5
- package/core/mapping/for-member.js +0 -8
- package/core/request-overflow/request-handler.base.d.ts +0 -4
- package/core/request-overflow/request-handler.base.js +0 -6
- package/core/request-overflow/request-result.d.ts +0 -15
- package/core/request-overflow/request-result.js +0 -37
- package/core/request-overflow/request-validator.base.d.ts +0 -7
- package/core/request-overflow/request-validator.base.js +0 -26
- package/core/security/strategies/api-key.strategy.d.ts +0 -16
- package/core/security/strategies/api-key.strategy.js +0 -31
- package/core/utils/assing-object.d.ts +0 -5
- package/core/utils/assing-object.js +0 -6
- package/core/utils/env.config.d.ts +0 -6
- package/core/utils/env.config.js +0 -18
- package/core/utils/filter-request-params.d.ts +0 -13
- package/core/utils/filter-request-params.js +0 -22
- package/core/utils/find-on-list.d.ts +0 -2
- package/core/utils/find-on-list.js +0 -13
- package/core/utils/get-type-by-prop.d.ts +0 -2
- package/core/utils/get-type-by-prop.js +0 -11
- package/core/utils/instanciate-class-with-dependencies-injection.d.ts +0 -2
- package/core/utils/instanciate-class-with-dependencies-injection.js +0 -10
- package/core/utils/interfaces/icomparable.d.ts +0 -5
- package/core/utils/interfaces/icomparable.js +0 -6
- package/core/utils/list.d.ts +0 -39
- package/core/utils/list.js +0 -168
- package/core/utils/promise-all.d.ts +0 -7
- package/core/utils/promise-all.js +0 -19
- package/core/utils/set-mask-document-number.d.ts +0 -1
- package/core/utils/set-mask-document-number.js +0 -13
- package/core/validators/file-validator.d.ts +0 -27
- package/core/validators/file-validator.js +0 -94
- package/decorators/api-exclude-endpoint-diff-develop.decorator.d.ts +0 -1
- package/decorators/api-exclude-endpoint-diff-develop.decorator.js +0 -9
- package/decorators/api-property-enum.decorator.d.ts +0 -8
- package/decorators/api-property-enum.decorator.js +0 -21
- package/decorators/api-property-only-develop.decorator.d.ts +0 -2
- package/decorators/api-property-only-develop.decorator.js +0 -9
- package/decorators/cookies.decorator.d.ts +0 -1
- package/decorators/cookies.decorator.js +0 -8
- package/decorators/is-public.decorator.d.ts +0 -2
- package/decorators/is-public.decorator.js +0 -7
- package/decorators/upload.decorator.d.ts +0 -1
- package/decorators/upload.decorator.js +0 -18
- package/docs/00-cli-reference.md +0 -201
- package/docs/01-guia-instalacao.md +0 -113
- package/docs/02-configuracao-inicial.md +0 -176
- package/docs/04-tratamento-erros.md +0 -303
- package/docs/05-features-avancadas.md +0 -969
- package/docs/06-decoradores.md +0 -220
- package/docs/07-guia-bun.md +0 -176
- package/docs/08-prisma-client.md +0 -487
- package/docs/09-mcp-vscode-extension.md +0 -437
- package/docs/EXAMPLE.md +0 -1671
- package/docs/README.md +0 -59
- package/env/env.d.ts +0 -25
- package/env/env.js +0 -14
- package/env/env.module.d.ts +0 -2
- package/env/env.module.js +0 -20
- package/env/env.service.d.ts +0 -7
- package/env/env.service.js +0 -28
- package/filters/domain-errors.filter.d.ts +0 -18
- package/filters/domain-errors.filter.js +0 -92
- package/filters/global-exception.filter.d.ts +0 -8
- package/filters/global-exception.filter.js +0 -68
- package/filters/prisma-validation-exception.filter.d.ts +0 -10
- package/filters/prisma-validation-exception.filter.js +0 -82
- package/filters/zod-errors.filter.d.ts +0 -9
- package/filters/zod-errors.filter.js +0 -60
- package/mcp-server/mcp.json.example +0 -27
- package/mcp-server/server.d.ts +0 -2
- package/mcp-server/server.d.ts.map +0 -1
- package/mcp-server/server.js +0 -248
- package/mcp-server/server.js.map +0 -1
- package/services/logging/ilogging.service.d.ts +0 -16
- package/services/logging/ilogging.service.js +0 -6
- package/services/logging/logging.service.d.ts +0 -4
- package/services/logging/logging.service.js +0 -20
- package/services/redis/iredis.service.d.ts +0 -6
- package/services/redis/iredis.service.js +0 -6
- package/services/redis/redis.service.d.ts +0 -14
- package/services/redis/redis.service.js +0 -65
- package/services/redlock/ired-lock.service.d.ts +0 -4
- package/services/redlock/ired-lock.service.js +0 -6
- package/services/redlock/red-lock.service.d.ts +0 -9
- package/services/redlock/red-lock.service.js +0 -46
- package/test/koala-app-test-dependencies.d.ts +0 -10
- package/test/koala-app-test-dependencies.js +0 -13
- package/test/koala-app-test.d.ts +0 -22
- package/test/koala-app-test.js +0 -77
- package/test/repositories/in-memory-base.repository.d.ts +0 -17
- package/test/repositories/in-memory-base.repository.js +0 -65
- package/test/services/fake-logging.service.d.ts +0 -4
- package/test/services/fake-logging.service.js +0 -9
- package/test/services/fake-red-lock.service.d.ts +0 -5
- package/test/services/fake-red-lock.service.js +0 -11
- package/test/utils/create-e2e-database.d.ts +0 -2
- package/test/utils/create-e2e-database.js +0 -47
- package/test/utils/drop-e2e-database.d.ts +0 -2
- package/test/utils/drop-e2e-database.js +0 -33
- package/test/utils/wait-for.d.ts +0 -1
- package/test/utils/wait-for.js +0 -21
- package/tsconfig.lib.tsbuildinfo +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { KlArray, KlDate, KlTime } from '@koalarx/utils'
|
|
2
|
+
import { Type } from '@nestjs/common'
|
|
3
|
+
import { Overwrite } from '..'
|
|
4
|
+
import { AutoMappingList } from '../mapping/auto-mapping-list'
|
|
5
|
+
import { IComparable, IComparableId } from '../utils/interfaces/icomparable'
|
|
6
|
+
import { List } from '../utils/list'
|
|
7
|
+
|
|
8
|
+
export enum EntityActionType {
|
|
9
|
+
create = 1,
|
|
10
|
+
update,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type EntityProps<T extends IComparable<T>> = Overwrite<
|
|
14
|
+
Omit<
|
|
15
|
+
{
|
|
16
|
+
[K in keyof T as T[K] extends Function ? never : K]: T[K]
|
|
17
|
+
},
|
|
18
|
+
'_id' | '_action'
|
|
19
|
+
>,
|
|
20
|
+
{ id?: T extends { id: infer U } ? U : never }
|
|
21
|
+
>
|
|
22
|
+
|
|
23
|
+
export abstract class EntityBase<T extends IComparable<T>>
|
|
24
|
+
implements IComparable<T>
|
|
25
|
+
{
|
|
26
|
+
_id: IComparableId
|
|
27
|
+
_action: EntityActionType = EntityActionType.create
|
|
28
|
+
|
|
29
|
+
constructor(props?: EntityProps<T>) {
|
|
30
|
+
if (props) {
|
|
31
|
+
this.automap(props)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
automap(props?: EntityProps<T>) {
|
|
36
|
+
if (props) {
|
|
37
|
+
for (const key of Object.keys(props)) {
|
|
38
|
+
if (props[key] === undefined) {
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const propDefinitions = AutoMappingList.getPropDefinitions(
|
|
43
|
+
this.constructor.prototype.constructor,
|
|
44
|
+
key,
|
|
45
|
+
)
|
|
46
|
+
const EntityOnPropKey = AutoMappingList.getSourceByName(
|
|
47
|
+
propDefinitions?.type ?? '',
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if (Array.isArray(props[key]) && this[key] instanceof List) {
|
|
51
|
+
let value: any = props[key]
|
|
52
|
+
|
|
53
|
+
if (this[key].entityType) {
|
|
54
|
+
value = value.map((item) => {
|
|
55
|
+
const entity = new (this[key].entityType as Type<any>)()
|
|
56
|
+
entity._action = this._action
|
|
57
|
+
entity.automap(item)
|
|
58
|
+
|
|
59
|
+
return entity
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this[key].setList(value)
|
|
64
|
+
} else if (
|
|
65
|
+
propDefinitions?.type === 'KlArray' &&
|
|
66
|
+
(props[key] instanceof Array || Array.isArray(props[key]))
|
|
67
|
+
) {
|
|
68
|
+
this[key] = new KlArray(props[key])
|
|
69
|
+
} else if (propDefinitions?.type === 'KlDate' && props[key] instanceof Date) {
|
|
70
|
+
this[key] = new KlDate(props[key])
|
|
71
|
+
} else if (propDefinitions?.type === 'KlTime' && props[key] instanceof Date) {
|
|
72
|
+
this[key] = new KlTime(props[key].getHours(), props[key].getMinutes(), props[key].getSeconds(), props[key].getMilliseconds())
|
|
73
|
+
} else if (EntityOnPropKey) {
|
|
74
|
+
if (props[key]) {
|
|
75
|
+
const entity = new EntityOnPropKey()
|
|
76
|
+
entity._action = this._action
|
|
77
|
+
entity.automap(props[key])
|
|
78
|
+
|
|
79
|
+
this[key] = entity
|
|
80
|
+
}
|
|
81
|
+
} else if (propDefinitions) {
|
|
82
|
+
if (key === 'id') {
|
|
83
|
+
this._id = props[key] as IComparableId
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this[key] = props[key]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public equals(obj: EntityBase<T>): boolean {
|
|
93
|
+
return obj._id === this._id
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker'
|
|
2
|
+
import { AutoMap } from '../mapping/auto-mapping.decorator'
|
|
3
|
+
import { List } from '../utils/list'
|
|
4
|
+
import { EntityBase } from './entity.base'
|
|
5
|
+
import { Entity } from './entity.decorator'
|
|
6
|
+
|
|
7
|
+
@Entity()
|
|
8
|
+
export class PersonAddress extends EntityBase<PersonAddress> {
|
|
9
|
+
@AutoMap()
|
|
10
|
+
id: number
|
|
11
|
+
|
|
12
|
+
@AutoMap()
|
|
13
|
+
address: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Entity()
|
|
17
|
+
export class PersonPhone extends EntityBase<PersonPhone> {
|
|
18
|
+
@AutoMap()
|
|
19
|
+
id: number
|
|
20
|
+
|
|
21
|
+
@AutoMap()
|
|
22
|
+
phone: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Entity()
|
|
26
|
+
export class Person extends EntityBase<Person> {
|
|
27
|
+
@AutoMap()
|
|
28
|
+
id: number
|
|
29
|
+
|
|
30
|
+
@AutoMap()
|
|
31
|
+
name: string
|
|
32
|
+
|
|
33
|
+
@AutoMap({ type: List })
|
|
34
|
+
phones = new List(PersonPhone)
|
|
35
|
+
|
|
36
|
+
@AutoMap({ type: PersonAddress })
|
|
37
|
+
address: PersonAddress
|
|
38
|
+
|
|
39
|
+
@AutoMap()
|
|
40
|
+
active: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe('Entity decorator', () => {
|
|
44
|
+
it('should create an instance of Person', () => {
|
|
45
|
+
const person = new Person({
|
|
46
|
+
name: faker.person.fullName(),
|
|
47
|
+
phones: [
|
|
48
|
+
{ phone: faker.phone.number() },
|
|
49
|
+
{ phone: faker.phone.number() },
|
|
50
|
+
],
|
|
51
|
+
address: { address: faker.location.streetAddress() },
|
|
52
|
+
active: true,
|
|
53
|
+
} as any)
|
|
54
|
+
|
|
55
|
+
expect(person).toBeInstanceOf(Person)
|
|
56
|
+
expect(person).toBeInstanceOf(EntityBase)
|
|
57
|
+
expect(person.constructor.name).toBe('Person')
|
|
58
|
+
|
|
59
|
+
expect(person.phones).toBeInstanceOf(List)
|
|
60
|
+
expect(person.phones.toArray()[0]).toBeInstanceOf(PersonPhone)
|
|
61
|
+
expect(person.phones.toArray()[1]).toBeInstanceOf(PersonPhone)
|
|
62
|
+
expect(person.phones.toArray()[0].phone).toBeDefined()
|
|
63
|
+
expect(person.phones.toArray()[1].phone).toBeDefined()
|
|
64
|
+
|
|
65
|
+
expect(person.address.constructor.name).toBe(PersonAddress.name)
|
|
66
|
+
expect(person.address.address).toBeDefined()
|
|
67
|
+
|
|
68
|
+
expect(person.name).toBeDefined()
|
|
69
|
+
expect(person.active).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EntityBase } from './entity.base'
|
|
2
|
+
|
|
3
|
+
type EntityProps<T> = Omit<
|
|
4
|
+
{
|
|
5
|
+
[K in keyof T as T[K] extends Function ? never : K]: T[K]
|
|
6
|
+
},
|
|
7
|
+
'_id' | '_action'
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
export function Entity<T extends new (...args: any[]) => EntityBase<any>>(
|
|
11
|
+
id?: keyof EntityProps<InstanceType<T>>,
|
|
12
|
+
) {
|
|
13
|
+
return function (target: T) {
|
|
14
|
+
class NewConstructor extends target {
|
|
15
|
+
constructor(...args: any[]) {
|
|
16
|
+
super(...args) // Chama o construtor original
|
|
17
|
+
|
|
18
|
+
// Chama o método `automap` se ele existir
|
|
19
|
+
if (typeof this.automap === 'function') {
|
|
20
|
+
this.automap(args[0])
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Copia o protótipo e propriedades estáticas para o novo construtor
|
|
26
|
+
Object.setPrototypeOf(NewConstructor.prototype, target.prototype)
|
|
27
|
+
Object.setPrototypeOf(NewConstructor, target)
|
|
28
|
+
|
|
29
|
+
// Define o nome do novo construtor para corresponder ao nome da classe original
|
|
30
|
+
Object.defineProperty(NewConstructor, 'name', {
|
|
31
|
+
value: target.name,
|
|
32
|
+
writable: false,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
Reflect.defineMetadata('entity:id', id, NewConstructor.prototype)
|
|
36
|
+
|
|
37
|
+
return NewConstructor
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Prisma } from 'prisma/generated/client'
|
|
2
|
+
|
|
3
|
+
export interface PrismaClientWithCustomTransaction
|
|
4
|
+
extends Readonly<Prisma.TransactionClient> {
|
|
5
|
+
withTransaction<F>(
|
|
6
|
+
fn: (prisma: Prisma.TransactionClient) => Promise<F>,
|
|
7
|
+
options?: {
|
|
8
|
+
maxWait?: number | undefined
|
|
9
|
+
timeout?: number | undefined
|
|
10
|
+
isolationLevel?: Prisma.TransactionIsolationLevel | undefined
|
|
11
|
+
},
|
|
12
|
+
): Promise<F>
|
|
13
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolver automático para o Prisma Client do projeto consumidor
|
|
3
|
+
* Tenta múltiplos caminhos para encontrar o cliente gerado
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path'
|
|
6
|
+
import * as fs from 'fs'
|
|
7
|
+
|
|
8
|
+
let cachedPrismaClient: any = null
|
|
9
|
+
|
|
10
|
+
function findPrismaClient(): string | null {
|
|
11
|
+
// Lista de caminhos possíveis onde o Prisma pode estar
|
|
12
|
+
const possiblePaths = [
|
|
13
|
+
path.join(process.cwd(), 'prisma/generated/client.js'),
|
|
14
|
+
path.join(__dirname, '../../../../../prisma/generated/client.js'),
|
|
15
|
+
path.join(process.cwd(), 'prisma/generated/client.ts'),
|
|
16
|
+
path.join(__dirname, '../../../../../prisma/generated/client.ts'),
|
|
17
|
+
...(require.main?.filename
|
|
18
|
+
? [
|
|
19
|
+
path.join(
|
|
20
|
+
path.dirname(require.main.filename),
|
|
21
|
+
'../prisma/generated/client.js',
|
|
22
|
+
),
|
|
23
|
+
path.join(
|
|
24
|
+
path.dirname(require.main.filename),
|
|
25
|
+
'../prisma/generated/client.ts',
|
|
26
|
+
),
|
|
27
|
+
]
|
|
28
|
+
: []),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
for (const prismaPath of possiblePaths) {
|
|
32
|
+
if (fs.existsSync(prismaPath)) {
|
|
33
|
+
return prismaPath
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function resolvePrismaClient() {
|
|
41
|
+
if (cachedPrismaClient) {
|
|
42
|
+
return cachedPrismaClient
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const prismaPath = findPrismaClient()
|
|
46
|
+
|
|
47
|
+
if (!prismaPath) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`
|
|
50
|
+
Não foi possível carregar o Prisma Client automaticamente.
|
|
51
|
+
|
|
52
|
+
Certifique-se de que você:
|
|
53
|
+
1. Executou 'bunx prisma generate' no seu projeto
|
|
54
|
+
2. Tem a pasta 'prisma/generated/client' no seu projeto
|
|
55
|
+
3. A lib @koalarx/nest está instalada como dependência
|
|
56
|
+
|
|
57
|
+
Se o problema persistir, você pode registrar manualmente o Prisma Client:
|
|
58
|
+
|
|
59
|
+
import { setPrismaClient } from '@koalarx/nest'
|
|
60
|
+
import { PrismaClient } from './prisma/generated/client'
|
|
61
|
+
|
|
62
|
+
setPrismaClient(PrismaClient)
|
|
63
|
+
`.trim(),
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
// Carrega dinamicamente o módulo
|
|
69
|
+
const module = await import(prismaPath)
|
|
70
|
+
// Extrai PrismaClient do módulo (pode ser default export ou named export)
|
|
71
|
+
cachedPrismaClient = module.PrismaClient || module.default || module
|
|
72
|
+
return cachedPrismaClient
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`
|
|
76
|
+
Erro ao carregar o Prisma Client de ${prismaPath}:
|
|
77
|
+
${error instanceof Error ? error.message : String(error)}
|
|
78
|
+
|
|
79
|
+
Certifique-se de que 'bunx prisma generate' foi executado com sucesso.
|
|
80
|
+
`.trim(),
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Variável global para registro manual
|
|
86
|
+
let manualPrismaClient: any = null
|
|
87
|
+
|
|
88
|
+
export function setPrismaClient(prismaClientClass: any) {
|
|
89
|
+
manualPrismaClient = prismaClientClass
|
|
90
|
+
cachedPrismaClient = null // Limpa cache
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getPrismaClientClass() {
|
|
94
|
+
if (manualPrismaClient) {
|
|
95
|
+
return manualPrismaClient
|
|
96
|
+
}
|
|
97
|
+
// Retorna uma função que resolve o cliente quando necessário
|
|
98
|
+
return resolvePrismaClient()
|
|
99
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Prisma } from 'prisma/generated/client'
|
|
2
|
+
|
|
3
|
+
export abstract class PrismaTransactionalClient {
|
|
4
|
+
[key: symbol]: any
|
|
5
|
+
|
|
6
|
+
constructor(
|
|
7
|
+
protected readonly transactionalClient: Prisma.TransactionClient,
|
|
8
|
+
) {}
|
|
9
|
+
|
|
10
|
+
async withTransaction<F>(
|
|
11
|
+
fn: (prisma: Prisma.TransactionClient) => Promise<F>,
|
|
12
|
+
): Promise<F> {
|
|
13
|
+
return await fn(this.transactionalClient)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$executeRaw(
|
|
17
|
+
query: TemplateStringsArray | Prisma.Sql,
|
|
18
|
+
...values: any[]
|
|
19
|
+
): Prisma.PrismaPromise<number> {
|
|
20
|
+
return this.transactionalClient.$executeRaw(query, ...values)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
$executeRawUnsafe(
|
|
24
|
+
query: string,
|
|
25
|
+
...values: any[]
|
|
26
|
+
): Prisma.PrismaPromise<number> {
|
|
27
|
+
return this.transactionalClient.$executeRawUnsafe(query, ...values)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
$queryRaw<T = unknown>(
|
|
31
|
+
query: TemplateStringsArray | Prisma.Sql,
|
|
32
|
+
...values: any[]
|
|
33
|
+
): Prisma.PrismaPromise<T> {
|
|
34
|
+
return this.transactionalClient.$queryRaw(query, ...values)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$queryRawUnsafe<T = unknown>(
|
|
38
|
+
query: string,
|
|
39
|
+
...values: any[]
|
|
40
|
+
): Prisma.PrismaPromise<T> {
|
|
41
|
+
return this.transactionalClient.$queryRawUnsafe(query, ...values)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { EnvService } from '@koalarx/nest/env/env.service'
|
|
2
|
+
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'
|
|
3
|
+
import { PrismaClientWithCustomTransaction } from './prisma-client-with-custom-transaction.interface'
|
|
4
|
+
import { getPrismaClientClass } from './prisma-resolver'
|
|
5
|
+
import type { Prisma } from 'prisma/generated/client'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configure opções padrão do PrismaClient (ex: adapter).
|
|
9
|
+
* Use isso na sua aplicação antes de inicializar o módulo Nest.
|
|
10
|
+
*/
|
|
11
|
+
let globalPrismaOptions = {} as Prisma.PrismaClientOptions
|
|
12
|
+
|
|
13
|
+
export function setPrismaClientOptions(options: Prisma.PrismaClientOptions) {
|
|
14
|
+
globalPrismaOptions = options
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Wrapper para carregar o PrismaClient dinamicamente
|
|
18
|
+
let PrismaClientClass: any = null
|
|
19
|
+
|
|
20
|
+
async function loadPrismaClient() {
|
|
21
|
+
if (!PrismaClientClass) {
|
|
22
|
+
PrismaClientClass = await getPrismaClientClass()
|
|
23
|
+
}
|
|
24
|
+
return PrismaClientClass
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Injectable()
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
export class PrismaService
|
|
31
|
+
implements OnModuleInit, OnModuleDestroy, PrismaClientWithCustomTransaction
|
|
32
|
+
{
|
|
33
|
+
private prismaInstance: any
|
|
34
|
+
|
|
35
|
+
constructor(private readonly env: EnvService) {
|
|
36
|
+
// Retorna um proxy para permitir acesso transparente às models
|
|
37
|
+
// Isso é necessário porque repository.base.ts tenta acessar this._context[modelName]
|
|
38
|
+
return new Proxy(this, {
|
|
39
|
+
get: (target, prop, receiver) => {
|
|
40
|
+
// Propriedades e métodos da instância têm prioridade
|
|
41
|
+
if (prop in target) {
|
|
42
|
+
const value = Reflect.get(target, prop, receiver)
|
|
43
|
+
if (typeof value === 'function') {
|
|
44
|
+
return value.bind(target)
|
|
45
|
+
}
|
|
46
|
+
return value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Caso a propriedade não exista, tenta acessar no prismaInstance
|
|
50
|
+
// Isso permite acessar models (person, user, etc.) e métodos como $queryRaw
|
|
51
|
+
if (target.prismaInstance && typeof prop === 'string') {
|
|
52
|
+
const value = target.prismaInstance[prop]
|
|
53
|
+
if (typeof value === 'function') {
|
|
54
|
+
return value.bind(target.prismaInstance)
|
|
55
|
+
}
|
|
56
|
+
return value
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Reflect.get(target, prop, receiver)
|
|
60
|
+
},
|
|
61
|
+
}) as any
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async initialize() {
|
|
65
|
+
const PrismaClientType = await loadPrismaClient()
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
this.prismaInstance = new PrismaClientType({
|
|
69
|
+
log: [{ emit: 'event', level: 'query' }],
|
|
70
|
+
...globalPrismaOptions,
|
|
71
|
+
} as Prisma.PrismaClientOptions)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async onModuleInit() {
|
|
75
|
+
await this.initialize()
|
|
76
|
+
if (this.env.get('PRISMA_QUERY_LOG')) {
|
|
77
|
+
this.prismaInstance?.$on?.('query', async (e: any) => {
|
|
78
|
+
console.log(`${e.query} ${e.params}`)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
return this.prismaInstance?.$connect?.()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onModuleDestroy() {
|
|
85
|
+
return this.prismaInstance?.$disconnect?.()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async withTransaction<F>(
|
|
89
|
+
fn: (prisma: Prisma.TransactionClient) => Promise<F>,
|
|
90
|
+
options?: {
|
|
91
|
+
maxWait?: number
|
|
92
|
+
timeout?: number
|
|
93
|
+
isolationLevel?: Prisma.TransactionIsolationLevel
|
|
94
|
+
},
|
|
95
|
+
): Promise<F> {
|
|
96
|
+
return this.prismaInstance?.$transaction?.(
|
|
97
|
+
fn,
|
|
98
|
+
options ?? {
|
|
99
|
+
maxWait: 20000,
|
|
100
|
+
timeout: 20000,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Expõe métodos e properties do PrismaClient dynamicamente
|
|
106
|
+
// Isso permite que o repositório acesse models (person, user, etc.) via Proxy
|
|
107
|
+
[Symbol.toPrimitive]() {
|
|
108
|
+
return this.prismaInstance
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
toString() {
|
|
112
|
+
return '[PrismaService]'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Métodos úteis do PrismaClient
|
|
116
|
+
get $connect() {
|
|
117
|
+
return this.prismaInstance?.$connect?.bind(this.prismaInstance)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
get $disconnect() {
|
|
121
|
+
return this.prismaInstance?.$disconnect?.bind(this.prismaInstance)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get $transaction() {
|
|
125
|
+
return this.prismaInstance?.$transaction?.bind(this.prismaInstance)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get $on() {
|
|
129
|
+
return this.prismaInstance?.$on?.bind(this.prismaInstance)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Proxy transparente para acessar models e qualquer outro property do PrismaClient
|
|
133
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
134
|
+
return this.prismaInstance
|
|
135
|
+
}
|
|
136
|
+
}
|