eva4j 1.0.13 → 1.0.15
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/AGENTS.md +314 -10
- package/COMMAND_EVALUATION.md +15 -16
- package/DOMAIN_YAML_GUIDE.md +576 -10
- package/FUTURE_FEATURES.md +1627 -1168
- package/README.md +318 -13
- package/bin/eva4j.js +34 -0
- package/config/defaults.json +1 -0
- package/design-system.md +797 -0
- package/docs/commands/EVALUATE_SYSTEM.md +994 -0
- package/docs/commands/GENERATE_ENTITIES.md +795 -6
- package/docs/commands/INDEX.md +10 -1
- package/examples/domain-endpoints-relations.yaml +353 -0
- package/examples/domain-endpoints-versioned.yaml +144 -0
- package/examples/domain-endpoints.yaml +135 -0
- package/examples/domain-events.yaml +166 -20
- package/examples/domain-listeners.yaml +212 -0
- package/examples/domain-one-to-many.yaml +1 -0
- package/examples/domain-one-to-one.yaml +1 -0
- package/examples/domain-ports.yaml +414 -0
- package/examples/domain-soft-delete.yaml +47 -44
- package/examples/system/notification.yaml +147 -0
- package/examples/system/product.yaml +185 -0
- package/examples/system/system.yaml +112 -0
- package/examples/system-report.html +971 -0
- package/examples/system.yaml +332 -0
- package/package.json +2 -1
- package/src/commands/build.js +714 -0
- package/src/commands/create.js +7 -3
- package/src/commands/detach.js +1 -0
- package/src/commands/evaluate-system.js +610 -0
- package/src/commands/generate-entities.js +1331 -49
- package/src/commands/generate-http-exchange.js +2 -0
- package/src/commands/generate-kafka-event.js +98 -11
- package/src/generators/base-generator.js +8 -1
- package/src/generators/postman-generator.js +188 -0
- package/src/generators/shared-generator.js +10 -0
- package/src/utils/config-manager.js +54 -0
- package/src/utils/context-builder.js +1 -0
- package/src/utils/domain-diagram.js +192 -0
- package/src/utils/domain-validator.js +970 -0
- package/src/utils/fake-data.js +376 -0
- package/src/utils/naming.js +3 -2
- package/src/utils/system-validator.js +434 -0
- package/src/utils/yaml-to-entity.js +302 -8
- package/templates/aggregate/AggregateMapper.java.ejs +3 -2
- package/templates/aggregate/AggregateRepository.java.ejs +8 -2
- package/templates/aggregate/AggregateRepositoryImpl.java.ejs +13 -3
- package/templates/aggregate/AggregateRoot.java.ejs +60 -2
- package/templates/aggregate/DomainEventHandler.java.ejs +27 -20
- package/templates/aggregate/DomainEventRecord.java.ejs +24 -8
- package/templates/aggregate/DomainEventSnapshot.java.ejs +46 -0
- package/templates/aggregate/JpaAggregateRoot.java.ejs +6 -0
- package/templates/aggregate/JpaRepository.java.ejs +5 -0
- package/templates/base/gradle/build.gradle.ejs +3 -2
- package/templates/base/root/AGENTS.md.ejs +306 -45
- package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1663 -0
- package/templates/base/root/skill-build-system-yaml.ejs +1446 -0
- package/templates/base/root/system.yaml.ejs +97 -0
- package/templates/crud/ApplicationMapper.java.ejs +4 -0
- package/templates/crud/Controller.java.ejs +4 -4
- package/templates/crud/CreateCommand.java.ejs +4 -0
- package/templates/crud/CreateItemDto.java.ejs +4 -0
- package/templates/crud/CreateValueObjectDto.java.ejs +4 -0
- package/templates/crud/DeleteCommandHandler.java.ejs +10 -2
- package/templates/crud/EndpointsController.java.ejs +178 -0
- package/templates/crud/FindByQuery.java.ejs +17 -0
- package/templates/crud/FindByQueryHandler.java.ejs +57 -0
- package/templates/crud/ListQuery.java.ejs +1 -1
- package/templates/crud/ListQueryHandler.java.ejs +8 -8
- package/templates/crud/ScaffoldCommand.java.ejs +12 -0
- package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
- package/templates/crud/ScaffoldQuery.java.ejs +13 -0
- package/templates/crud/ScaffoldQueryHandler.java.ejs +41 -0
- package/templates/crud/SubEntityAddCommand.java.ejs +21 -0
- package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
- package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
- package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
- package/templates/crud/TransitionCommand.java.ejs +9 -0
- package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
- package/templates/crud/UpdateCommand.java.ejs +4 -0
- package/templates/evaluate/report.html.ejs +1363 -0
- package/templates/kafka-event/DomainEventHandlerMethod.ejs +3 -1
- package/templates/kafka-event/Event.java.ejs +16 -0
- package/templates/kafka-listener/KafkaController.java.ejs +1 -1
- package/templates/kafka-listener/KafkaListenerClass.java.ejs +1 -1
- package/templates/kafka-listener/ListenerClass.java.ejs +65 -0
- package/templates/kafka-listener/ListenerCommand.java.ejs +31 -0
- package/templates/kafka-listener/ListenerCommandHandler.java.ejs +23 -0
- package/templates/kafka-listener/ListenerIntegrationEvent.java.ejs +37 -0
- package/templates/kafka-listener/ListenerMethod.java.ejs +1 -1
- package/templates/kafka-listener/ListenerNestedType.java.ejs +28 -0
- package/templates/mock/MockEvent.java.ejs +10 -0
- package/templates/mock/MockMessageBrokerImpl.java.ejs +35 -0
- package/templates/mock/MockMessageBrokerImplMethod.java.ejs +6 -0
- package/templates/mock/SpringEventListener.java.ejs +61 -0
- package/templates/ports/PortDomainModel.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +67 -0
- package/templates/ports/PortFeignClient.java.ejs +45 -0
- package/templates/ports/PortFeignConfig.java.ejs +24 -0
- package/templates/ports/PortInterface.java.ejs +45 -0
- package/templates/ports/PortNestedType.java.ejs +28 -0
- package/templates/ports/PortRequestDto.java.ejs +30 -0
- package/templates/ports/PortResponseDto.java.ejs +28 -0
- package/templates/postman/Collection.json.ejs +1 -1
- package/templates/postman/UnifiedCollection.json.ejs +185 -0
- package/templates/shared/configurations/eventPublicationConfig/EventPublicationSchemaConfig.java.ejs +109 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# system.yaml
|
|
2
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# Archivo de arquitectura del sistema — System-First Development con eva4j
|
|
4
|
+
#
|
|
5
|
+
# Describe qué módulos existen, qué exponen y cómo se comunican entre sí.
|
|
6
|
+
# Los campos de dominio (aggregates, events, ports) se declaran en domain.yaml.
|
|
7
|
+
#
|
|
8
|
+
# Comandos disponibles:
|
|
9
|
+
# eva system validate → valida coherencia del grafo (referencias, ciclos)
|
|
10
|
+
# eva generate system → genera módulos + domain.yaml con endpoints: pre-generado
|
|
11
|
+
# eva system diagram → genera diagrama Mermaid del sistema
|
|
12
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
system:
|
|
15
|
+
name: <%= projectName %>
|
|
16
|
+
groupId: <%= groupId %>
|
|
17
|
+
javaVersion: <%= javaVersion %>
|
|
18
|
+
springBootVersion: <%= springBootVersion %>
|
|
19
|
+
database: <%= databaseType %>
|
|
20
|
+
|
|
21
|
+
# messaging: # Descomentar si el sistema usa mensajería asíncrona
|
|
22
|
+
# enabled: true
|
|
23
|
+
# broker: kafka # kafka | rabbitmq | sns-sqs
|
|
24
|
+
# kafka:
|
|
25
|
+
# bootstrapServers: localhost:9092
|
|
26
|
+
# defaultGroupId: <%= projectName %>
|
|
27
|
+
# topicPrefix: <%= projectName %> # prefija todos los topics: <%= projectName %>.ORDER_PLACED
|
|
28
|
+
|
|
29
|
+
modules:
|
|
30
|
+
# Declara cada módulo del sistema (nombre en plural, kebab-case).
|
|
31
|
+
# eva generate system genera por cada módulo: carpeta + domain.yaml con endpoints: pre-generado.
|
|
32
|
+
#
|
|
33
|
+
# - name: orders
|
|
34
|
+
# description: "Gestión del ciclo de vida de pedidos"
|
|
35
|
+
# exposes:
|
|
36
|
+
# - method: GET
|
|
37
|
+
# path: /orders/{id}
|
|
38
|
+
# useCase: GetOrder # PascalCase — alimenta endpoints: en domain.yaml
|
|
39
|
+
# description: "Obtener pedido por ID"
|
|
40
|
+
# - method: GET
|
|
41
|
+
# path: /orders
|
|
42
|
+
# useCase: FindAllOrders
|
|
43
|
+
# description: "Listar pedidos con filtros y paginación"
|
|
44
|
+
# - method: POST
|
|
45
|
+
# path: /orders
|
|
46
|
+
# useCase: CreateOrder
|
|
47
|
+
# description: "Crear nuevo pedido"
|
|
48
|
+
# - method: PUT
|
|
49
|
+
# path: /orders/{id}/confirm
|
|
50
|
+
# useCase: ConfirmOrder
|
|
51
|
+
# description: "Confirmar pedido pendiente"
|
|
52
|
+
# - method: PUT
|
|
53
|
+
# path: /orders/{id}/cancel
|
|
54
|
+
# useCase: CancelOrder
|
|
55
|
+
# description: "Cancelar pedido (PENDING o CONFIRMED)"
|
|
56
|
+
#
|
|
57
|
+
# - name: customers
|
|
58
|
+
# description: "Registro y gestión de clientes"
|
|
59
|
+
# exposes:
|
|
60
|
+
# - method: GET
|
|
61
|
+
# path: /customers/{id}
|
|
62
|
+
# useCase: GetCustomer
|
|
63
|
+
# description: "Obtener cliente por ID"
|
|
64
|
+
# - method: POST
|
|
65
|
+
# path: /customers
|
|
66
|
+
# useCase: CreateCustomer
|
|
67
|
+
# description: "Registrar nuevo cliente"
|
|
68
|
+
#
|
|
69
|
+
# - name: notifications
|
|
70
|
+
# description: "Envío de notificaciones"
|
|
71
|
+
# # Sin endpoints REST — solo consume eventos
|
|
72
|
+
|
|
73
|
+
# integrations:
|
|
74
|
+
# async:
|
|
75
|
+
# # Eventos asíncronos entre módulos.
|
|
76
|
+
# # Los campos del evento se declaran en domain.yaml → events[].fields del productor.
|
|
77
|
+
# - event: OrderPlacedEvent
|
|
78
|
+
# producer: orders
|
|
79
|
+
# topic: ORDER_PLACED
|
|
80
|
+
# consumers:
|
|
81
|
+
# - module: payments
|
|
82
|
+
# - module: notifications
|
|
83
|
+
#
|
|
84
|
+
# - event: PaymentProcessedEvent
|
|
85
|
+
# producer: payments
|
|
86
|
+
# topic: PAYMENT_PROCESSED
|
|
87
|
+
# consumers:
|
|
88
|
+
# - module: orders
|
|
89
|
+
#
|
|
90
|
+
# sync:
|
|
91
|
+
# # Llamadas HTTP síncronas entre módulos.
|
|
92
|
+
# # El shape del DTO de respuesta se declara en domain.yaml → ports[] del caller.
|
|
93
|
+
# - caller: orders
|
|
94
|
+
# calls: customers
|
|
95
|
+
# port: CustomerService
|
|
96
|
+
# using:
|
|
97
|
+
# - GET /customers/{id}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package <%= packageName %>.<%= moduleName %>.application.mappers;
|
|
2
2
|
|
|
3
|
+
<% if (hasCreateOperation) { %>
|
|
3
4
|
import <%= packageName %>.<%= moduleName %>.application.commands.Create<%= aggregateName %>Command;
|
|
5
|
+
<% } %>
|
|
4
6
|
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
5
7
|
<% secondaryEntities.forEach(entity => { %>
|
|
6
8
|
import <%= packageName %>.<%= moduleName %>.application.dtos.Create<%= entity.name %>Dto;
|
|
@@ -31,6 +33,7 @@ public class <%= aggregateName %>ApplicationMapper {
|
|
|
31
33
|
|
|
32
34
|
// ========== Command to Domain Mapping ==========
|
|
33
35
|
|
|
36
|
+
<% if (hasCreateOperation) { %>
|
|
34
37
|
/**
|
|
35
38
|
* Convert Create<%= aggregateName %>Command to <%= aggregateName %> domain entity
|
|
36
39
|
*/
|
|
@@ -98,6 +101,7 @@ public class <%= aggregateName %>ApplicationMapper {
|
|
|
98
101
|
<% } %>
|
|
99
102
|
return entity;
|
|
100
103
|
}
|
|
104
|
+
<% } %>
|
|
101
105
|
<% if (oneToManyRelationships && oneToManyRelationships.length > 0) { %>
|
|
102
106
|
<% oneToManyRelationships.forEach(rel => { %>
|
|
103
107
|
|
|
@@ -4,7 +4,7 @@ import <%= packageName %>.<%= moduleName %>.application.commands.Create<%= aggre
|
|
|
4
4
|
import <%= packageName %>.<%= moduleName %>.application.commands.Delete<%= aggregateName %>Command;
|
|
5
5
|
import <%= packageName %>.<%= moduleName %>.application.commands.Update<%= aggregateName %>Command;
|
|
6
6
|
import <%= packageName %>.<%= moduleName %>.application.queries.Get<%= aggregateName %>Query;
|
|
7
|
-
import <%= packageName %>.<%= moduleName %>.application.queries.FindAll<%=
|
|
7
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.FindAll<%= aggregateNamePlural %>Query;
|
|
8
8
|
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
9
9
|
import <%= packageName %>.shared.application.dtos.PagedResponse;
|
|
10
10
|
import <%= packageName %>.shared.infrastructure.configurations.useCaseConfig.UseCaseMediator;
|
|
@@ -49,15 +49,15 @@ public class <%= aggregateName %>Controller {
|
|
|
49
49
|
|
|
50
50
|
@GetMapping
|
|
51
51
|
@ResponseStatus(HttpStatus.OK)
|
|
52
|
-
@Operation(summary = "Get all <%=
|
|
52
|
+
@Operation(summary = "Get all <%= aggregateNamePlural %> (paginated)")
|
|
53
53
|
public PagedResponse<<%= aggregateName %>ResponseDto> findAll(
|
|
54
54
|
@RequestParam(defaultValue = "0") int page,
|
|
55
55
|
@RequestParam(defaultValue = "20") int size,
|
|
56
56
|
@RequestParam(defaultValue = "id") String sortBy,
|
|
57
57
|
@RequestParam(defaultValue = "ASC") String sortDirection) {
|
|
58
|
-
log.info("Finding all <%=
|
|
58
|
+
log.info("Finding all <%= aggregateNamePlural %> — page={}, size={}, sortBy={}, sortDirection={}",
|
|
59
59
|
page, size, sortBy, sortDirection);
|
|
60
|
-
return useCaseMediator.dispatch(new FindAll<%=
|
|
60
|
+
return useCaseMediator.dispatch(new FindAll<%= aggregateNamePlural %>Query(page, size, sortBy, sortDirection));
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
@DeleteMapping("/{id}")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package <%= packageName %>.<%= moduleName %>.application.commands;
|
|
2
2
|
|
|
3
3
|
import <%= packageName %>.shared.domain.interfaces.Command;
|
|
4
|
+
import io.swagger.v3.oas.annotations.media.Schema;
|
|
4
5
|
<% if (hasValueObjects) { %>
|
|
5
6
|
import <%= packageName %>.<%= moduleName %>.domain.models.valueObjects.*;
|
|
6
7
|
<% } %>
|
|
@@ -29,6 +30,9 @@ public record Create<%= aggregateName %>Command(
|
|
|
29
30
|
<% (field.validationAnnotations || []).forEach(annotation => { %>
|
|
30
31
|
<%- annotation %>
|
|
31
32
|
<% }); %>
|
|
33
|
+
<% if (field.schemaExample) { %>
|
|
34
|
+
@Schema(example = "<%= field.schemaExample %>")
|
|
35
|
+
<% } %>
|
|
32
36
|
<%- field.javaType %> <%= field.name %><% if (idx < commandFields.length - 1 || (oneToManyRelationships && oneToManyRelationships.length > 0) || (oneToOneRelationships && oneToOneRelationships.length > 0)) { %>,<% } %>
|
|
33
37
|
<% }); %>
|
|
34
38
|
<% if (oneToManyRelationships && oneToManyRelationships.length > 0) { %>
|
|
@@ -9,6 +9,7 @@ import <%= packageName %>.<%= moduleName %>.domain.models.enums.*;
|
|
|
9
9
|
<% if (hasNestedRelationships || fields.some(f => f.isCollection)) { %>
|
|
10
10
|
import java.util.List;
|
|
11
11
|
<% } %>
|
|
12
|
+
import io.swagger.v3.oas.annotations.media.Schema;
|
|
12
13
|
<% imports.forEach(imp => { %>
|
|
13
14
|
<%- imp %>
|
|
14
15
|
<% }); %>
|
|
@@ -18,6 +19,9 @@ public record Create<%= entityName %>Dto(
|
|
|
18
19
|
<% (field.validationAnnotations || []).forEach(annotation => { %>
|
|
19
20
|
<%- annotation %>
|
|
20
21
|
<% }); %>
|
|
22
|
+
<% if (field.schemaExample) { %>
|
|
23
|
+
@Schema(example = "<%= field.schemaExample %>")
|
|
24
|
+
<% } %>
|
|
21
25
|
<%- field.javaType %> <%= field.name %><% if (idx < fields.length - 1 || hasNestedRelationships || (forwardOneToOneRels && forwardOneToOneRels.length > 0)) { %>,<% } %>
|
|
22
26
|
<% }); %>
|
|
23
27
|
<% if (hasNestedRelationships) { %>
|
|
@@ -3,6 +3,7 @@ package <%= packageName %>.<%= moduleName %>.application.dtos;
|
|
|
3
3
|
<% if (hasEnums) { %>
|
|
4
4
|
import <%= packageName %>.<%= moduleName %>.domain.models.enums.*;
|
|
5
5
|
<% } %>
|
|
6
|
+
import io.swagger.v3.oas.annotations.media.Schema;
|
|
6
7
|
<% imports.forEach(imp => { %>
|
|
7
8
|
<%- imp %>
|
|
8
9
|
<% }); %>
|
|
@@ -12,6 +13,9 @@ public record Create<%= voName %>Dto(
|
|
|
12
13
|
<% (field.validationAnnotations || []).forEach(annotation => { %>
|
|
13
14
|
<%- annotation %>
|
|
14
15
|
<% }); %>
|
|
16
|
+
<% if (field.schemaExample) { %>
|
|
17
|
+
@Schema(example = "<%= field.schemaExample %>")
|
|
18
|
+
<% } %>
|
|
15
19
|
<%- field.javaType %> <%= field.name %><% if (idx < fields.length - 1) { %>,<% } %>
|
|
16
20
|
<% }); %>
|
|
17
21
|
) {
|
|
@@ -2,6 +2,9 @@ package <%= packageName %>.<%= moduleName %>.application.usecases;
|
|
|
2
2
|
|
|
3
3
|
import <%= packageName %>.<%= moduleName %>.application.commands.Delete<%= aggregateName %>Command;
|
|
4
4
|
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= aggregateName %>Repository;
|
|
5
|
+
<% if (hasSoftDelete) { %>
|
|
6
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.entities.<%= aggregateName %>;
|
|
7
|
+
<% } %>
|
|
5
8
|
import <%= packageName %>.shared.domain.annotations.ApplicationComponent;
|
|
6
9
|
import <%= packageName %>.shared.domain.customExceptions.NotFoundException;
|
|
7
10
|
import <%= packageName %>.shared.domain.interfaces.CommandHandler;
|
|
@@ -26,12 +29,17 @@ public class Delete<%= aggregateName %>CommandHandler implements CommandHandler<
|
|
|
26
29
|
@Transactional
|
|
27
30
|
public void handle(Delete<%= aggregateName %>Command command) {
|
|
28
31
|
log.info("Handling Delete<%= aggregateName %>Command for id: {}", command.id());
|
|
29
|
-
|
|
32
|
+
<% if (hasSoftDelete) { %>
|
|
33
|
+
<%= aggregateName %> entity = repository.findById(command.id())
|
|
34
|
+
.orElseThrow(() -> new NotFoundException("<%= aggregateName %> not found with id: " + command.id()));
|
|
35
|
+
entity.softDelete();
|
|
36
|
+
repository.save(entity);
|
|
37
|
+
<% } else { %>
|
|
30
38
|
if (!repository.existsById(command.id())) {
|
|
31
39
|
throw new NotFoundException("<%= aggregateName %> not found with id: " + command.id());
|
|
32
40
|
}
|
|
33
|
-
|
|
34
41
|
repository.deleteById(command.id());
|
|
42
|
+
<% } %>
|
|
35
43
|
log.info("<%= aggregateName %> deleted successfully with id: {}", command.id());
|
|
36
44
|
}
|
|
37
45
|
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<%
|
|
2
|
+
// ── Classify operations for selective imports ────────────────────────────
|
|
3
|
+
const uniqueOpsMap = new Map();
|
|
4
|
+
operations.forEach(op => { if (!uniqueOpsMap.has(op.useCase)) uniqueOpsMap.set(op.useCase, op); });
|
|
5
|
+
const uniqueOps = Array.from(uniqueOpsMap.values());
|
|
6
|
+
|
|
7
|
+
const hasCreate = uniqueOps.some(op => op.isStandard && op.standardType === 'create');
|
|
8
|
+
const hasUpdate = uniqueOps.some(op => op.isStandard && op.standardType === 'update');
|
|
9
|
+
const hasDelete = uniqueOps.some(op => op.isStandard && op.standardType === 'delete');
|
|
10
|
+
const hasGetById = uniqueOps.some(op => op.isStandard && op.standardType === 'getById');
|
|
11
|
+
const hasFindAll = uniqueOps.some(op => op.isStandard && op.standardType === 'findAll');
|
|
12
|
+
const hasTransition = uniqueOps.some(op => op.classifiedType === 'transition');
|
|
13
|
+
const hasSubAdd = uniqueOps.some(op => op.classifiedType === 'subEntityAdd');
|
|
14
|
+
const hasSubRemove = uniqueOps.some(op => op.classifiedType === 'subEntityRemove');
|
|
15
|
+
const hasFindBy = uniqueOps.some(op => op.classifiedType === 'findBy');
|
|
16
|
+
|
|
17
|
+
const transitionOps = uniqueOps.filter(op => op.classifiedType === 'transition');
|
|
18
|
+
const subAddOps = uniqueOps.filter(op => op.classifiedType === 'subEntityAdd');
|
|
19
|
+
const subRemoveOps = uniqueOps.filter(op => op.classifiedType === 'subEntityRemove');
|
|
20
|
+
const findByOps = uniqueOps.filter(op => op.classifiedType === 'findBy');
|
|
21
|
+
const customCmdUCs = uniqueOps.filter(op => op.classifiedType === 'scaffold' && op.type !== 'query');
|
|
22
|
+
const customQueryUCs = uniqueOps.filter(op => op.classifiedType === 'scaffold' && op.type === 'query');
|
|
23
|
+
-%>
|
|
24
|
+
package <%= packageName %>.<%= moduleName %>.infrastructure.rest.controllers.<%= resourceNameCamel %>.<%= apiVersion %>;
|
|
25
|
+
|
|
26
|
+
<% if (hasCreate) { -%>
|
|
27
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.Create<%= aggregateName %>Command;
|
|
28
|
+
<% } -%>
|
|
29
|
+
<% if (hasUpdate) { -%>
|
|
30
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.Update<%= aggregateName %>Command;
|
|
31
|
+
<% } -%>
|
|
32
|
+
<% if (hasDelete) { -%>
|
|
33
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.Delete<%= aggregateName %>Command;
|
|
34
|
+
<% } -%>
|
|
35
|
+
<% if (hasGetById) { -%>
|
|
36
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.Get<%= aggregateName %>Query;
|
|
37
|
+
<% } -%>
|
|
38
|
+
<% if (hasFindAll) { -%>
|
|
39
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.FindAll<%= aggregateNamePlural %>Query;
|
|
40
|
+
<% } -%>
|
|
41
|
+
<% customCmdUCs.forEach(function(op) { -%>
|
|
42
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.<%= op.useCase %>Command;
|
|
43
|
+
<% }); -%>
|
|
44
|
+
<% customQueryUCs.forEach(function(op) { -%>
|
|
45
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.<%= op.useCase %>Query;
|
|
46
|
+
<% }); -%>
|
|
47
|
+
<% transitionOps.forEach(function(op) { -%>
|
|
48
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.<%= op.useCase %>Command;
|
|
49
|
+
<% }); -%>
|
|
50
|
+
<% subAddOps.forEach(function(op) { -%>
|
|
51
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.<%= op.useCase %>Command;
|
|
52
|
+
<% }); -%>
|
|
53
|
+
<% subRemoveOps.forEach(function(op) { -%>
|
|
54
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.<%= op.useCase %>Command;
|
|
55
|
+
<% }); -%>
|
|
56
|
+
<% findByOps.forEach(function(op) { -%>
|
|
57
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.<%= op.useCase %>Query;
|
|
58
|
+
<% }); -%>
|
|
59
|
+
<% if (hasGetById || hasFindAll || hasFindBy || customQueryUCs.length > 0) { -%>
|
|
60
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
61
|
+
<% } -%>
|
|
62
|
+
<% if (hasFindAll || hasFindBy) { -%>
|
|
63
|
+
import <%= packageName %>.shared.application.dtos.PagedResponse;
|
|
64
|
+
<% } -%>
|
|
65
|
+
import <%= packageName %>.shared.infrastructure.configurations.useCaseConfig.UseCaseMediator;
|
|
66
|
+
|
|
67
|
+
import io.swagger.v3.oas.annotations.Operation;
|
|
68
|
+
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
69
|
+
import jakarta.validation.Valid;
|
|
70
|
+
import lombok.extern.slf4j.Slf4j;
|
|
71
|
+
import org.springframework.http.HttpStatus;
|
|
72
|
+
import org.springframework.web.bind.annotation.*;
|
|
73
|
+
|
|
74
|
+
@RestController
|
|
75
|
+
@RequestMapping("/api/<%= apiVersion %><%= basePath %>")
|
|
76
|
+
@Slf4j
|
|
77
|
+
@Tag(name = "<%= aggregateName %>", description = "<%= aggregateName %> Management API")
|
|
78
|
+
public class <%= controllerName %> {
|
|
79
|
+
|
|
80
|
+
private final UseCaseMediator useCaseMediator;
|
|
81
|
+
|
|
82
|
+
public <%= controllerName %>(UseCaseMediator useCaseMediator) {
|
|
83
|
+
this.useCaseMediator = useCaseMediator;
|
|
84
|
+
}
|
|
85
|
+
<% operations.forEach(function(op) { %>
|
|
86
|
+
/**
|
|
87
|
+
* <%= op.description || op.useCase %>
|
|
88
|
+
*/
|
|
89
|
+
@<%- op.httpAnnotation %>(<% if (op.path && op.path !== '/') { %>"<%= op.path %>"<% } %>)
|
|
90
|
+
@ResponseStatus(<%= op.httpStatus %>)
|
|
91
|
+
@Operation(summary = "<%= op.description || op.useCase %>")
|
|
92
|
+
<% if (op.isStandard && op.standardType === 'create') { %>
|
|
93
|
+
public void <%= op.methodName %>(@Valid @RequestBody Create<%= aggregateName %>Command command) {
|
|
94
|
+
log.info("Creating <%= aggregateName %>: {}", command);
|
|
95
|
+
useCaseMediator.dispatch(command);
|
|
96
|
+
}
|
|
97
|
+
<% } else if (op.isStandard && op.standardType === 'getById') { %>
|
|
98
|
+
public <%= aggregateName %>ResponseDto <%= op.methodName %>(@PathVariable <%- idType %> id) {
|
|
99
|
+
log.info("Finding <%= aggregateName %> by id: {}", id);
|
|
100
|
+
return useCaseMediator.dispatch(new Get<%= aggregateName %>Query(id));
|
|
101
|
+
}
|
|
102
|
+
<% } else if (op.isStandard && op.standardType === 'findAll') { %>
|
|
103
|
+
public PagedResponse<<%= aggregateName %>ResponseDto> <%= op.methodName %>(
|
|
104
|
+
@RequestParam(defaultValue = "0") int page,
|
|
105
|
+
@RequestParam(defaultValue = "20") int size,
|
|
106
|
+
@RequestParam(defaultValue = "id") String sortBy,
|
|
107
|
+
@RequestParam(defaultValue = "ASC") String sortDirection) {
|
|
108
|
+
log.info("Finding all <%= aggregateNamePlural %> — page={}, size={}, sortBy={}, sortDirection={}",
|
|
109
|
+
page, size, sortBy, sortDirection);
|
|
110
|
+
return useCaseMediator.dispatch(new FindAll<%= aggregateNamePlural %>Query(page, size, sortBy, sortDirection));
|
|
111
|
+
}
|
|
112
|
+
<% } else if (op.isStandard && op.standardType === 'delete') { %>
|
|
113
|
+
public void <%= op.methodName %>(@PathVariable <%- idType %> id) {
|
|
114
|
+
log.info("Deleting <%= aggregateName %> id: {}", id);
|
|
115
|
+
useCaseMediator.dispatch(new Delete<%= aggregateName %>Command(id));
|
|
116
|
+
}
|
|
117
|
+
<% } else if (op.isStandard && op.standardType === 'update') { %>
|
|
118
|
+
public void <%= op.methodName %>(
|
|
119
|
+
@PathVariable <%- idType %> id,
|
|
120
|
+
@RequestBody Update<%= aggregateName %>Command command) {
|
|
121
|
+
log.info("Updating <%= aggregateName %> id: {}", id);
|
|
122
|
+
useCaseMediator.dispatch(new Update<%= aggregateName %>Command(
|
|
123
|
+
id<% if (commandFields && commandFields.length > 0) { %>,<% } %>
|
|
124
|
+
<% (commandFields || []).forEach(function(field, idx) { %>
|
|
125
|
+
command.<%= field.name %>()<% if (idx < commandFields.length - 1 || (oneToManyRelationships && oneToManyRelationships.length > 0) || (oneToOneRelationships && oneToOneRelationships.length > 0)) { %>,<% } %>
|
|
126
|
+
<% }); %>
|
|
127
|
+
<% if (oneToManyRelationships && oneToManyRelationships.length > 0) { %>
|
|
128
|
+
<% oneToManyRelationships.forEach(function(rel, idx) { %>
|
|
129
|
+
command.<%= rel.fieldName %>()<% if (idx < oneToManyRelationships.length - 1 || (oneToOneRelationships && oneToOneRelationships.length > 0)) { %>,<% } %>
|
|
130
|
+
<% }); %>
|
|
131
|
+
<% } %>
|
|
132
|
+
<% if (oneToOneRelationships && oneToOneRelationships.length > 0) { %>
|
|
133
|
+
<% oneToOneRelationships.forEach(function(rel, idx) { %>
|
|
134
|
+
command.<%= rel.fieldName %>()<% if (idx < oneToOneRelationships.length - 1) { %>,<% } %>
|
|
135
|
+
<% }); %>
|
|
136
|
+
<% } %>
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
<% } else if (op.classifiedType === 'transition') { %>
|
|
140
|
+
public void <%= op.methodName %>(@PathVariable <%- op.idType %> id) {
|
|
141
|
+
log.info("Handling <%= op.useCase %> for <%= aggregateName %> id: {}", id);
|
|
142
|
+
useCaseMediator.dispatch(new <%= op.useCase %>Command(id));
|
|
143
|
+
}
|
|
144
|
+
<% } else if (op.classifiedType === 'subEntityAdd') { %>
|
|
145
|
+
public void <%= op.methodName %>(@PathVariable <%- op.idType %> id, @Valid @RequestBody <%= op.useCase %>Command command) {
|
|
146
|
+
log.info("Handling <%= op.useCase %> for <%= aggregateName %> id: {}", id);
|
|
147
|
+
useCaseMediator.dispatch(new <%= op.useCase %>Command(id<% if (op.classification && op.classification.entityFields && op.classification.entityFields.length > 0) { %>, <% op.classification.entityFields.forEach(function(f, idx) { %>command.<%= f.name %>()<% if (idx < op.classification.entityFields.length - 1) { %>, <% } %><% }); %><% } %>));
|
|
148
|
+
}
|
|
149
|
+
<% } else if (op.classifiedType === 'subEntityRemove') { %>
|
|
150
|
+
public void <%= op.methodName %>(@PathVariable <%- op.idType %> id, @PathVariable String itemId) {
|
|
151
|
+
log.info("Handling <%= op.useCase %> for <%= aggregateName %> id: {}, itemId: {}", id, itemId);
|
|
152
|
+
useCaseMediator.dispatch(new <%= op.useCase %>Command(id, itemId));
|
|
153
|
+
}
|
|
154
|
+
<% } else if (op.classifiedType === 'findBy') { %>
|
|
155
|
+
public PagedResponse<<%= aggregateName %>ResponseDto> <%= op.methodName %>(
|
|
156
|
+
@RequestParam <%- op.classification.fieldJavaType %> <%= op.classification.fieldName %>,
|
|
157
|
+
@RequestParam(defaultValue = "0") int page,
|
|
158
|
+
@RequestParam(defaultValue = "20") int size,
|
|
159
|
+
@RequestParam(defaultValue = "id") String sortBy,
|
|
160
|
+
@RequestParam(defaultValue = "ASC") String sortDirection) {
|
|
161
|
+
log.info("Handling <%= op.useCase %> — <%= op.classification.fieldName %>={}, page={}, size={}", <%= op.classification.fieldName %>, page, size);
|
|
162
|
+
return useCaseMediator.dispatch(new <%= op.useCase %>Query(<%= op.classification.fieldName %>, page, size, sortBy, sortDirection));
|
|
163
|
+
}
|
|
164
|
+
<% } else if (op.type === 'command') { %>
|
|
165
|
+
// TODO: Review the fields declared in <%= op.useCase %>Command and adapt the method signature if needed
|
|
166
|
+
public void <%= op.methodName %>(<% if (op.hasPathVar) { %>@PathVariable <%- op.idType %> <%= op.pathVarName %>, <% } %>@Valid @RequestBody <%= op.useCase %>Command command) {
|
|
167
|
+
log.info("Handling <%= op.useCase %>: {}", command);
|
|
168
|
+
useCaseMediator.dispatch(command);
|
|
169
|
+
}
|
|
170
|
+
<% } else { %>
|
|
171
|
+
// TODO: Review the parameters in <%= op.useCase %>Query and adapt the return type if needed
|
|
172
|
+
public <%- op.returnType %> <%= op.methodName %>(<% if (op.hasPathVar) { %>@PathVariable <%- op.idType %> <%= op.pathVarName %><% } %>) {
|
|
173
|
+
log.info("Handling <%= op.useCase %>");
|
|
174
|
+
return useCaseMediator.dispatch(new <%= op.useCase %>Query(<% if (op.hasPathVar) { %><%= op.pathVarName %><% } %>));
|
|
175
|
+
}
|
|
176
|
+
<% } -%>
|
|
177
|
+
<% }); %>
|
|
178
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.queries;
|
|
2
|
+
|
|
3
|
+
import <%= packageName %>.shared.domain.interfaces.Query;
|
|
4
|
+
import <%= packageName %>.shared.application.dtos.PagedResponse;
|
|
5
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* <%= useCaseName %>Query
|
|
9
|
+
* Returns a paginated list of <%= aggregateNamePlural %> filtered by <%= fieldName %>.
|
|
10
|
+
*/
|
|
11
|
+
public record <%= useCaseName %>Query(
|
|
12
|
+
<%- fieldJavaType %> <%= fieldName %>,
|
|
13
|
+
int page,
|
|
14
|
+
int size,
|
|
15
|
+
String sortBy,
|
|
16
|
+
String sortDirection
|
|
17
|
+
) implements Query<PagedResponse<<%= aggregateName %>ResponseDto>> {}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.usecases;
|
|
2
|
+
|
|
3
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.<%= useCaseName %>Query;
|
|
4
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
5
|
+
import <%= packageName %>.<%= moduleName %>.application.mappers.<%= aggregateName %>ApplicationMapper;
|
|
6
|
+
import <%= packageName %>.<%= moduleName %>.domain.models.entities.<%= aggregateName %>;
|
|
7
|
+
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= aggregateName %>Repository;
|
|
8
|
+
import <%= packageName %>.shared.application.dtos.PagedResponse;
|
|
9
|
+
import <%= packageName %>.shared.domain.annotations.ApplicationComponent;
|
|
10
|
+
import <%= packageName %>.shared.domain.interfaces.QueryHandler;
|
|
11
|
+
import lombok.extern.slf4j.Slf4j;
|
|
12
|
+
import org.springframework.data.domain.Page;
|
|
13
|
+
import org.springframework.data.domain.PageRequest;
|
|
14
|
+
import org.springframework.data.domain.Pageable;
|
|
15
|
+
import org.springframework.data.domain.Sort;
|
|
16
|
+
import org.springframework.transaction.annotation.Transactional;
|
|
17
|
+
|
|
18
|
+
import java.util.List;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* <%= useCaseName %>QueryHandler
|
|
22
|
+
* Returns paginated <%= aggregateNamePlural %> filtered by <%= fieldName %>.
|
|
23
|
+
* Calls repository.<%= jpaMethodName %>(<%= fieldName %>, pageable).
|
|
24
|
+
*/
|
|
25
|
+
@Slf4j
|
|
26
|
+
@ApplicationComponent
|
|
27
|
+
public class <%= useCaseName %>QueryHandler implements QueryHandler<<%= useCaseName %>Query, PagedResponse<<%= aggregateName %>ResponseDto>> {
|
|
28
|
+
|
|
29
|
+
private final <%= aggregateName %>Repository repository;
|
|
30
|
+
private final <%= aggregateName %>ApplicationMapper mapper;
|
|
31
|
+
|
|
32
|
+
public <%= useCaseName %>QueryHandler(<%= aggregateName %>Repository repository,
|
|
33
|
+
<%= aggregateName %>ApplicationMapper mapper) {
|
|
34
|
+
this.repository = repository;
|
|
35
|
+
this.mapper = mapper;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Override
|
|
39
|
+
@Transactional(readOnly = true)
|
|
40
|
+
public PagedResponse<<%= aggregateName %>ResponseDto> handle(<%= useCaseName %>Query query) {
|
|
41
|
+
log.info("Handling <%= useCaseName %>Query — <%= fieldName %>={}, page={}, size={}",
|
|
42
|
+
query.<%= fieldName %>(), query.page(), query.size());
|
|
43
|
+
|
|
44
|
+
Sort sort = Sort.by(Sort.Direction.fromString(query.sortDirection()), query.sortBy());
|
|
45
|
+
Pageable pageable = PageRequest.of(query.page(), query.size(), sort);
|
|
46
|
+
|
|
47
|
+
Page<<%= aggregateName %>> page = repository.<%= jpaMethodName %>(query.<%= fieldName %>(), pageable);
|
|
48
|
+
List<<%= aggregateName %>ResponseDto> content = page.getContent().stream()
|
|
49
|
+
.map(mapper::toDto)
|
|
50
|
+
.toList();
|
|
51
|
+
|
|
52
|
+
log.info("<%= useCaseName %> retrieved — page={}/{}, totalElements={}",
|
|
53
|
+
page.getNumber() + 1, page.getTotalPages(), page.getTotalElements());
|
|
54
|
+
|
|
55
|
+
return PagedResponse.of(content, page.getNumber(), page.getSize(), page.getTotalElements());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -4,7 +4,7 @@ import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %
|
|
|
4
4
|
import <%= packageName %>.shared.application.dtos.PagedResponse;
|
|
5
5
|
import <%= packageName %>.shared.domain.interfaces.Query;
|
|
6
6
|
|
|
7
|
-
public record FindAll<%=
|
|
7
|
+
public record FindAll<%= aggregateNamePlural %>Query(
|
|
8
8
|
int page,
|
|
9
9
|
int size,
|
|
10
10
|
String sortBy,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package <%= packageName %>.<%= moduleName %>.application.usecases;
|
|
2
2
|
|
|
3
|
-
import <%= packageName %>.<%= moduleName %>.application.queries.FindAll<%=
|
|
3
|
+
import <%= packageName %>.<%= moduleName %>.application.queries.FindAll<%= aggregateNamePlural %>Query;
|
|
4
4
|
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
5
5
|
import <%= packageName %>.<%= moduleName %>.application.mappers.<%= aggregateName %>ApplicationMapper;
|
|
6
6
|
import <%= packageName %>.<%= moduleName %>.domain.models.entities.<%= aggregateName %>;
|
|
@@ -18,17 +18,17 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
18
18
|
import java.util.List;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* FindAll<%=
|
|
22
|
-
* Handles retrieval of all <%=
|
|
21
|
+
* FindAll<%= aggregateNamePlural %>QueryHandler
|
|
22
|
+
* Handles retrieval of all <%= aggregateNamePlural %> (paginated)
|
|
23
23
|
*/
|
|
24
24
|
@Slf4j
|
|
25
25
|
@ApplicationComponent
|
|
26
|
-
public class FindAll<%=
|
|
26
|
+
public class FindAll<%= aggregateNamePlural %>QueryHandler implements QueryHandler<FindAll<%= aggregateNamePlural %>Query, PagedResponse<<%= aggregateName %>ResponseDto>> {
|
|
27
27
|
|
|
28
28
|
private final <%= aggregateName %>Repository repository;
|
|
29
29
|
private final <%= aggregateName %>ApplicationMapper mapper;
|
|
30
30
|
|
|
31
|
-
public FindAll<%=
|
|
31
|
+
public FindAll<%= aggregateNamePlural %>QueryHandler(<%= aggregateName %>Repository repository,
|
|
32
32
|
<%= aggregateName %>ApplicationMapper mapper) {
|
|
33
33
|
this.repository = repository;
|
|
34
34
|
this.mapper = mapper;
|
|
@@ -36,8 +36,8 @@ public class FindAll<%= aggregateName %>sQueryHandler implements QueryHandler<Fi
|
|
|
36
36
|
|
|
37
37
|
@Override
|
|
38
38
|
@Transactional(readOnly = true)
|
|
39
|
-
public PagedResponse<<%= aggregateName %>ResponseDto> handle(FindAll<%=
|
|
40
|
-
log.info("Handling FindAll<%=
|
|
39
|
+
public PagedResponse<<%= aggregateName %>ResponseDto> handle(FindAll<%= aggregateNamePlural %>Query query) {
|
|
40
|
+
log.info("Handling FindAll<%= aggregateNamePlural %>Query — page={}, size={}, sortBy={}, sortDirection={}",
|
|
41
41
|
query.page(), query.size(), query.sortBy(), query.sortDirection());
|
|
42
42
|
|
|
43
43
|
Sort sort = Sort.by(Sort.Direction.fromString(query.sortDirection()), query.sortBy());
|
|
@@ -48,7 +48,7 @@ public class FindAll<%= aggregateName %>sQueryHandler implements QueryHandler<Fi
|
|
|
48
48
|
.map(mapper::toDto)
|
|
49
49
|
.toList();
|
|
50
50
|
|
|
51
|
-
log.info("FindAll<%=
|
|
51
|
+
log.info("FindAll<%= aggregateNamePlural %> retrieved — page={}/{}, totalElements={}",
|
|
52
52
|
page.getNumber() + 1, page.getTotalPages(), page.getTotalElements());
|
|
53
53
|
|
|
54
54
|
return PagedResponse.of(content, page.getNumber(), page.getSize(), page.getTotalElements());
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.commands;
|
|
2
|
+
|
|
3
|
+
import <%= packageName %>.shared.domain.interfaces.Command;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* <%= useCaseName %>Command
|
|
7
|
+
* TODO: Add the fields required by this use case and remove the placeholder.
|
|
8
|
+
*/
|
|
9
|
+
public record <%= useCaseName %>Command(
|
|
10
|
+
// TODO: Replace with actual command fields
|
|
11
|
+
String id
|
|
12
|
+
) implements Command {}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.usecases;
|
|
2
|
+
|
|
3
|
+
import <%= packageName %>.<%= moduleName %>.application.commands.<%= useCaseName %>Command;
|
|
4
|
+
import <%= packageName %>.<%= moduleName %>.domain.repositories.<%= aggregateName %>Repository;
|
|
5
|
+
import <%= packageName %>.shared.domain.annotations.ApplicationComponent;
|
|
6
|
+
import <%= packageName %>.shared.domain.interfaces.CommandHandler;
|
|
7
|
+
import lombok.extern.slf4j.Slf4j;
|
|
8
|
+
import org.springframework.transaction.annotation.Transactional;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* <%= useCaseName %>CommandHandler
|
|
12
|
+
* TODO: Implement the business logic for the use case "<%= useCaseName %>".
|
|
13
|
+
*
|
|
14
|
+
* Suggested steps:
|
|
15
|
+
* 1. Find the aggregate root by ID via repository
|
|
16
|
+
* 2. Call the appropriate domain method (e.g. entity.someBusinessMethod())
|
|
17
|
+
* 3. Persist the result via repository.save(entity)
|
|
18
|
+
*/
|
|
19
|
+
@Slf4j
|
|
20
|
+
@ApplicationComponent
|
|
21
|
+
public class <%= useCaseName %>CommandHandler implements CommandHandler<<%= useCaseName %>Command> {
|
|
22
|
+
|
|
23
|
+
private final <%= aggregateName %>Repository repository;
|
|
24
|
+
|
|
25
|
+
public <%= useCaseName %>CommandHandler(<%= aggregateName %>Repository repository) {
|
|
26
|
+
this.repository = repository;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Override
|
|
30
|
+
@Transactional
|
|
31
|
+
public void handle(<%= useCaseName %>Command command) {
|
|
32
|
+
log.info("Handling <%= useCaseName %>Command: {}", command);
|
|
33
|
+
|
|
34
|
+
// TODO: Implement business logic
|
|
35
|
+
// Example:
|
|
36
|
+
// <%= aggregateName %> entity = repository.findById(command.id())
|
|
37
|
+
// .orElseThrow(() -> new EntityNotFoundException("<%= aggregateName %> not found"));
|
|
38
|
+
// entity.someBusinessMethod();
|
|
39
|
+
// repository.save(entity);
|
|
40
|
+
|
|
41
|
+
throw new UnsupportedOperationException("<%= useCaseName %> not yet implemented");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.queries;
|
|
2
|
+
|
|
3
|
+
import <%= packageName %>.<%= moduleName %>.application.dtos.<%= aggregateName %>ResponseDto;
|
|
4
|
+
import <%= packageName %>.shared.domain.interfaces.Query;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* <%= useCaseName %>Query
|
|
8
|
+
* TODO: Add the parameters required by this query and adapt the return type if needed.
|
|
9
|
+
*/
|
|
10
|
+
public record <%= useCaseName %>Query(
|
|
11
|
+
// TODO: Replace with actual query parameters
|
|
12
|
+
String id
|
|
13
|
+
) implements Query<<%= aggregateName %>ResponseDto> {}
|