nestjs-ddd-cli 2.2.0 → 3.2.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 +247 -408
- package/ddd.schema.json +111 -0
- package/dist/commands/aggregate-validator.d.ts +9 -0
- package/dist/commands/aggregate-validator.js +953 -0
- package/dist/commands/aggregate-validator.js.map +1 -0
- package/dist/commands/ai-assist.d.ts +8 -0
- package/dist/commands/ai-assist.js +337 -0
- package/dist/commands/ai-assist.js.map +1 -0
- package/dist/commands/api-contracts.d.ts +9 -0
- package/dist/commands/api-contracts.js +1368 -0
- package/dist/commands/api-contracts.js.map +1 -0
- package/dist/commands/api-docs.d.ts +8 -0
- package/dist/commands/api-docs.js +408 -0
- package/dist/commands/api-docs.js.map +1 -0
- package/dist/commands/api-versioning.d.ts +11 -0
- package/dist/commands/api-versioning.js +643 -0
- package/dist/commands/api-versioning.js.map +1 -0
- package/dist/commands/audit-logging.d.ts +9 -0
- package/dist/commands/audit-logging.js +1129 -0
- package/dist/commands/audit-logging.js.map +1 -0
- package/dist/commands/batch-generate.d.ts +10 -0
- package/dist/commands/batch-generate.js +405 -0
- package/dist/commands/batch-generate.js.map +1 -0
- package/dist/commands/caching-strategies.d.ts +9 -0
- package/dist/commands/caching-strategies.js +874 -0
- package/dist/commands/caching-strategies.js.map +1 -0
- package/dist/commands/code-analyzer.d.ts +42 -0
- package/dist/commands/code-analyzer.js +474 -0
- package/dist/commands/code-analyzer.js.map +1 -0
- package/dist/commands/database-seeding.d.ts +6 -0
- package/dist/commands/database-seeding.js +621 -0
- package/dist/commands/database-seeding.js.map +1 -0
- package/dist/commands/db-optimization.d.ts +7 -0
- package/dist/commands/db-optimization.js +687 -0
- package/dist/commands/db-optimization.js.map +1 -0
- package/dist/commands/dependency-graph.d.ts +6 -0
- package/dist/commands/dependency-graph.js +329 -0
- package/dist/commands/dependency-graph.js.map +1 -0
- package/dist/commands/doctor-enhanced.d.ts +22 -0
- package/dist/commands/doctor-enhanced.js +543 -0
- package/dist/commands/doctor-enhanced.js.map +1 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +151 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/env-manager.d.ts +6 -0
- package/dist/commands/env-manager.js +419 -0
- package/dist/commands/env-manager.js.map +1 -0
- package/dist/commands/event-sourcing-full.d.ts +10 -0
- package/dist/commands/event-sourcing-full.js +1107 -0
- package/dist/commands/event-sourcing-full.js.map +1 -0
- package/dist/commands/feature-flags.d.ts +9 -0
- package/dist/commands/feature-flags.js +824 -0
- package/dist/commands/feature-flags.js.map +1 -0
- package/dist/commands/filter-dsl.d.ts +10 -0
- package/dist/commands/filter-dsl.js +1407 -0
- package/dist/commands/filter-dsl.js.map +1 -0
- package/dist/commands/generate-all.js +485 -32
- package/dist/commands/generate-all.js.map +1 -1
- package/dist/commands/generate-deployment.d.ts +8 -0
- package/dist/commands/generate-deployment.js +746 -0
- package/dist/commands/generate-deployment.js.map +1 -0
- package/dist/commands/generate-domain-service.d.ts +14 -0
- package/dist/commands/generate-domain-service.js +796 -0
- package/dist/commands/generate-domain-service.js.map +1 -0
- package/dist/commands/generate-entity.js +82 -24
- package/dist/commands/generate-entity.js.map +1 -1
- package/dist/commands/generate-from-schema.d.ts +56 -0
- package/dist/commands/generate-from-schema.js +222 -0
- package/dist/commands/generate-from-schema.js.map +1 -0
- package/dist/commands/generate-orchestrator.d.ts +14 -0
- package/dist/commands/generate-orchestrator.js +887 -0
- package/dist/commands/generate-orchestrator.js.map +1 -0
- package/dist/commands/generate-repository.d.ts +14 -0
- package/dist/commands/generate-repository.js +1019 -0
- package/dist/commands/generate-repository.js.map +1 -0
- package/dist/commands/generate-shared.d.ts +4 -0
- package/dist/commands/generate-shared.js +388 -0
- package/dist/commands/generate-shared.js.map +1 -0
- package/dist/commands/generate-value-object.d.ts +32 -0
- package/dist/commands/generate-value-object.js +700 -0
- package/dist/commands/generate-value-object.js.map +1 -0
- package/dist/commands/graphql-subscriptions.d.ts +6 -0
- package/dist/commands/graphql-subscriptions.js +607 -0
- package/dist/commands/graphql-subscriptions.js.map +1 -0
- package/dist/commands/graphql-types.d.ts +5 -0
- package/dist/commands/graphql-types.js +423 -0
- package/dist/commands/graphql-types.js.map +1 -0
- package/dist/commands/health-probes-advanced.d.ts +6 -0
- package/dist/commands/health-probes-advanced.js +655 -0
- package/dist/commands/health-probes-advanced.js.map +1 -0
- package/dist/commands/i18n-setup.d.ts +10 -0
- package/dist/commands/i18n-setup.js +677 -0
- package/dist/commands/i18n-setup.js.map +1 -0
- package/dist/commands/init-config.d.ts +6 -0
- package/dist/commands/init-config.js +370 -0
- package/dist/commands/init-config.js.map +1 -0
- package/dist/commands/init-project.js +56 -6
- package/dist/commands/init-project.js.map +1 -1
- package/dist/commands/interactive-scaffold.d.ts +5 -0
- package/dist/commands/interactive-scaffold.js +271 -0
- package/dist/commands/interactive-scaffold.js.map +1 -0
- package/dist/commands/metrics-prometheus.d.ts +6 -0
- package/dist/commands/metrics-prometheus.js +681 -0
- package/dist/commands/metrics-prometheus.js.map +1 -0
- package/dist/commands/migration-engine.d.ts +6 -0
- package/dist/commands/migration-engine.js +446 -0
- package/dist/commands/migration-engine.js.map +1 -0
- package/dist/commands/migration.d.ts +12 -0
- package/dist/commands/migration.js +484 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/monorepo.d.ts +8 -0
- package/dist/commands/monorepo.js +483 -0
- package/dist/commands/monorepo.js.map +1 -0
- package/dist/commands/multi-database.d.ts +5 -0
- package/dist/commands/multi-database.js +439 -0
- package/dist/commands/multi-database.js.map +1 -0
- package/dist/commands/observability-tracing.d.ts +10 -0
- package/dist/commands/observability-tracing.js +740 -0
- package/dist/commands/observability-tracing.js.map +1 -0
- package/dist/commands/openapi-export.d.ts +8 -0
- package/dist/commands/openapi-export.js +359 -0
- package/dist/commands/openapi-export.js.map +1 -0
- package/dist/commands/perf-analyzer.d.ts +8 -0
- package/dist/commands/perf-analyzer.js +423 -0
- package/dist/commands/perf-analyzer.js.map +1 -0
- package/dist/commands/rate-limiting.d.ts +10 -0
- package/dist/commands/rate-limiting.js +953 -0
- package/dist/commands/rate-limiting.js.map +1 -0
- package/dist/commands/recipe-plugin.d.ts +56 -0
- package/dist/commands/recipe-plugin.js +315 -0
- package/dist/commands/recipe-plugin.js.map +1 -0
- package/dist/commands/recipe.d.ts +6 -0
- package/dist/commands/recipe.js +3941 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
- package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
- package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
- package/dist/commands/recipes/index.d.ts +7 -0
- package/dist/commands/recipes/index.js +24 -0
- package/dist/commands/recipes/index.js.map +1 -0
- package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
- package/dist/commands/recipes/message-queue.recipe.js +706 -0
- package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
- package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
- package/dist/commands/recipes/middleware.recipe.js +383 -0
- package/dist/commands/recipes/middleware.recipe.js.map +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2.recipe.js +472 -0
- package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
- package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
- package/dist/commands/recipes/websocket.recipe.js +453 -0
- package/dist/commands/recipes/websocket.recipe.js.map +1 -0
- package/dist/commands/resilience-patterns.d.ts +13 -0
- package/dist/commands/resilience-patterns.js +1029 -0
- package/dist/commands/resilience-patterns.js.map +1 -0
- package/dist/commands/security-patterns.d.ts +11 -0
- package/dist/commands/security-patterns.js +2233 -0
- package/dist/commands/security-patterns.js.map +1 -0
- package/dist/commands/template-debug.d.ts +27 -0
- package/dist/commands/template-debug.js +388 -0
- package/dist/commands/template-debug.js.map +1 -0
- package/dist/commands/test-factory-full.d.ts +9 -0
- package/dist/commands/test-factory-full.js +1570 -0
- package/dist/commands/test-factory-full.js.map +1 -0
- package/dist/commands/test-scaffold.d.ts +7 -0
- package/dist/commands/test-scaffold.js +621 -0
- package/dist/commands/test-scaffold.js.map +1 -0
- package/dist/index.js +1088 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
- package/dist/templates/ai-context/conventions.md.hbs +154 -0
- package/dist/templates/command/create-command.hbs +6 -14
- package/dist/templates/command/delete-command.hbs +19 -0
- package/dist/templates/command/update-command.hbs +24 -0
- package/dist/templates/controller/controller.hbs +64 -17
- package/dist/templates/dto/create-dto.hbs +29 -5
- package/dist/templates/dto/filter-dto.hbs +52 -0
- package/dist/templates/dto/filter-query.dto.hbs +148 -0
- package/dist/templates/dto/paginated-response.dto.hbs +29 -0
- package/dist/templates/dto/pagination-query.dto.hbs +30 -0
- package/dist/templates/dto/response-dto.hbs +38 -0
- package/dist/templates/dto/update-dto.hbs +11 -0
- package/dist/templates/entity/entity.hbs +32 -1
- package/dist/templates/event/domain-event.hbs +33 -7
- package/dist/templates/event/event-handler.hbs +40 -0
- package/dist/templates/exception/base-exceptions.hbs +69 -0
- package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
- package/dist/templates/mapper/mapper.hbs +49 -24
- package/dist/templates/module/module.hbs +34 -10
- package/dist/templates/orm-entity/orm-entity.hbs +63 -12
- package/dist/templates/prisma/prisma-mapper.hbs +71 -0
- package/dist/templates/prisma/prisma-repository.hbs +114 -0
- package/dist/templates/prisma/prisma-schema.hbs +20 -0
- package/dist/templates/prisma/prisma-service.hbs +51 -0
- package/dist/templates/query/get-all.query.hbs +50 -0
- package/dist/templates/query/get-by-id.query.hbs +31 -0
- package/dist/templates/repository/repository.hbs +55 -13
- package/dist/templates/resolver/graphql-input.hbs +54 -0
- package/dist/templates/resolver/graphql-type.hbs +58 -0
- package/dist/templates/resolver/pagination-args.hbs +33 -0
- package/dist/templates/resolver/resolver.hbs +62 -0
- package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
- package/dist/templates/shared/query-builder.util.hbs +218 -0
- package/dist/templates/test/controller.spec.hbs +124 -0
- package/dist/templates/test/repository.spec.hbs +158 -0
- package/dist/templates/test/usecase.spec.hbs +116 -0
- package/dist/templates/usecase/create-usecase.hbs +19 -7
- package/dist/templates/usecase/delete-usecase.hbs +17 -0
- package/dist/templates/usecase/update-usecase.hbs +31 -0
- package/dist/utils/config.utils.d.ts +45 -0
- package/dist/utils/config.utils.js +211 -0
- package/dist/utils/config.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +145 -0
- package/dist/utils/error.utils.js +422 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/field.utils.d.ts +54 -0
- package/dist/utils/field.utils.js +389 -0
- package/dist/utils/field.utils.js.map +1 -0
- package/dist/utils/file.utils.d.ts +19 -8
- package/dist/utils/file.utils.js +135 -4
- package/dist/utils/file.utils.js.map +1 -1
- package/dist/utils/idempotency.utils.d.ts +123 -0
- package/dist/utils/idempotency.utils.js +444 -0
- package/dist/utils/idempotency.utils.js.map +1 -0
- package/dist/utils/naming.utils.js +26 -3
- package/dist/utils/naming.utils.js.map +1 -1
- package/dist/utils/performance.utils.d.ts +37 -0
- package/dist/utils/performance.utils.js +158 -0
- package/dist/utils/performance.utils.js.map +1 -0
- package/dist/utils/relation.utils.d.ts +92 -0
- package/dist/utils/relation.utils.js +388 -0
- package/dist/utils/relation.utils.js.map +1 -0
- package/dist/utils/rollback.utils.d.ts +49 -0
- package/dist/utils/rollback.utils.js +306 -0
- package/dist/utils/rollback.utils.js.map +1 -0
- package/dist/utils/schema.utils.d.ts +123 -0
- package/dist/utils/schema.utils.js +419 -0
- package/dist/utils/schema.utils.js.map +1 -0
- package/dist/utils/security.utils.d.ts +57 -0
- package/dist/utils/security.utils.js +315 -0
- package/dist/utils/security.utils.js.map +1 -0
- package/dist/utils/template-engine.utils.d.ts +80 -0
- package/dist/utils/template-engine.utils.js +463 -0
- package/dist/utils/template-engine.utils.js.map +1 -0
- package/dist/utils/validation-registry.utils.d.ts +160 -0
- package/dist/utils/validation-registry.utils.js +526 -0
- package/dist/utils/validation-registry.utils.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ApiPropertyOptional } from "@nestjs/swagger";
|
|
2
|
+
import { IsOptional, IsString, IsBoolean, IsDate, IsUUID } from "class-validator";
|
|
3
|
+
import { Type } from "class-transformer";
|
|
4
|
+
import { PaginationQueryDto } from "./pagination.query.dto";
|
|
5
|
+
|
|
6
|
+
export class {{entityNamePascal}}FilterDto extends PaginationQueryDto {
|
|
7
|
+
@ApiPropertyOptional({ description: "Search by ID" })
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsUUID()
|
|
10
|
+
id?: string;
|
|
11
|
+
|
|
12
|
+
@ApiPropertyOptional({ description: "Filter by active status" })
|
|
13
|
+
@IsOptional()
|
|
14
|
+
@IsBoolean()
|
|
15
|
+
@Type(() => Boolean)
|
|
16
|
+
isActive?: boolean;
|
|
17
|
+
|
|
18
|
+
@ApiPropertyOptional({ description: "Search term for text fields" })
|
|
19
|
+
@IsOptional()
|
|
20
|
+
@IsString()
|
|
21
|
+
search?: string;
|
|
22
|
+
|
|
23
|
+
@ApiPropertyOptional({ description: "Filter by creation date (from)" })
|
|
24
|
+
@IsOptional()
|
|
25
|
+
@Type(() => Date)
|
|
26
|
+
@IsDate()
|
|
27
|
+
createdFrom?: Date;
|
|
28
|
+
|
|
29
|
+
@ApiPropertyOptional({ description: "Filter by creation date (to)" })
|
|
30
|
+
@IsOptional()
|
|
31
|
+
@Type(() => Date)
|
|
32
|
+
@IsDate()
|
|
33
|
+
createdTo?: Date;
|
|
34
|
+
|
|
35
|
+
{{#if hasFields}}
|
|
36
|
+
{{#each fields}}
|
|
37
|
+
{{#unless this.isArray}}
|
|
38
|
+
@ApiPropertyOptional({ description: "Filter by {{this.camelCase}}" })
|
|
39
|
+
@IsOptional()
|
|
40
|
+
{{this.snakeCase}}?: {{this.tsType}};
|
|
41
|
+
|
|
42
|
+
{{/unless}}
|
|
43
|
+
{{/each}}
|
|
44
|
+
{{else}}
|
|
45
|
+
// Add your filter fields here
|
|
46
|
+
// Example:
|
|
47
|
+
// @ApiPropertyOptional({ description: "Filter by name" })
|
|
48
|
+
// @IsOptional()
|
|
49
|
+
// @IsString()
|
|
50
|
+
// name?: string;
|
|
51
|
+
{{/if}}
|
|
52
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ApiPropertyOptional } from "@nestjs/swagger";
|
|
2
|
+
import { IsOptional, IsString, IsIn, IsArray, ValidateNested } from "class-validator";
|
|
3
|
+
import { Type, Transform } from "class-transformer";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Filter operators for query building
|
|
7
|
+
*/
|
|
8
|
+
export type FilterOperator =
|
|
9
|
+
| "eq" // Equal
|
|
10
|
+
| "ne" // Not equal
|
|
11
|
+
| "gt" // Greater than
|
|
12
|
+
| "gte" // Greater than or equal
|
|
13
|
+
| "lt" // Less than
|
|
14
|
+
| "lte" // Less than or equal
|
|
15
|
+
| "in" // In array
|
|
16
|
+
| "nin" // Not in array
|
|
17
|
+
| "like" // Contains (case insensitive)
|
|
18
|
+
| "ilike" // Contains (case insensitive) - PostgreSQL
|
|
19
|
+
| "between" // Between two values
|
|
20
|
+
| "isNull" // Is null
|
|
21
|
+
| "isNotNull"; // Is not null
|
|
22
|
+
|
|
23
|
+
export class FilterCondition {
|
|
24
|
+
@ApiPropertyOptional({ description: "Field name to filter" })
|
|
25
|
+
@IsString()
|
|
26
|
+
field: string;
|
|
27
|
+
|
|
28
|
+
@ApiPropertyOptional({
|
|
29
|
+
description: "Filter operator",
|
|
30
|
+
enum: ["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "like", "ilike", "between", "isNull", "isNotNull"]
|
|
31
|
+
})
|
|
32
|
+
@IsIn(["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin", "like", "ilike", "between", "isNull", "isNotNull"])
|
|
33
|
+
operator: FilterOperator;
|
|
34
|
+
|
|
35
|
+
@ApiPropertyOptional({ description: "Filter value" })
|
|
36
|
+
value?: any;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class {{entityNamePascal}}FilterDto {
|
|
40
|
+
{{#if hasFields}}
|
|
41
|
+
{{#each fields}}
|
|
42
|
+
@ApiPropertyOptional({ description: "Filter by {{this.camelCase}}" })
|
|
43
|
+
@IsOptional()
|
|
44
|
+
{{this.camelCase}}?: {{this.tsType}};
|
|
45
|
+
|
|
46
|
+
@ApiPropertyOptional({ description: "Filter by {{this.camelCase}} with operator (e.g., {{this.camelCase}}__gte=10)" })
|
|
47
|
+
@IsOptional()
|
|
48
|
+
{{this.camelCase}}__eq?: {{this.tsType}};
|
|
49
|
+
|
|
50
|
+
@ApiPropertyOptional()
|
|
51
|
+
@IsOptional()
|
|
52
|
+
{{this.camelCase}}__ne?: {{this.tsType}};
|
|
53
|
+
|
|
54
|
+
{{#if (or (eq this.type 'number') (eq this.type 'date') (eq this.type 'datetime'))}}
|
|
55
|
+
@ApiPropertyOptional()
|
|
56
|
+
@IsOptional()
|
|
57
|
+
{{this.camelCase}}__gt?: {{this.tsType}};
|
|
58
|
+
|
|
59
|
+
@ApiPropertyOptional()
|
|
60
|
+
@IsOptional()
|
|
61
|
+
{{this.camelCase}}__gte?: {{this.tsType}};
|
|
62
|
+
|
|
63
|
+
@ApiPropertyOptional()
|
|
64
|
+
@IsOptional()
|
|
65
|
+
{{this.camelCase}}__lt?: {{this.tsType}};
|
|
66
|
+
|
|
67
|
+
@ApiPropertyOptional()
|
|
68
|
+
@IsOptional()
|
|
69
|
+
{{this.camelCase}}__lte?: {{this.tsType}};
|
|
70
|
+
|
|
71
|
+
{{/if}}
|
|
72
|
+
{{#if (eq this.type 'string')}}
|
|
73
|
+
@ApiPropertyOptional({ description: "Contains search for {{this.camelCase}}" })
|
|
74
|
+
@IsOptional()
|
|
75
|
+
{{this.camelCase}}__like?: string;
|
|
76
|
+
|
|
77
|
+
{{/if}}
|
|
78
|
+
{{/each}}
|
|
79
|
+
{{else}}
|
|
80
|
+
// Add filter fields based on your entity properties
|
|
81
|
+
// Example:
|
|
82
|
+
// @ApiPropertyOptional()
|
|
83
|
+
// @IsOptional()
|
|
84
|
+
// name?: string;
|
|
85
|
+
//
|
|
86
|
+
// @ApiPropertyOptional()
|
|
87
|
+
// @IsOptional()
|
|
88
|
+
// name__like?: string;
|
|
89
|
+
{{/if}}
|
|
90
|
+
|
|
91
|
+
@ApiPropertyOptional({ description: "Filter by active status" })
|
|
92
|
+
@IsOptional()
|
|
93
|
+
isActive?: boolean;
|
|
94
|
+
|
|
95
|
+
@ApiPropertyOptional({ description: "Search across multiple fields" })
|
|
96
|
+
@IsOptional()
|
|
97
|
+
@IsString()
|
|
98
|
+
search?: string;
|
|
99
|
+
|
|
100
|
+
@ApiPropertyOptional({ description: "Fields to search in (comma-separated)" })
|
|
101
|
+
@IsOptional()
|
|
102
|
+
@Transform(({ value }) => typeof value === "string" ? value.split(",") : value)
|
|
103
|
+
@IsArray()
|
|
104
|
+
searchFields?: string[];
|
|
105
|
+
|
|
106
|
+
@ApiPropertyOptional({ description: "Filter by date range - start" })
|
|
107
|
+
@IsOptional()
|
|
108
|
+
@Type(() => Date)
|
|
109
|
+
createdAtFrom?: Date;
|
|
110
|
+
|
|
111
|
+
@ApiPropertyOptional({ description: "Filter by date range - end" })
|
|
112
|
+
@IsOptional()
|
|
113
|
+
@Type(() => Date)
|
|
114
|
+
createdAtTo?: Date;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Combined filter and pagination DTO
|
|
119
|
+
*/
|
|
120
|
+
export class {{entityNamePascal}}QueryDto extends {{entityNamePascal}}FilterDto {
|
|
121
|
+
@ApiPropertyOptional({ description: "Page number", default: 1, minimum: 1 })
|
|
122
|
+
@IsOptional()
|
|
123
|
+
@Type(() => Number)
|
|
124
|
+
page?: number = 1;
|
|
125
|
+
|
|
126
|
+
@ApiPropertyOptional({ description: "Items per page", default: 10, minimum: 1, maximum: 100 })
|
|
127
|
+
@IsOptional()
|
|
128
|
+
@Type(() => Number)
|
|
129
|
+
limit?: number = 10;
|
|
130
|
+
|
|
131
|
+
@ApiPropertyOptional({ description: "Field to sort by", default: "createdAt" })
|
|
132
|
+
@IsOptional()
|
|
133
|
+
@IsString()
|
|
134
|
+
sortBy?: string = "createdAt";
|
|
135
|
+
|
|
136
|
+
@ApiPropertyOptional({ description: "Sort order", enum: ["ASC", "DESC"], default: "DESC" })
|
|
137
|
+
@IsOptional()
|
|
138
|
+
@IsIn(["ASC", "DESC"])
|
|
139
|
+
sortOrder?: "ASC" | "DESC" = "DESC";
|
|
140
|
+
|
|
141
|
+
get skip(): number {
|
|
142
|
+
return ((this.page || 1) - 1) * (this.limit || 10);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
get take(): number {
|
|
146
|
+
return this.limit || 10;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ApiProperty } from "@nestjs/swagger";
|
|
2
|
+
|
|
3
|
+
export class PaginationMeta {
|
|
4
|
+
@ApiProperty({ description: "Total number of items" })
|
|
5
|
+
total: number;
|
|
6
|
+
|
|
7
|
+
@ApiProperty({ description: "Current page number" })
|
|
8
|
+
page: number;
|
|
9
|
+
|
|
10
|
+
@ApiProperty({ description: "Number of items per page" })
|
|
11
|
+
limit: number;
|
|
12
|
+
|
|
13
|
+
@ApiProperty({ description: "Total number of pages" })
|
|
14
|
+
totalPages: number;
|
|
15
|
+
|
|
16
|
+
@ApiProperty({ description: "Whether there is a next page" })
|
|
17
|
+
hasNextPage: boolean;
|
|
18
|
+
|
|
19
|
+
@ApiProperty({ description: "Whether there is a previous page" })
|
|
20
|
+
hasPreviousPage: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class PaginatedResponseDto<T> {
|
|
24
|
+
@ApiProperty({ description: "Array of items", isArray: true })
|
|
25
|
+
items: T[];
|
|
26
|
+
|
|
27
|
+
@ApiProperty({ description: "Pagination metadata", type: PaginationMeta })
|
|
28
|
+
meta: PaginationMeta;
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ApiPropertyOptional } from "@nestjs/swagger";
|
|
2
|
+
import { IsOptional, IsInt, Min, Max, IsString, IsIn } from "class-validator";
|
|
3
|
+
import { Type } from "class-transformer";
|
|
4
|
+
|
|
5
|
+
export class PaginationQueryDto {
|
|
6
|
+
@ApiPropertyOptional({ description: "Page number", default: 1, minimum: 1 })
|
|
7
|
+
@IsOptional()
|
|
8
|
+
@Type(() => Number)
|
|
9
|
+
@IsInt()
|
|
10
|
+
@Min(1)
|
|
11
|
+
page?: number = 1;
|
|
12
|
+
|
|
13
|
+
@ApiPropertyOptional({ description: "Items per page", default: 10, minimum: 1, maximum: 100 })
|
|
14
|
+
@IsOptional()
|
|
15
|
+
@Type(() => Number)
|
|
16
|
+
@IsInt()
|
|
17
|
+
@Min(1)
|
|
18
|
+
@Max(100)
|
|
19
|
+
limit?: number = 10;
|
|
20
|
+
|
|
21
|
+
@ApiPropertyOptional({ description: "Field to sort by", default: "createdAt" })
|
|
22
|
+
@IsOptional()
|
|
23
|
+
@IsString()
|
|
24
|
+
sortBy?: string = "createdAt";
|
|
25
|
+
|
|
26
|
+
@ApiPropertyOptional({ description: "Sort order", enum: ["ASC", "DESC"], default: "DESC" })
|
|
27
|
+
@IsOptional()
|
|
28
|
+
@IsIn(["ASC", "DESC"])
|
|
29
|
+
sortOrder?: "ASC" | "DESC" = "DESC";
|
|
30
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ApiProperty } from "@nestjs/swagger";
|
|
2
|
+
import { Expose } from "class-transformer";
|
|
3
|
+
|
|
4
|
+
export class {{entityNamePascal}}ResponseDto {
|
|
5
|
+
@ApiProperty({ description: "Unique identifier", format: "uuid" })
|
|
6
|
+
@Expose()
|
|
7
|
+
id: string;
|
|
8
|
+
|
|
9
|
+
{{#if hasFields}}
|
|
10
|
+
{{#each fields}}
|
|
11
|
+
@ApiProperty({ description: "{{this.description}}"{{#if this.example}}, example: "{{this.example}}"{{/if}} })
|
|
12
|
+
@Expose()
|
|
13
|
+
{{this.camelCase}}: {{this.tsType}};
|
|
14
|
+
|
|
15
|
+
{{/each}}
|
|
16
|
+
{{else}}
|
|
17
|
+
// Add your response properties here
|
|
18
|
+
// Example:
|
|
19
|
+
// @ApiProperty({ description: "User name" })
|
|
20
|
+
// @Expose()
|
|
21
|
+
// name: string;
|
|
22
|
+
{{/if}}
|
|
23
|
+
@ApiProperty({ description: "Whether the record is active" })
|
|
24
|
+
@Expose()
|
|
25
|
+
isActive: boolean;
|
|
26
|
+
|
|
27
|
+
@ApiProperty({ description: "Creation timestamp" })
|
|
28
|
+
@Expose()
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
|
|
31
|
+
@ApiProperty({ description: "Last update timestamp" })
|
|
32
|
+
@Expose()
|
|
33
|
+
updatedAt: Date;
|
|
34
|
+
|
|
35
|
+
constructor(partial: Partial<{{entityNamePascal}}ResponseDto>) {
|
|
36
|
+
Object.assign(this, partial);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiPropertyOptional } from "@nestjs/swagger";
|
|
2
|
+
import { IsOptional, IsBoolean } from "class-validator";
|
|
3
|
+
import { PartialType } from "@nestjs/swagger";
|
|
4
|
+
import { Create{{entityNamePascal}}Dto } from "./create-{{entityNameKebab}}.dto";
|
|
5
|
+
|
|
6
|
+
export class Update{{entityNamePascal}}Dto extends PartialType(Create{{entityNamePascal}}Dto) {
|
|
7
|
+
@ApiPropertyOptional({ description: "Whether the record is active" })
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsBoolean()
|
|
10
|
+
isActive?: boolean;
|
|
11
|
+
}
|
|
@@ -4,8 +4,14 @@ export interface {{entityNamePascal}}EntityProps {
|
|
|
4
4
|
createdAt?: Date;
|
|
5
5
|
updatedAt?: Date;
|
|
6
6
|
deletedAt?: Date;
|
|
7
|
+
{{#if hasFields}}
|
|
8
|
+
{{#each fields}}
|
|
9
|
+
{{this.camelCase}}{{#if this.isOptional}}?{{/if}}: {{this.tsType}};
|
|
10
|
+
{{/each}}
|
|
11
|
+
{{else}}
|
|
7
12
|
// Add your domain properties here
|
|
8
13
|
// Example: name: string;
|
|
14
|
+
{{/if}}
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
export class {{entityNamePascal}}Entity {
|
|
@@ -14,10 +20,35 @@ export class {{entityNamePascal}}Entity {
|
|
|
14
20
|
public readonly createdAt?: Date;
|
|
15
21
|
public readonly updatedAt?: Date;
|
|
16
22
|
public readonly deletedAt?: Date;
|
|
23
|
+
{{#if hasFields}}
|
|
24
|
+
{{#each fields}}
|
|
25
|
+
public readonly {{this.camelCase}}{{#if this.isOptional}}?{{/if}}: {{this.tsType}};
|
|
26
|
+
{{/each}}
|
|
27
|
+
{{else}}
|
|
17
28
|
// Add your domain properties here
|
|
18
29
|
// Example: public readonly name: string;
|
|
30
|
+
{{/if}}
|
|
19
31
|
|
|
20
32
|
constructor(props: {{entityNamePascal}}EntityProps) {
|
|
21
33
|
Object.assign(this, props);
|
|
22
34
|
}
|
|
23
|
-
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a copy of the entity with updated properties
|
|
38
|
+
*/
|
|
39
|
+
public update(props: Partial<{{entityNamePascal}}EntityProps>): {{entityNamePascal}}Entity {
|
|
40
|
+
return new {{entityNamePascal}}Entity({
|
|
41
|
+
...this,
|
|
42
|
+
...props,
|
|
43
|
+
updatedAt: new Date(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if the entity is valid for persistence
|
|
49
|
+
*/
|
|
50
|
+
public isValid(): boolean {
|
|
51
|
+
// Add your validation logic here
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
import { IEvent } from
|
|
1
|
+
import { IEvent } from "@nestjs/cqrs";
|
|
2
|
+
|
|
3
|
+
export interface {{entityNamePascal}}EventData {
|
|
4
|
+
// Define your event payload here
|
|
5
|
+
// Example:
|
|
6
|
+
// name: string;
|
|
7
|
+
// email: string;
|
|
8
|
+
{{#each fields}}
|
|
9
|
+
{{this.camelCase}}{{#if this.isOptional}}?{{/if}}: {{this.tsType}};
|
|
10
|
+
{{/each}}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class {{entityNamePascal}}{{eventName}}Event implements IEvent {
|
|
14
|
+
public readonly occurredAt: Date;
|
|
15
|
+
public readonly eventType = "{{entityNamePascal}}{{eventName}}";
|
|
2
16
|
|
|
3
|
-
export class {{entityName}}Event implements IEvent {
|
|
4
17
|
constructor(
|
|
5
|
-
public readonly
|
|
6
|
-
public readonly data:
|
|
7
|
-
public readonly
|
|
8
|
-
|
|
9
|
-
|
|
18
|
+
public readonly {{entityNameCamel}}Id: string,
|
|
19
|
+
public readonly data: {{entityNamePascal}}EventData,
|
|
20
|
+
public readonly metadata?: {
|
|
21
|
+
correlationId?: string;
|
|
22
|
+
causationId?: string;
|
|
23
|
+
userId?: string;
|
|
24
|
+
}
|
|
25
|
+
) {
|
|
26
|
+
this.occurredAt = new Date();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get a string representation of the event for logging
|
|
31
|
+
*/
|
|
32
|
+
toString(): string {
|
|
33
|
+
return `${this.eventType}(${this.{{entityNameCamel}}Id}) at ${this.occurredAt.toISOString()}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EventsHandler, IEventHandler } from "@nestjs/cqrs";
|
|
2
|
+
import { Logger } from "@nestjs/common";
|
|
3
|
+
import { {{entityNamePascal}}{{eventName}}Event } from "./{{entityNameKebab}}-{{eventNameKebab}}.event";
|
|
4
|
+
|
|
5
|
+
@EventsHandler({{entityNamePascal}}{{eventName}}Event)
|
|
6
|
+
export class {{entityNamePascal}}{{eventName}}Handler
|
|
7
|
+
implements IEventHandler<{{entityNamePascal}}{{eventName}}Event>
|
|
8
|
+
{
|
|
9
|
+
private readonly logger = new Logger({{entityNamePascal}}{{eventName}}Handler.name);
|
|
10
|
+
|
|
11
|
+
async handle(event: {{entityNamePascal}}{{eventName}}Event): Promise<void> {
|
|
12
|
+
this.logger.log(
|
|
13
|
+
`Handling {{entityNamePascal}}{{eventName}}Event for {{entityNameCamel}} ${event.{{entityNameCamel}}Id}`
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
// Implement your event handling logic here
|
|
17
|
+
// Examples:
|
|
18
|
+
// - Send notification emails
|
|
19
|
+
// - Update related aggregates
|
|
20
|
+
// - Publish to external systems
|
|
21
|
+
// - Update read models
|
|
22
|
+
// - Trigger workflows
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Your async operations here
|
|
26
|
+
await this.processEvent(event);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
this.logger.error(
|
|
29
|
+
`Failed to handle {{entityNamePascal}}{{eventName}}Event: ${error.message}`,
|
|
30
|
+
error.stack
|
|
31
|
+
);
|
|
32
|
+
// Consider: retry logic, dead letter queue, or alerting
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async processEvent(event: {{entityNamePascal}}{{eventName}}Event): Promise<void> {
|
|
38
|
+
// Implement your specific event processing logic
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BadRequestException,
|
|
3
|
+
ConflictException,
|
|
4
|
+
ForbiddenException,
|
|
5
|
+
NotFoundException,
|
|
6
|
+
UnauthorizedException,
|
|
7
|
+
} from "@nestjs/common";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base exception for domain validation errors
|
|
11
|
+
*/
|
|
12
|
+
export class DomainValidationException extends BadRequestException {
|
|
13
|
+
constructor(message: string, public readonly errors?: Record<string, string[]>) {
|
|
14
|
+
super({
|
|
15
|
+
statusCode: 400,
|
|
16
|
+
message,
|
|
17
|
+
errors,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Exception for when an entity already exists (duplicate)
|
|
24
|
+
*/
|
|
25
|
+
export class EntityAlreadyExistsException extends ConflictException {
|
|
26
|
+
constructor(entityName: string, field: string, value: string) {
|
|
27
|
+
super(`${entityName} with ${field} '${value}' already exists`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Exception for when an entity is not found
|
|
33
|
+
*/
|
|
34
|
+
export class EntityNotFoundException extends NotFoundException {
|
|
35
|
+
constructor(entityName: string, id: string) {
|
|
36
|
+
super(`${entityName} with id '${id}' was not found`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Exception for when a business rule is violated
|
|
42
|
+
*/
|
|
43
|
+
export class BusinessRuleViolationException extends BadRequestException {
|
|
44
|
+
constructor(message: string) {
|
|
45
|
+
super({
|
|
46
|
+
statusCode: 400,
|
|
47
|
+
message,
|
|
48
|
+
error: 'Business Rule Violation',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Exception for unauthorized access
|
|
55
|
+
*/
|
|
56
|
+
export class UnauthorizedAccessException extends UnauthorizedException {
|
|
57
|
+
constructor(message = 'You are not authorized to perform this action') {
|
|
58
|
+
super(message);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Exception for forbidden operations
|
|
64
|
+
*/
|
|
65
|
+
export class ForbiddenOperationException extends ForbiddenException {
|
|
66
|
+
constructor(message = 'You do not have permission to perform this operation') {
|
|
67
|
+
super(message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,37 +1,62 @@
|
|
|
1
|
-
import { {{entityNamePascal}}OrmEntity } from "@modules/{{moduleNameKebab}}/infrastructure/orm-entities/{{entityNameKebab}}.orm-entity";
|
|
2
|
-
import { {{entityNamePascal}}Entity } from "@modules/{{moduleNameKebab}}/domain/entities/{{entityNameKebab}}.entity";
|
|
3
1
|
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { {{entityNamePascal}}Entity } from "@modules/{{moduleNameKebab}}/domain/entities/{{entityNameKebab}}.entity";
|
|
3
|
+
import { {{entityNamePascal}}OrmEntity } from "@modules/{{moduleNameKebab}}/infrastructure/orm-entities/{{entityNameKebab}}.orm-entity";
|
|
4
|
+
import { {{entityNamePascal}}ResponseDto } from "@modules/{{moduleNameKebab}}/application/dto/responses/{{entityNameKebab}}.response.dto";
|
|
4
5
|
|
|
5
6
|
@Injectable()
|
|
6
7
|
export class {{entityNamePascal}}Mapper {
|
|
7
|
-
|
|
8
|
-
if (!
|
|
9
|
-
throw new Error(
|
|
8
|
+
toDomainEntity(ormEntity: {{entityNamePascal}}OrmEntity): {{entityNamePascal}}Entity {
|
|
9
|
+
if (!ormEntity) {
|
|
10
|
+
throw new Error("ORM entity is required");
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
ormEntity.id = domainEntity.id;
|
|
14
|
-
ormEntity.isActive = domainEntity.isActive;
|
|
15
|
-
ormEntity.createdAt = domainEntity.createdAt;
|
|
16
|
-
ormEntity.updatedAt = domainEntity.updatedAt;
|
|
17
|
-
ormEntity.deletedAt = domainEntity.deletedAt;
|
|
18
|
-
// Map your properties from camelCase to snake_case
|
|
19
|
-
// Example: ormEntity.property_name = domainEntity.propertyName;
|
|
20
|
-
|
|
21
|
-
return ormEntity;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
toDomainEntity(ormEntity: {{entityNamePascal}}OrmEntity): {{entityNamePascal}}Entity {
|
|
25
|
-
const entity = new {{entityNamePascal}}Entity({
|
|
13
|
+
return new {{entityNamePascal}}Entity({
|
|
26
14
|
id: ormEntity.id,
|
|
27
15
|
isActive: ormEntity.isActive,
|
|
28
16
|
createdAt: ormEntity.createdAt,
|
|
29
17
|
updatedAt: ormEntity.updatedAt,
|
|
30
18
|
deletedAt: ormEntity.deletedAt,
|
|
31
|
-
// Map
|
|
32
|
-
|
|
19
|
+
// Map additional fields from ORM entity (snake_case) to domain entity (camelCase)
|
|
20
|
+
{{#each fields}}
|
|
21
|
+
{{this.camelCase}}: ormEntity.{{this.snakeCase}},
|
|
22
|
+
{{/each}}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toOrmEntity(domainEntity: {{entityNamePascal}}Entity): Partial<{{entityNamePascal}}OrmEntity> {
|
|
27
|
+
if (!domainEntity) {
|
|
28
|
+
throw new Error("Domain entity is required");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const ormEntity: Partial<{{entityNamePascal}}OrmEntity> = {
|
|
32
|
+
id: domainEntity.id,
|
|
33
|
+
isActive: domainEntity.isActive,
|
|
34
|
+
createdAt: domainEntity.createdAt,
|
|
35
|
+
updatedAt: domainEntity.updatedAt,
|
|
36
|
+
deletedAt: domainEntity.deletedAt,
|
|
37
|
+
// Map additional fields from domain entity (camelCase) to ORM entity (snake_case)
|
|
38
|
+
{{#each fields}}
|
|
39
|
+
{{this.snakeCase}}: domainEntity.{{this.camelCase}},
|
|
40
|
+
{{/each}}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return ormEntity;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
toResponseDto(entity: {{entityNamePascal}}Entity): {{entityNamePascal}}ResponseDto {
|
|
47
|
+
return new {{entityNamePascal}}ResponseDto({
|
|
48
|
+
id: entity.id,
|
|
49
|
+
isActive: entity.isActive,
|
|
50
|
+
createdAt: entity.createdAt,
|
|
51
|
+
updatedAt: entity.updatedAt,
|
|
52
|
+
// Map additional fields for response
|
|
53
|
+
{{#each fields}}
|
|
54
|
+
{{this.camelCase}}: entity.{{this.camelCase}},
|
|
55
|
+
{{/each}}
|
|
33
56
|
});
|
|
34
|
-
|
|
35
|
-
return entity;
|
|
36
57
|
}
|
|
37
|
-
|
|
58
|
+
|
|
59
|
+
toResponseDtoList(entities: {{entityNamePascal}}Entity[]): {{entityNamePascal}}ResponseDto[] {
|
|
60
|
+
return entities.map((entity) => this.toResponseDto(entity));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,25 +1,49 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common";
|
|
2
2
|
import { CqrsModule } from "@nestjs/cqrs";
|
|
3
|
+
import { TypeOrmModule } from "@nestjs/typeorm";
|
|
4
|
+
|
|
5
|
+
// Infrastructure
|
|
6
|
+
import { OrmEntities } from "@modules/{{moduleNameKebab}}/infrastructure/orm-entities";
|
|
3
7
|
import { Repositories } from "@modules/{{moduleNameKebab}}/infrastructure/repositories";
|
|
4
|
-
import { Queries } from "@modules/{{moduleNameKebab}}/application/queries";
|
|
5
8
|
import { Mappers } from "@modules/{{moduleNameKebab}}/infrastructure/mappers";
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
// Application - Commands
|
|
8
11
|
import { CommandHandlers } from "@modules/{{moduleNameKebab}}/application/commands";
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
|
|
13
|
+
// Application - Queries
|
|
14
|
+
import { Queries } from "@modules/{{moduleNameKebab}}/application/queries";
|
|
15
|
+
|
|
16
|
+
// Application - Use Cases
|
|
17
|
+
import { UseCases } from "@modules/{{moduleNameKebab}}/application/domain/usecases";
|
|
18
|
+
|
|
19
|
+
// Application - Services
|
|
11
20
|
import { Services } from "@modules/{{moduleNameKebab}}/application/domain/services";
|
|
12
21
|
|
|
22
|
+
// Application - Controllers
|
|
23
|
+
import { Controllers } from "@modules/{{moduleNameKebab}}/application/controllers";
|
|
24
|
+
|
|
13
25
|
@Module({
|
|
14
|
-
imports: [
|
|
26
|
+
imports: [
|
|
27
|
+
TypeOrmModule.forFeature([...OrmEntities]),
|
|
28
|
+
CqrsModule,
|
|
29
|
+
],
|
|
30
|
+
controllers: [...Controllers],
|
|
15
31
|
providers: [
|
|
32
|
+
// CQRS handlers
|
|
16
33
|
...CommandHandlers,
|
|
17
34
|
...Queries,
|
|
18
|
-
|
|
19
|
-
...Mappers,
|
|
35
|
+
// Domain layer
|
|
20
36
|
...UseCases,
|
|
21
37
|
...Services,
|
|
38
|
+
// Infrastructure layer
|
|
39
|
+
...Repositories,
|
|
40
|
+
...Mappers,
|
|
41
|
+
],
|
|
42
|
+
exports: [
|
|
43
|
+
// Export repositories for use in other modules
|
|
44
|
+
...Repositories,
|
|
45
|
+
// Export mappers for use in other modules
|
|
46
|
+
...Mappers,
|
|
22
47
|
],
|
|
23
|
-
controllers: [...Controllers],
|
|
24
48
|
})
|
|
25
|
-
export class {{
|
|
49
|
+
export class {{moduleNamePascal}}Module {}
|