From dfc9cc59f55b3c41e1d60a72b2379a56b5b0504f Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 13:36:18 -0300 Subject: [PATCH 01/22] 01-vamos-refatorar-um-mini-projeto-aplicando-ports-and-adapters --- .../java/br/com/fullcycle/hexagonal/Main.java | 3 +- .../hexagonal/graphql/CustomerResolver.java | 47 +++++++++++++++++++ src/main/resources/application.properties | 4 +- src/main/resources/graphql/schema.gqls | 21 +++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java create mode 100644 src/main/resources/graphql/schema.gqls diff --git a/src/main/java/br/com/fullcycle/hexagonal/Main.java b/src/main/java/br/com/fullcycle/hexagonal/Main.java index 6bd1948b..ac68c2dc 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/Main.java +++ b/src/main/java/br/com/fullcycle/hexagonal/Main.java @@ -9,5 +9,4 @@ public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } - -} +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java new file mode 100644 index 00000000..85d2cf28 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java @@ -0,0 +1,47 @@ +package br.com.fullcycle.hexagonal.graphql; + +import br.com.fullcycle.hexagonal.dtos.CustomerDTO; +import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.services.CustomerService; +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.MutationMapping; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +import java.util.Objects; + +@Controller +public class CustomerResolver { + + private final CustomerService customerService; + + public CustomerResolver(final CustomerService customerService) { + this.customerService = Objects.requireNonNull(customerService); + } + + @MutationMapping + public CustomerDTO createCustomer(@Argument CustomerDTO input) { + if (customerService.findByCpf(input.getCpf()).isPresent()) { + throw new RuntimeException("Customer already exists"); + } + if (customerService.findByEmail(input.getEmail()).isPresent()) { + throw new RuntimeException("Customer already exists"); + } + + var customer = new Customer(); + customer.setName(input.getName()); + customer.setCpf(input.getCpf()); + customer.setEmail(input.getEmail()); + + customer = customerService.save(customer); + + return new CustomerDTO(customer); + } + + @QueryMapping + public CustomerDTO customerOfId(@Argument Long id) { + return customerService.findById(id) + .map(CustomerDTO::new) + .orElse(null); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 285d5eb3..16ac00b9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,4 +3,6 @@ spring.datasource.username=root spring.datasource.password=root spring.jpa.hibernate.ddl-auto=update spring.jpa.open-in-view=false -spring.jpa.show-sql=true \ No newline at end of file +spring.jpa.show-sql=true + +spring.graphql.graphiql.enabled=true \ No newline at end of file diff --git a/src/main/resources/graphql/schema.gqls b/src/main/resources/graphql/schema.gqls new file mode 100644 index 00000000..e9b80c35 --- /dev/null +++ b/src/main/resources/graphql/schema.gqls @@ -0,0 +1,21 @@ + +type Query { + customerOfId(id: ID!): Customer +} + +type Mutation { + createCustomer(input: CustomerInput): Customer! +} + +type Customer { + id: ID! + name: String + email: String + cpf: String +} + +input CustomerInput { + name: String + email: String + cpf: String +} \ No newline at end of file From b9ae3132f4b959d995b96ec93b7fb433da608853 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 13:45:59 -0300 Subject: [PATCH 02/22] 02-anatomia-de-um-caso-de-uso --- .../fullcycle/hexagonal/application/NullaryUseCase.java | 9 +++++++++ .../com/fullcycle/hexagonal/application/UnitUseCase.java | 9 +++++++++ .../br/com/fullcycle/hexagonal/application/UseCase.java | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java new file mode 100644 index 00000000..3c8a6827 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java @@ -0,0 +1,9 @@ +package br.com.fullcycle.hexagonal.application; + +public abstract class NullaryUseCase { + + // 1. Cada caso de uso tem um Input e um Output próprio. Não retorna a entidade, o agregado, ou objeto de valor. + // 2. O caso de uso implementa o padrão Command + + public abstract OUTPUT execute(); +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java new file mode 100644 index 00000000..c0748911 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java @@ -0,0 +1,9 @@ +package br.com.fullcycle.hexagonal.application; + +public abstract class UnitUseCase { + + // 1. Cada caso de uso tem um Input e um Output próprio. Não retorna a entidade, o agregado, ou objeto de valor. + // 2. O caso de uso implementa o padrão Command + + public abstract void execute(INPUT input); +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java new file mode 100644 index 00000000..7e8fb8ca --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java @@ -0,0 +1,9 @@ +package br.com.fullcycle.hexagonal.application; + +public abstract class UseCase { + + // 1. Cada caso de uso tem um Input e um Output próprio. Não retorna a entidade, o agregado, ou objeto de valor. + // 2. O caso de uso implementa o padrão Command + + public abstract OUTPUT execute(INPUT input); +} From 4c0d3efe8835e6f9da5915229d8bdbd8cb5735a8 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 14:16:50 -0300 Subject: [PATCH 03/22] 03-extraindo-o-caso-de-uso-createcustomer --- .../exceptions/ValidationException.java | 12 ++ .../usecases/CreateCustomerUseCase.java | 41 +++++++ .../controllers/CustomerController.java | 24 ++-- .../hexagonal/graphql/CustomerResolver.java | 22 +--- .../hexagonal/application/Dummy.java | 4 + .../usecases/CreateCustomerUseCaseTest.java | 104 ++++++++++++++++++ 6 files changed, 175 insertions(+), 32 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java b/src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java new file mode 100644 index 00000000..a4dcb35a --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.hexagonal.application.exceptions; + +public class ValidationException extends RuntimeException { + + public ValidationException(final String message) { + super(message, null, true, false); + } + + public ValidationException(final String message, final Throwable cause) { + super(message, cause, true, false); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java new file mode 100644 index 00000000..b9bb3daa --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -0,0 +1,41 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.services.CustomerService; + +public class CreateCustomerUseCase + extends UseCase { + + private final CustomerService customerService; + + public CreateCustomerUseCase(CustomerService customerService) { + this.customerService = customerService; + } + + @Override + public Output execute(final Input input) { + if (customerService.findByCpf(input.cpf).isPresent()) { + throw new ValidationException("Customer already exists"); + } + + if (customerService.findByEmail(input.email).isPresent()) { + throw new ValidationException("Customer already exists"); + } + + var customer = new Customer(); + customer.setName(input.name); + customer.setCpf(input.cpf); + customer.setEmail(input.email); + customer = customerService.save(customer); + + return new Output(customer.getId(), customer.getCpf(), customer.getEmail(), customer.getName()); + } + + public record Input(String cpf, String email, String name) { + } + + public record Output(Long id, String cpf, String email, String name) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java index d8d9b300..6ca20fec 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java @@ -1,7 +1,8 @@ package br.com.fullcycle.hexagonal.controllers; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.models.Customer; import br.com.fullcycle.hexagonal.services.CustomerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -9,6 +10,7 @@ import java.net.URI; +// Adapter @RestController @RequestMapping(value = "customers") public class CustomerController { @@ -18,21 +20,13 @@ public class CustomerController { @PostMapping public ResponseEntity create(@RequestBody CustomerDTO dto) { - if (customerService.findByCpf(dto.getCpf()).isPresent()) { - return ResponseEntity.unprocessableEntity().body("Customer already exists"); + try { + final var useCase = new CreateCustomerUseCase(customerService); + final var output = useCase.execute(new CreateCustomerUseCase.Input(dto.getCpf(), dto.getEmail(), dto.getName())); + return ResponseEntity.created(URI.create("/customers/" + output.id())).body(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); } - if (customerService.findByEmail(dto.getEmail()).isPresent()) { - return ResponseEntity.unprocessableEntity().body("Customer already exists"); - } - - var customer = new Customer(); - customer.setName(dto.getName()); - customer.setCpf(dto.getCpf()); - customer.setEmail(dto.getEmail()); - - customer = customerService.save(customer); - - return ResponseEntity.created(URI.create("/customers/" + customer.getId())).body(customer); } @GetMapping("/{id}") diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java index 85d2cf28..5ec16527 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.graphql; +import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.models.Customer; import br.com.fullcycle.hexagonal.services.CustomerService; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; @@ -10,6 +10,7 @@ import java.util.Objects; +// Adapter @Controller public class CustomerResolver { @@ -20,22 +21,9 @@ public CustomerResolver(final CustomerService customerService) { } @MutationMapping - public CustomerDTO createCustomer(@Argument CustomerDTO input) { - if (customerService.findByCpf(input.getCpf()).isPresent()) { - throw new RuntimeException("Customer already exists"); - } - if (customerService.findByEmail(input.getEmail()).isPresent()) { - throw new RuntimeException("Customer already exists"); - } - - var customer = new Customer(); - customer.setName(input.getName()); - customer.setCpf(input.getCpf()); - customer.setEmail(input.getEmail()); - - customer = customerService.save(customer); - - return new CustomerDTO(customer); + public CreateCustomerUseCase.Output createCustomer(@Argument CustomerDTO input) { + final var useCase = new CreateCustomerUseCase(customerService); + return useCase.execute(new CreateCustomerUseCase.Input(input.getCpf(), input.getEmail(), input.getName())); } @QueryMapping diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java b/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java new file mode 100644 index 00000000..1ced5a49 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java @@ -0,0 +1,4 @@ +package br.com.fullcycle.hexagonal.application; + +public class Dummy { +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java new file mode 100644 index 00000000..9855151a --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java @@ -0,0 +1,104 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.services.CustomerService; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class CreateCustomerUseCaseTest { + + @Test + @DisplayName("Deve criar um cliente") + public void testCreateCustomer() { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + // when + final var customerService = Mockito.mock(CustomerService.class); + when(customerService.findByCpf(expectedCPF)).thenReturn(Optional.empty()); + when(customerService.findByEmail(expectedEmail)).thenReturn(Optional.empty()); + when(customerService.save(any())).thenAnswer(a -> { + var customer = a.getArgument(0, Customer.class); + customer.setId(UUID.randomUUID().getMostSignificantBits()); + return customer; + }); + + final var useCase = new CreateCustomerUseCase(customerService); + final var output = useCase.execute(createInput); + + // then + Assertions.assertNotNull(output.id()); + Assertions.assertEquals(expectedCPF, output.cpf()); + Assertions.assertEquals(expectedEmail, output.email()); + Assertions.assertEquals(expectedName, output.name()); + } + + @Test + @DisplayName("Não deve cadastrar um cliente com CPF duplicado") + public void testCreateWithDuplicatedCPFShouldFail() throws Exception { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Customer already exists"; + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + final var aCustomer = new Customer(); + aCustomer.setId(UUID.randomUUID().getMostSignificantBits()); + aCustomer.setCpf(expectedCPF); + aCustomer.setName(expectedName); + aCustomer.setEmail(expectedEmail); + + // when + final var customerService = Mockito.mock(CustomerService.class); + when(customerService.findByCpf(expectedCPF)).thenReturn(Optional.of(aCustomer)); + + final var useCase = new CreateCustomerUseCase(customerService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") + public void testCreateWithDuplicatedEmailShouldFail() throws Exception { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Customer already exists"; + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + final var aCustomer = new Customer(); + aCustomer.setId(UUID.randomUUID().getMostSignificantBits()); + aCustomer.setCpf(expectedCPF); + aCustomer.setName(expectedName); + aCustomer.setEmail(expectedEmail); + + // when + final var customerService = Mockito.mock(CustomerService.class); + when(customerService.findByEmail(expectedEmail)).thenReturn(Optional.of(aCustomer)); + + final var useCase = new CreateCustomerUseCase(customerService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} From 01b6b446a7b49680a8a803328515ff7b02b59346 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 14:42:45 -0300 Subject: [PATCH 04/22] 04-extraindo-os-casos-de-uso-implicitos --- .../usecases/CreatePartnerUseCase.java | 43 ++++++++++++ .../usecases/GetCustomerByIdUseCase.java | 29 ++++++++ .../usecases/GetPartnerByIdUseCase.java | 29 ++++++++ .../controllers/CustomerController.java | 11 ++-- .../controllers/PartnerController.java | 38 +++++------ .../hexagonal/graphql/CustomerResolver.java | 8 +-- .../hexagonal/graphql/PartnerResolver.java | 35 ++++++++++ src/main/resources/graphql/schema.gqls | 16 ++++- .../usecases/GetCustomerByIdUseCaseTest.java | 66 +++++++++++++++++++ 9 files changed, 241 insertions(+), 34 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java new file mode 100644 index 00000000..1fa161fa --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java @@ -0,0 +1,43 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.services.PartnerService; + +import java.util.Objects; + +public class CreatePartnerUseCase extends UseCase { + + private final PartnerService partnerService; + + public CreatePartnerUseCase(final PartnerService partnerService) { + this.partnerService = Objects.requireNonNull(partnerService); + } + + @Override + public Output execute(final Input input) { + if (partnerService.findByCnpj(input.cnpj).isPresent()) { + throw new ValidationException("Partner already exists"); + } + + if (partnerService.findByEmail(input.email).isPresent()) { + throw new ValidationException("Partner already exists"); + } + + var partner = new Partner(); + partner.setName(input.name); + partner.setCnpj(input.cnpj); + partner.setEmail(input.email); + + partner = partnerService.save(partner); + + return new Output(partner.getId(), partner.getCnpj(), partner.getEmail(), partner.getName()); + } + + public record Input(String cnpj, String email, String name) { + } + + public record Output(Long id, String cnpj, String email, String name) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java new file mode 100644 index 00000000..0551c2e1 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -0,0 +1,29 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.services.CustomerService; + +import java.util.Objects; +import java.util.Optional; + +public class GetCustomerByIdUseCase + extends UseCase> { + + private final CustomerService customerService; + + public GetCustomerByIdUseCase(final CustomerService customerService) { + this.customerService = Objects.requireNonNull(customerService); + } + + @Override + public Optional execute(final Input input) { + return customerService.findById(input.id) + .map(c -> new Output(c.getId(), c.getCpf(), c.getEmail(), c.getName())); + } + + public record Input(Long id) { + } + + public record Output(Long id, String cpf, String email, String name) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java new file mode 100644 index 00000000..14660c3e --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java @@ -0,0 +1,29 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.services.PartnerService; + +import java.util.Objects; +import java.util.Optional; + +public class GetPartnerByIdUseCase + extends UseCase> { + + private final PartnerService partnerService; + + public GetPartnerByIdUseCase(final PartnerService partnerService) { + this.partnerService = Objects.requireNonNull(partnerService); + } + + @Override + public Optional execute(final Input input) { + return partnerService.findById(input.id) + .map(p -> new Output(p.getId(), p.getCnpj(), p.getEmail(), p.getName())); + } + + public record Input(Long id) { + } + + public record Output(Long id, String cnpj, String email, String name) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java index 6ca20fec..e46a3507 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java @@ -2,6 +2,7 @@ import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.dtos.CustomerDTO; import br.com.fullcycle.hexagonal.services.CustomerService; import org.springframework.beans.factory.annotation.Autowired; @@ -31,11 +32,9 @@ public ResponseEntity create(@RequestBody CustomerDTO dto) { @GetMapping("/{id}") public ResponseEntity get(@PathVariable Long id) { - var customer = customerService.findById(id); - if (customer.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(customer.get()); + final var useCase = new GetCustomerByIdUseCase(customerService); + return useCase.execute(new GetCustomerByIdUseCase.Input(id)) + .map(ResponseEntity::ok) + .orElseGet(ResponseEntity.notFound()::build); } } \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java b/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java index af61785b..bb38312e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java @@ -1,7 +1,9 @@ package br.com.fullcycle.hexagonal.controllers; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.models.Partner; import br.com.fullcycle.hexagonal.services.PartnerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -9,6 +11,7 @@ import java.net.URI; +// Adapter @RestController @RequestMapping(value = "partners") public class PartnerController { @@ -18,31 +21,20 @@ public class PartnerController { @PostMapping public ResponseEntity create(@RequestBody PartnerDTO dto) { - if (partnerService.findByCnpj(dto.getCnpj()).isPresent()) { - return ResponseEntity.unprocessableEntity().body("Partner already exists"); + try { + final var useCase = new CreatePartnerUseCase(partnerService); + final var output = useCase.execute(new CreatePartnerUseCase.Input(dto.getCnpj(), dto.getEmail(), dto.getName())); + return ResponseEntity.created(URI.create("/partners/" + output.id())).body(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); } - if (partnerService.findByEmail(dto.getEmail()).isPresent()) { - return ResponseEntity.unprocessableEntity().body("Partner already exists"); - } - - var partner = new Partner(); - partner.setName(dto.getName()); - partner.setCnpj(dto.getCnpj()); - partner.setEmail(dto.getEmail()); - - partner = partnerService.save(partner); - - return ResponseEntity.created(URI.create("/partners/" + partner.getId())).body(partner); } @GetMapping("/{id}") public ResponseEntity get(@PathVariable Long id) { - var partner = partnerService.findById(id); - if (partner.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(partner.get()); + final var useCase = new GetPartnerByIdUseCase(partnerService); + return useCase.execute(new GetPartnerByIdUseCase.Input(id)) + .map(ResponseEntity::ok) + .orElseGet(ResponseEntity.notFound()::build); } - -} +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java index 5ec16527..0a4f3848 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java @@ -1,6 +1,7 @@ package br.com.fullcycle.hexagonal.graphql; import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.dtos.CustomerDTO; import br.com.fullcycle.hexagonal.services.CustomerService; import org.springframework.graphql.data.method.annotation.Argument; @@ -27,9 +28,8 @@ public CreateCustomerUseCase.Output createCustomer(@Argument CustomerDTO input) } @QueryMapping - public CustomerDTO customerOfId(@Argument Long id) { - return customerService.findById(id) - .map(CustomerDTO::new) - .orElse(null); + public GetCustomerByIdUseCase.Output customerOfId(@Argument Long id) { + final var useCase = new GetCustomerByIdUseCase(customerService); + return useCase.execute(new GetCustomerByIdUseCase.Input(id)).orElse(null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java new file mode 100644 index 00000000..bd7290be --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java @@ -0,0 +1,35 @@ +package br.com.fullcycle.hexagonal.graphql; + +import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; +import br.com.fullcycle.hexagonal.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.services.PartnerService; +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.MutationMapping; +import org.springframework.graphql.data.method.annotation.QueryMapping; +import org.springframework.stereotype.Controller; + +import java.util.Objects; + +// Adapter +@Controller +public class PartnerResolver { + + private final PartnerService partnerService; + + public PartnerResolver(final PartnerService partnerService) { + this.partnerService = Objects.requireNonNull(partnerService); + } + + @MutationMapping + public CreatePartnerUseCase.Output createPartner(@Argument PartnerDTO input) { + final var useCase = new CreatePartnerUseCase(partnerService); + return useCase.execute(new CreatePartnerUseCase.Input(input.getCnpj(), input.getEmail(), input.getName())); + } + + @QueryMapping + public GetPartnerByIdUseCase.Output partnerOfId(@Argument Long id) { + final var useCase = new GetPartnerByIdUseCase(partnerService); + return useCase.execute(new GetPartnerByIdUseCase.Input(id)).orElse(null); + } +} diff --git a/src/main/resources/graphql/schema.gqls b/src/main/resources/graphql/schema.gqls index e9b80c35..f251e836 100644 --- a/src/main/resources/graphql/schema.gqls +++ b/src/main/resources/graphql/schema.gqls @@ -1,10 +1,11 @@ - type Query { customerOfId(id: ID!): Customer + partnerOfId(id: ID!): Partner } type Mutation { createCustomer(input: CustomerInput): Customer! + createPartner(input: PartnerInput): Partner! } type Customer { @@ -18,4 +19,17 @@ input CustomerInput { name: String email: String cpf: String +} + +type Partner { + id: ID! + name: String + email: String + cnpj: String +} + +input PartnerInput { + name: String + email: String + cnpj: String } \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java new file mode 100644 index 00000000..d5dd8bdd --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java @@ -0,0 +1,66 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.services.CustomerService; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; +import java.util.UUID; + +import static org.mockito.Mockito.when; + +class GetCustomerByIdUseCaseTest { + + @Test + @DisplayName("Deve obter um cliente por id") + public void testGetById() { + // given + final var expectedID = UUID.randomUUID().getMostSignificantBits(); + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + final var aCustomer = new Customer(); + aCustomer.setId(expectedID); + aCustomer.setCpf(expectedCPF); + aCustomer.setName(expectedName); + aCustomer.setEmail(expectedEmail); + + final var input = new GetCustomerByIdUseCase.Input(expectedID); + + // when + final var customerService = Mockito.mock(CustomerService.class); + when(customerService.findById(expectedID)).thenReturn(Optional.of(aCustomer)); + + final var useCase = new GetCustomerByIdUseCase(customerService); + final var output = useCase.execute(input).get(); + + // then + Assertions.assertEquals(expectedID, output.id()); + Assertions.assertEquals(expectedCPF, output.cpf()); + Assertions.assertEquals(expectedEmail, output.email()); + Assertions.assertEquals(expectedName, output.name()); + } + + @Test + @DisplayName("Deve obter vazio ao tentar recuperar um cliente não existente por id") + public void testGetByIdWIthInvalidId() { + // given + final var expectedID = UUID.randomUUID().getMostSignificantBits(); + + final var input = new GetCustomerByIdUseCase.Input(expectedID); + + // when + final var customerService = Mockito.mock(CustomerService.class); + when(customerService.findById(expectedID)).thenReturn(Optional.empty()); + + final var useCase = new GetCustomerByIdUseCase(customerService); + final var output = useCase.execute(input); + + // then + Assertions.assertTrue(output.isEmpty()); + } +} \ No newline at end of file From 2c43fc5e4b9e11acf4822177e01ffe908e957b4d Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 15:09:56 -0300 Subject: [PATCH 05/22] 05-casos-de-uso-relacionados-aos-eventos-e-ingressos --- .../usecases/CreateEventUseCase.java | 45 ++++++++++++ .../SubscribeCustomerToEventUseCase.java | 58 +++++++++++++++ .../controllers/EventController.java | 71 ++++++------------- 3 files changed, 123 insertions(+), 51 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java new file mode 100644 index 00000000..4ff9f523 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java @@ -0,0 +1,45 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Event; +import br.com.fullcycle.hexagonal.services.EventService; +import br.com.fullcycle.hexagonal.services.PartnerService; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +public class CreateEventUseCase extends UseCase { + + private final EventService eventService; + private final PartnerService partnerService; + + public CreateEventUseCase(final EventService eventService, final PartnerService partnerService) { + this.eventService = Objects.requireNonNull(eventService); + this.partnerService = Objects.requireNonNull(partnerService); + } + + @Override + public Output execute(final Input input) { + var event = new Event(); + event.setDate(LocalDate.parse(input.date, DateTimeFormatter.ISO_DATE)); + event.setName(input.name); + event.setTotalSpots(input.totalSpots); + + partnerService.findById(input.partnerId) + .ifPresentOrElse(event::setPartner, () -> { + throw new ValidationException("Partner not found"); + }); + + event = eventService.save(event); + + return new Output(event.getId(), input.date, event.getName(), input.totalSpots, input.partnerId); + } + + public record Input(String date, String name, Long partnerId, Integer totalSpots) { + } + + public record Output(Long id, String date, String name, int totalSpots, Long partnerId) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java new file mode 100644 index 00000000..445f6d35 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java @@ -0,0 +1,58 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Ticket; +import br.com.fullcycle.hexagonal.models.TicketStatus; +import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.services.EventService; + +import java.time.Instant; +import java.util.Objects; + +public class SubscribeCustomerToEventUseCase extends UseCase { + + private final CustomerService customerService; + private final EventService eventService; + + public SubscribeCustomerToEventUseCase(final CustomerService customerService, final EventService eventService) { + this.customerService = Objects.requireNonNull(customerService); + this.eventService = Objects.requireNonNull(eventService); + } + + @Override + public Output execute(final Input input) { + var customer = customerService.findById(input.customerId()) + .orElseThrow(() -> new ValidationException("Customer not found")); + + var event = eventService.findById(input.eventId) + .orElseThrow(() -> new ValidationException("Event not found")); + + eventService.findTicketByEventIdAndCustomerId(input.eventId, input.customerId) + .ifPresent(t -> { + throw new ValidationException("Email already registered"); + }); + + if (event.getTotalSpots() < event.getTickets().size() + 1) { + throw new ValidationException("Event sold out"); + } + + var ticket = new Ticket(); + ticket.setEvent(event); + ticket.setCustomer(customer); + ticket.setReservedAt(Instant.now()); + ticket.setStatus(TicketStatus.PENDING); + + event.getTickets().add(ticket); + + eventService.save(event); + + return new Output(event.getId(), ticket.getStatus().name(), ticket.getReservedAt()); + } + + public record Input(Long eventId, Long customerId) { + } + + public record Output(Long eventId, String ticketStatus, Instant reservationDate) { + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java index 6e07e2d4..8cb8a46b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java @@ -1,10 +1,10 @@ package br.com.fullcycle.hexagonal.controllers; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; import br.com.fullcycle.hexagonal.dtos.EventDTO; import br.com.fullcycle.hexagonal.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.models.Event; -import br.com.fullcycle.hexagonal.models.Ticket; -import br.com.fullcycle.hexagonal.models.TicketStatus; import br.com.fullcycle.hexagonal.services.CustomerService; import br.com.fullcycle.hexagonal.services.EventService; import br.com.fullcycle.hexagonal.services.PartnerService; @@ -13,12 +13,12 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; +import java.net.URI; +import java.util.Objects; import static org.springframework.http.HttpStatus.CREATED; +// Adapter @RestController @RequestMapping(value = "events") public class EventController { @@ -34,57 +34,26 @@ public class EventController { @PostMapping @ResponseStatus(CREATED) - public Event create(@RequestBody EventDTO dto) { - var event = new Event(); - event.setDate(LocalDate.parse(dto.getDate(), DateTimeFormatter.ISO_DATE)); - event.setName(dto.getName()); - event.setTotalSpots(dto.getTotalSpots()); - - var partner = partnerService.findById(dto.getPartner().getId()); - if (partner.isEmpty()) { - throw new RuntimeException("Partner not found"); + public ResponseEntity create(@RequestBody EventDTO dto) { + try { + final var partnerId = Objects.requireNonNull(dto.getPartner(), "Partner is required").getId(); + final var useCase = new CreateEventUseCase(eventService, partnerService); + final var output = useCase.execute(new CreateEventUseCase.Input(dto.getDate(), dto.getName(), partnerId, dto.getTotalSpots())); + return ResponseEntity.created(URI.create("/events/" + output.id())).body(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); } - event.setPartner(partner.get()); - - return eventService.save(event); } @Transactional @PostMapping(value = "/{id}/subscribe") public ResponseEntity subscribe(@PathVariable Long id, @RequestBody SubscribeDTO dto) { - - var maybeCustomer = customerService.findById(dto.getCustomerId()); - if (maybeCustomer.isEmpty()) { - return ResponseEntity.unprocessableEntity().body("Customer not found"); - } - - var maybeEvent = eventService.findById(id); - if (maybeEvent.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - var maybeTicket = eventService.findTicketByEventIdAndCustomerId(id, dto.getCustomerId()); - if (maybeTicket.isPresent()) { - return ResponseEntity.unprocessableEntity().body("Email already registered"); + try { + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var output = useCase.execute(new SubscribeCustomerToEventUseCase.Input(id, dto.getCustomerId())); + return ResponseEntity.ok(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); } - - var customer = maybeCustomer.get(); - var event = maybeEvent.get(); - - if (event.getTotalSpots() < event.getTickets().size() + 1) { - throw new RuntimeException("Event sold out"); - } - - var ticket = new Ticket(); - ticket.setEvent(event); - ticket.setCustomer(customer); - ticket.setReservedAt(Instant.now()); - ticket.setStatus(TicketStatus.PENDING); - - event.getTickets().add(ticket); - - eventService.save(event); - - return ResponseEntity.ok(new EventDTO(event)); } } From e2a740061e9a8beed3b33b3ddcfd494e33035af6 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 19:58:03 -0300 Subject: [PATCH 06/22] 06-testes-unitarios-dos-casos-de-uso --- .../SubscribeCustomerToEventUseCase.java | 2 +- .../controllers/EventController.java | 2 +- .../usecases/CreateEventUseCaseTest.java | 84 +++++++++ .../usecases/CreatePartnerUseCaseTest.java | 104 +++++++++++ .../usecases/GetPartnerByIdUseCaseTest.java | 66 +++++++ .../SubscribeCustomerToEventUseCaseTest.java | 176 ++++++++++++++++++ 6 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java index 445f6d35..9d6ff491 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java @@ -50,7 +50,7 @@ public Output execute(final Input input) { return new Output(event.getId(), ticket.getStatus().name(), ticket.getReservedAt()); } - public record Input(Long eventId, Long customerId) { + public record Input(Long customerId, Long eventId) { } public record Output(Long eventId, String ticketStatus, Instant reservationDate) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java index 8cb8a46b..e931f981 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java @@ -50,7 +50,7 @@ public ResponseEntity create(@RequestBody EventDTO dto) { public ResponseEntity subscribe(@PathVariable Long id, @RequestBody SubscribeDTO dto) { try { final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); - final var output = useCase.execute(new SubscribeCustomerToEventUseCase.Input(id, dto.getCustomerId())); + final var output = useCase.execute(new SubscribeCustomerToEventUseCase.Input(dto.getCustomerId(), id)); return ResponseEntity.ok(output); } catch (ValidationException ex) { return ResponseEntity.unprocessableEntity().body(ex.getMessage()); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java new file mode 100644 index 00000000..d8c6638f --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java @@ -0,0 +1,84 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Event; +import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.services.EventService; +import br.com.fullcycle.hexagonal.services.PartnerService; +import io.hypersistence.tsid.TSID; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +class CreateEventUseCaseTest { + + @Test + @DisplayName("Deve criar um evento") + public void testCreate() throws Exception { + // given + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = TSID.fast().toLong(); + + final var createInput = + new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); + + // when + final var eventService = Mockito.mock(EventService.class); + final var partnerService = Mockito.mock(PartnerService.class); + + when(partnerService.findById(eq(expectedPartnerId))) + .thenReturn(Optional.of(new Partner())); + + when(eventService.save(any())).thenAnswer(a -> { + final var e = a.getArgument(0, Event.class); + e.setId(TSID.fast().toLong()); + return e; + }); + + final var useCase = new CreateEventUseCase(eventService, partnerService); + final var output = useCase.execute(createInput); + + // then + Assertions.assertNotNull(output.id()); + Assertions.assertEquals(expectedDate, output.date()); + Assertions.assertEquals(expectedName, output.name()); + Assertions.assertEquals(expectedTotalSpots, output.totalSpots()); + Assertions.assertEquals(expectedPartnerId, output.partnerId()); + } + + @Test + @DisplayName("Não deve criar um evento quando o Partner não for encontrado") + public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Exception { + // given + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = TSID.fast().toLong(); + final var expectedError = "Partner not found"; + + final var createInput = + new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); + + // when + final var eventService = Mockito.mock(EventService.class); + final var partnerService = Mockito.mock(PartnerService.class); + + when(partnerService.findById(eq(expectedPartnerId))) + .thenReturn(Optional.empty()); + + final var useCase = new CreateEventUseCase(eventService, partnerService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java new file mode 100644 index 00000000..9c9975de --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java @@ -0,0 +1,104 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.services.PartnerService; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class CreatePartnerUseCaseTest { + + @Test + @DisplayName("Deve criar um parceiro") + public void testCreatePartner() { + // given + final var expectedCNPJ = "41536538000100"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); + + // when + final var partnerService = Mockito.mock(PartnerService.class); + when(partnerService.findByCnpj(expectedCNPJ)).thenReturn(Optional.empty()); + when(partnerService.findByEmail(expectedEmail)).thenReturn(Optional.empty()); + when(partnerService.save(any())).thenAnswer(a -> { + var customer = a.getArgument(0, Partner.class); + customer.setId(UUID.randomUUID().getMostSignificantBits()); + return customer; + }); + + final var useCase = new CreatePartnerUseCase(partnerService); + final var output = useCase.execute(createInput); + + // then + Assertions.assertNotNull(output.id()); + Assertions.assertEquals(expectedCNPJ, output.cnpj()); + Assertions.assertEquals(expectedEmail, output.email()); + Assertions.assertEquals(expectedName, output.name()); + } + + @Test + @DisplayName("Não deve cadastrar um parceiro com CNPJ duplicado") + public void testCreateWithDuplicatedCNPJShouldFail() throws Exception { + // given + final var expectedCNPJ = "41536538000100"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Partner already exists"; + + final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); + + final var aPartner = new Partner(); + aPartner.setId(UUID.randomUUID().getMostSignificantBits()); + aPartner.setCnpj(expectedCNPJ); + aPartner.setName(expectedName); + aPartner.setEmail(expectedEmail); + + // when + final var partnerService = Mockito.mock(PartnerService.class); + when(partnerService.findByCnpj(expectedCNPJ)).thenReturn(Optional.of(aPartner)); + + final var useCase = new CreatePartnerUseCase(partnerService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Não deve cadastrar um parceiro com e-mail duplicado") + public void testCreateWithDuplicatedEmailShouldFail() throws Exception { + // given + final var expectedCNPJ = "41536538000100"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Partner already exists"; + + final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); + + final var aPartner = new Partner(); + aPartner.setId(UUID.randomUUID().getMostSignificantBits()); + aPartner.setCnpj(expectedCNPJ); + aPartner.setName(expectedName); + aPartner.setEmail(expectedEmail); + + // when + final var partnerService = Mockito.mock(PartnerService.class); + when(partnerService.findByEmail(expectedEmail)).thenReturn(Optional.of(aPartner)); + + final var useCase = new CreatePartnerUseCase(partnerService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java new file mode 100644 index 00000000..06c4c597 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java @@ -0,0 +1,66 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.services.PartnerService; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; +import java.util.UUID; + +import static org.mockito.Mockito.when; + +class GetPartnerByIdUseCaseTest { + + @Test + @DisplayName("Deve obter um parceiro por id") + public void testGetById() { + // given + final var expectedID = UUID.randomUUID().getMostSignificantBits(); + final var expectedCNPJ = "41536538000100"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + final var aPartner = new Partner(); + aPartner.setId(expectedID); + aPartner.setCnpj(expectedCNPJ); + aPartner.setName(expectedName); + aPartner.setEmail(expectedEmail); + + final var input = new GetPartnerByIdUseCase.Input(expectedID); + + // when + final var partnerService = Mockito.mock(PartnerService.class); + when(partnerService.findById(expectedID)).thenReturn(Optional.of(aPartner)); + + final var useCase = new GetPartnerByIdUseCase(partnerService); + final var output = useCase.execute(input).get(); + + // then + Assertions.assertEquals(expectedID, output.id()); + Assertions.assertEquals(expectedCNPJ, output.cnpj()); + Assertions.assertEquals(expectedEmail, output.email()); + Assertions.assertEquals(expectedName, output.name()); + } + + @Test + @DisplayName("Deve obter vazio ao tentar recuperar um parceiro não existente por id") + public void testGetByIdWIthInvalidId() { + // given + final var expectedID = UUID.randomUUID().getMostSignificantBits(); + + final var input = new GetPartnerByIdUseCase.Input(expectedID); + + // when + final var partnerService = Mockito.mock(PartnerService.class); + when(partnerService.findById(expectedID)).thenReturn(Optional.empty()); + + final var useCase = new GetPartnerByIdUseCase(partnerService); + final var output = useCase.execute(input); + + // then + Assertions.assertTrue(output.isEmpty()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java new file mode 100644 index 00000000..8882ac57 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java @@ -0,0 +1,176 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.models.Event; +import br.com.fullcycle.hexagonal.models.Ticket; +import br.com.fullcycle.hexagonal.models.TicketStatus; +import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.services.EventService; +import io.hypersistence.tsid.TSID; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class SubscribeCustomerToEventUseCaseTest { + + @Test + @DisplayName("Deve comprar um ticket de um evento") + public void testReserveTicket() throws Exception { + // given + final var expectedTicketsSize = 1; + + final var customerID = TSID.fast().toLong(); + final var eventID = TSID.fast().toLong(); + + final var aEvent = new Event(); + aEvent.setId(eventID); + aEvent.setName("Disney"); + aEvent.setTotalSpots(10); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + + // when + final var customerService = mock(CustomerService.class); + final var eventService = mock(EventService.class); + + when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); + when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); + when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.empty()); + when(eventService.save(any())).thenAnswer(a -> { + final var e = a.getArgument(0, Event.class); + Assertions.assertEquals(expectedTicketsSize, e.getTickets().size()); + return e; + }); + + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var output = useCase.execute(subscribeInput); + + // then + Assertions.assertEquals(eventID, output.eventId()); + Assertions.assertNotNull(output.reservationDate()); + Assertions.assertEquals(TicketStatus.PENDING.name(), output.ticketStatus()); + } + + @Test + @DisplayName("Não deve comprar um ticket com um cliente não existente") + public void testReserveTicketWithoutCustomer() throws Exception { + // given + final var expectedError = "Customer not found"; + + final var customerID = TSID.fast().toLong(); + final var eventID = TSID.fast().toLong(); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); + + // when + final var customerService = mock(CustomerService.class); + final var eventService = mock(EventService.class); + + when(customerService.findById(customerID)).thenReturn(Optional.empty()); + + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Não deve comprar um ticket de um evento que não existe") + public void testReserveTicketWithoutEvent() throws Exception { + // given + final var expectedError = "Event not found"; + + final var customerID = TSID.fast().toLong(); + final var eventID = TSID.fast().toLong(); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); + + // when + final var customerService = mock(CustomerService.class); + final var eventService = mock(EventService.class); + + when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); + when(eventService.findById(eventID)).thenReturn(Optional.empty()); + + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Um mesmo cliente não pode comprar mais de um ticket por evento") + public void testReserveTicketMoreThanOnce() throws Exception { + // given + final var expectedError = "Email already registered"; + + final var customerID = TSID.fast().toLong(); + final var eventID = TSID.fast().toLong(); + + final var aEvent = new Event(); + aEvent.setId(eventID); + aEvent.setName("Disney"); + aEvent.setTotalSpots(10); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + + // when + final var customerService = mock(CustomerService.class); + final var eventService = mock(EventService.class); + + when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); + when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); + when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.of(new Ticket())); + + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Um mesmo cliente não pode comprar de um evento que não há mais cadeiras") + public void testReserveTicketWithoutSlots() throws Exception { + // given + final var expectedError = "Event sold out"; + + final var customerID = TSID.fast().toLong(); + final var eventID = TSID.fast().toLong(); + + final var aEvent = new Event(); + aEvent.setId(eventID); + aEvent.setName("Disney"); + aEvent.setTotalSpots(0); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + + // when + final var customerService = mock(CustomerService.class); + final var eventService = mock(EventService.class); + + when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); + when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); + when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.empty()); + + final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} \ No newline at end of file From e3acd03a90855493a4417f1308015fee0e1a2aea Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 20:24:52 -0300 Subject: [PATCH 07/22] 07-injecao-de-dependencia-nos-casos-de-uso-e-testes-integrados --- build.gradle.kts | 2 + .../usecases/CreateCustomerUseCase.java | 4 +- .../usecases/CreateEventUseCase.java | 6 +- .../usecases/CreatePartnerUseCase.java | 4 +- .../usecases/GetCustomerByIdUseCase.java | 2 +- .../usecases/GetPartnerByIdUseCase.java | 2 +- .../SubscribeCustomerToEventUseCase.java | 8 +- .../hexagonal/{ => infrastructure}/Main.java | 2 +- .../configurations/UseCaseConfig.java | 58 ++++++++++++ .../controllers/CustomerController.java | 6 +- .../controllers/EventController.java | 12 +-- .../controllers/PartnerController.java | 6 +- .../dtos/CustomerDTO.java | 4 +- .../{ => infrastructure}/dtos/EventDTO.java | 4 +- .../{ => infrastructure}/dtos/PartnerDTO.java | 4 +- .../dtos/SubscribeDTO.java | 2 +- .../{ => infrastructure}/dtos/TicketDTO.java | 6 +- .../graphql/CustomerResolver.java | 6 +- .../graphql/PartnerResolver.java | 6 +- .../{ => infrastructure}/models/Customer.java | 2 +- .../{ => infrastructure}/models/Event.java | 2 +- .../{ => infrastructure}/models/Partner.java | 2 +- .../{ => infrastructure}/models/Ticket.java | 2 +- .../models/TicketStatus.java | 2 +- .../repositories/CustomerRepository.java | 4 +- .../repositories/EventRepository.java | 4 +- .../repositories/PartnerRepository.java | 4 +- .../repositories/TicketRepository.java | 4 +- .../services/CustomerService.java | 6 +- .../services/EventService.java | 10 +- .../services/PartnerService.java | 6 +- .../fullcycle/hexagonal/IntegrationTest.java | 10 ++ .../usecases/CreateCustomerUseCaseIT.java | 94 +++++++++++++++++++ .../usecases/CreateCustomerUseCaseTest.java | 4 +- .../usecases/CreateEventUseCaseIT.java | 83 ++++++++++++++++ .../usecases/CreateEventUseCaseTest.java | 8 +- .../usecases/CreatePartnerUseCaseTest.java | 4 +- .../usecases/GetCustomerByIdUseCaseTest.java | 4 +- .../usecases/GetPartnerByIdUseCaseTest.java | 4 +- .../SubscribeCustomerToEventUseCaseTest.java | 12 +-- .../{ => infrastructure}/MainTests.java | 2 +- .../controllers/CustomerControllerTest.java | 6 +- .../controllers/EventControllerTest.java | 20 ++-- .../controllers/PartnerControllerTest.java | 6 +- 44 files changed, 348 insertions(+), 101 deletions(-) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/Main.java (83%) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/CustomerController.java (87%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/EventController.java (83%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/PartnerController.java (87%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/dtos/CustomerDTO.java (87%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/dtos/EventDTO.java (91%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/dtos/PartnerDTO.java (88%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/dtos/SubscribeDTO.java (79%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/dtos/TicketDTO.java (89%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/graphql/CustomerResolver.java (86%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/graphql/PartnerResolver.java (86%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/models/Customer.java (96%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/models/Event.java (97%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/models/Partner.java (95%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/models/Ticket.java (97%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/models/TicketStatus.java (51%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/repositories/CustomerRepository.java (67%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/repositories/EventRepository.java (51%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/repositories/PartnerRepository.java (67%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/repositories/TicketRepository.java (65%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/services/CustomerService.java (77%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/services/EventService.java (70%) rename src/main/java/br/com/fullcycle/hexagonal/{ => infrastructure}/services/PartnerService.java (77%) create mode 100644 src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java rename src/test/java/br/com/fullcycle/hexagonal/{ => infrastructure}/MainTests.java (83%) rename src/test/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/CustomerControllerTest.java (96%) rename src/test/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/EventControllerTest.java (86%) rename src/test/java/br/com/fullcycle/hexagonal/{ => infrastructure}/controllers/PartnerControllerTest.java (96%) diff --git a/build.gradle.kts b/build.gradle.kts index acfe3ee1..67eb6d1d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,8 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-graphql") implementation("org.springframework.boot:spring-boot-starter-web") + implementation("jakarta.inject:jakarta.inject-api:2.0.1") + runtimeOnly("com.mysql:mysql-connector-j") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java index b9bb3daa..b53d6304 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -2,8 +2,8 @@ import br.com.fullcycle.hexagonal.application.UseCase; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; public class CreateCustomerUseCase extends UseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java index 4ff9f523..187a70c9 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java @@ -2,9 +2,9 @@ import br.com.fullcycle.hexagonal.application.UseCase; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Event; -import br.com.fullcycle.hexagonal.services.EventService; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java index 1fa161fa..ab6b8b4a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java @@ -2,8 +2,8 @@ import br.com.fullcycle.hexagonal.application.UseCase; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java index 0551c2e1..1c92fd05 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java index 14660c3e..339737d2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java index 9d6ff491..77f60e56 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java @@ -2,10 +2,10 @@ import br.com.fullcycle.hexagonal.application.UseCase; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Ticket; -import br.com.fullcycle.hexagonal.models.TicketStatus; -import br.com.fullcycle.hexagonal.services.CustomerService; -import br.com.fullcycle.hexagonal.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; import java.time.Instant; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/Main.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/Main.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java index ac68c2dc..3ca266b8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/Main.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal; +package br.com.fullcycle.hexagonal.infrastructure; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java new file mode 100644 index 00000000..7a21e6d0 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -0,0 +1,58 @@ +package br.com.fullcycle.hexagonal.infrastructure.configurations; + +import br.com.fullcycle.hexagonal.application.usecases.*; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Objects; + +@Configuration +public class UseCaseConfig { + + private final CustomerService customerService; + private final EventService eventService; + private final PartnerService partnerService; + + public UseCaseConfig( + final CustomerService customerService, + final EventService eventService, + final PartnerService partnerService + ) { + this.customerService = Objects.requireNonNull(customerService); + this.eventService = Objects.requireNonNull(eventService); + this.partnerService = Objects.requireNonNull(partnerService); + } + + @Bean + public CreateCustomerUseCase createCustomerUseCase() { + return new CreateCustomerUseCase(customerService); + } + + @Bean + public CreateEventUseCase createEventUseCase() { + return new CreateEventUseCase(eventService, partnerService); + } + + @Bean + public CreatePartnerUseCase createPartnerUseCase() { + return new CreatePartnerUseCase(partnerService); + } + + @Bean + public GetCustomerByIdUseCase getCustomerByIdUseCase() { + return new GetCustomerByIdUseCase(customerService); + } + + @Bean + public GetPartnerByIdUseCase getPartnerByIdUseCase() { + return new GetPartnerByIdUseCase(partnerService); + } + + @Bean + public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { + return new SubscribeCustomerToEventUseCase(customerService, eventService); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java index e46a3507..59255a07 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/CustomerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.controllers; +package br.com.fullcycle.hexagonal.infrastructure.controllers; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java index e931f981..2a424c8d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java @@ -1,13 +1,13 @@ -package br.com.fullcycle.hexagonal.controllers; +package br.com.fullcycle.hexagonal.infrastructure.controllers; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.dtos.EventDTO; -import br.com.fullcycle.hexagonal.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.services.CustomerService; -import br.com.fullcycle.hexagonal.services.EventService; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.EventDTO; +import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java index bb38312e..e562986e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/controllers/PartnerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.controllers; +package br.com.fullcycle.hexagonal.infrastructure.controllers; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/dtos/CustomerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/dtos/CustomerDTO.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java index 0d6d9e72..eb01e63f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/dtos/CustomerDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.dtos; +package br.com.fullcycle.hexagonal.infrastructure.dtos; -import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; public class CustomerDTO { private Long id; diff --git a/src/main/java/br/com/fullcycle/hexagonal/dtos/EventDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java similarity index 91% rename from src/main/java/br/com/fullcycle/hexagonal/dtos/EventDTO.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java index 300bfc4e..e6cbfd0a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/dtos/EventDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.dtos; +package br.com.fullcycle.hexagonal.infrastructure.dtos; -import br.com.fullcycle.hexagonal.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/br/com/fullcycle/hexagonal/dtos/PartnerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java similarity index 88% rename from src/main/java/br/com/fullcycle/hexagonal/dtos/PartnerDTO.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java index b28f9dab..c4055d65 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/dtos/PartnerDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.dtos; +package br.com.fullcycle.hexagonal.infrastructure.dtos; -import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; public class PartnerDTO { private Long id; diff --git a/src/main/java/br/com/fullcycle/hexagonal/dtos/SubscribeDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java similarity index 79% rename from src/main/java/br/com/fullcycle/hexagonal/dtos/SubscribeDTO.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java index e6433fc6..60682cdc 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/dtos/SubscribeDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.dtos; +package br.com.fullcycle.hexagonal.infrastructure.dtos; public class SubscribeDTO { diff --git a/src/main/java/br/com/fullcycle/hexagonal/dtos/TicketDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java similarity index 89% rename from src/main/java/br/com/fullcycle/hexagonal/dtos/TicketDTO.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java index f189a4fe..4224a4cb 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/dtos/TicketDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.dtos; +package br.com.fullcycle.hexagonal.infrastructure.dtos; -import br.com.fullcycle.hexagonal.models.Ticket; -import br.com.fullcycle.hexagonal.models.TicketStatus; +import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; import java.time.Instant; diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java similarity index 86% rename from src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java index 0a4f3848..25ee2fd6 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.graphql; +package br.com.fullcycle.hexagonal.infrastructure.graphql; import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java similarity index 86% rename from src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java index bd7290be..f56a7ca8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/graphql/PartnerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.graphql; +package br.com.fullcycle.hexagonal.infrastructure.graphql; import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/models/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java similarity index 96% rename from src/main/java/br/com/fullcycle/hexagonal/models/Customer.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java index fa68c1c4..624811a3 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/models/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.models; +package br.com.fullcycle.hexagonal.infrastructure.models; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; diff --git a/src/main/java/br/com/fullcycle/hexagonal/models/Event.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java similarity index 97% rename from src/main/java/br/com/fullcycle/hexagonal/models/Event.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java index 1e3a1358..a6177b4f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/models/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.models; +package br.com.fullcycle.hexagonal.infrastructure.models; import jakarta.persistence.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/models/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java similarity index 95% rename from src/main/java/br/com/fullcycle/hexagonal/models/Partner.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java index fa3a13a4..0c6d7ad0 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/models/Partner.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.models; +package br.com.fullcycle.hexagonal.infrastructure.models; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; diff --git a/src/main/java/br/com/fullcycle/hexagonal/models/Ticket.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java similarity index 97% rename from src/main/java/br/com/fullcycle/hexagonal/models/Ticket.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java index 215412ef..39699486 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/models/Ticket.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.models; +package br.com.fullcycle.hexagonal.infrastructure.models; import jakarta.persistence.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/models/TicketStatus.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java similarity index 51% rename from src/main/java/br/com/fullcycle/hexagonal/models/TicketStatus.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java index c1aa6a4e..fa667ff8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/models/TicketStatus.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.models; +package br.com.fullcycle.hexagonal.infrastructure.models; public enum TicketStatus { PENDING, PROCESSING, PAID; diff --git a/src/main/java/br/com/fullcycle/hexagonal/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java similarity index 67% rename from src/main/java/br/com/fullcycle/hexagonal/repositories/CustomerRepository.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java index ac87c0f0..40fbb754 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/repositories/CustomerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.repositories; +package br.com.fullcycle.hexagonal.infrastructure.repositories; -import br.com.fullcycle.hexagonal.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; import org.springframework.data.repository.CrudRepository; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java similarity index 51% rename from src/main/java/br/com/fullcycle/hexagonal/repositories/EventRepository.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java index fb28336c..0137717a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/repositories/EventRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.repositories; +package br.com.fullcycle.hexagonal.infrastructure.repositories; -import br.com.fullcycle.hexagonal.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; import org.springframework.data.repository.CrudRepository; public interface EventRepository extends CrudRepository { diff --git a/src/main/java/br/com/fullcycle/hexagonal/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java similarity index 67% rename from src/main/java/br/com/fullcycle/hexagonal/repositories/PartnerRepository.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java index 0f09c735..f29d681e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/repositories/PartnerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.repositories; +package br.com.fullcycle.hexagonal.infrastructure.repositories; -import br.com.fullcycle.hexagonal.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; import org.springframework.data.repository.CrudRepository; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java similarity index 65% rename from src/main/java/br/com/fullcycle/hexagonal/repositories/TicketRepository.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java index c18133f8..0174ae92 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/repositories/TicketRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.repositories; +package br.com.fullcycle.hexagonal.infrastructure.repositories; -import br.com.fullcycle.hexagonal.models.Ticket; +import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; import org.springframework.data.repository.CrudRepository; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/services/CustomerService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java similarity index 77% rename from src/main/java/br/com/fullcycle/hexagonal/services/CustomerService.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java index 019a0587..cb670971 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/services/CustomerService.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.services; +package br.com.fullcycle.hexagonal.infrastructure.services; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/services/EventService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java similarity index 70% rename from src/main/java/br/com/fullcycle/hexagonal/services/EventService.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java index 6df6c747..1f85128a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/services/EventService.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.services; +package br.com.fullcycle.hexagonal.infrastructure.services; -import br.com.fullcycle.hexagonal.models.Event; -import br.com.fullcycle.hexagonal.models.Ticket; -import br.com.fullcycle.hexagonal.repositories.EventRepository; -import br.com.fullcycle.hexagonal.repositories.TicketRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.TicketRepository; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; +import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/services/PartnerService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java similarity index 77% rename from src/main/java/br/com/fullcycle/hexagonal/services/PartnerService.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java index 0f248775..01357a3c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/services/PartnerService.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.services; +package br.com.fullcycle.hexagonal.infrastructure.services; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java b/src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java new file mode 100644 index 00000000..39a62207 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java @@ -0,0 +1,10 @@ +package br.com.fullcycle.hexagonal; + +import br.com.fullcycle.hexagonal.infrastructure.Main; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@ActiveProfiles("test") +@SpringBootTest(classes = Main.class) +public abstract class IntegrationTest { +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java new file mode 100644 index 00000000..e00c3639 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java @@ -0,0 +1,94 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.IntegrationTest; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class CreateCustomerUseCaseIT extends IntegrationTest { + + @Autowired + private CreateCustomerUseCase useCase; + + @Autowired + private CustomerRepository customerRepository; + + @AfterEach + void tearDown() { + customerRepository.deleteAll(); + } + + @Test + @DisplayName("Deve criar um cliente") + public void testCreateCustomer() { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + // when + final var output = useCase.execute(createInput); + + // then + Assertions.assertNotNull(output.id()); + Assertions.assertEquals(expectedCPF, output.cpf()); + Assertions.assertEquals(expectedEmail, output.email()); + Assertions.assertEquals(expectedName, output.name()); + } + + @Test + @DisplayName("Não deve cadastrar um cliente com CPF duplicado") + public void testCreateWithDuplicatedCPFShouldFail() throws Exception { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Customer already exists"; + + createCustomer(expectedCPF, expectedEmail, expectedName); + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + // when + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") + public void testCreateWithDuplicatedEmailShouldFail() throws Exception { + // given + final var expectedCPF = "12345678901"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + final var expectedError = "Customer already exists"; + + createCustomer("23132131231", expectedEmail, expectedName); + + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + + // when + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + private Customer createCustomer(final String cpf, final String email, final String name) { + final var aCustomer = new Customer(); + aCustomer.setCpf(cpf); + aCustomer.setName(name); + aCustomer.setEmail(email); + + return customerRepository.save(aCustomer); + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java index 9855151a..5ac0b921 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java new file mode 100644 index 00000000..b4fef1e6 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java @@ -0,0 +1,83 @@ +package br.com.fullcycle.hexagonal.application.usecases; + +import br.com.fullcycle.hexagonal.IntegrationTest; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; +import io.hypersistence.tsid.TSID; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class CreateEventUseCaseIT extends IntegrationTest { + + @Autowired + private CreateEventUseCase useCase; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private PartnerRepository partnerRepository; + + @BeforeEach + void tearDown() { + eventRepository.deleteAll(); + partnerRepository.deleteAll(); + } + + @Test + @DisplayName("Deve criar um evento") + public void testCreate() throws Exception { + // given + final var partner = createPartner("41536538000100", "john.doe@gmail.com", "John Doe"); + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = partner.getId(); + + final var createInput = + new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); + + // when + final var output = useCase.execute(createInput); + + // then + Assertions.assertNotNull(output.id()); + Assertions.assertEquals(expectedDate, output.date()); + Assertions.assertEquals(expectedName, output.name()); + Assertions.assertEquals(expectedTotalSpots, output.totalSpots()); + Assertions.assertEquals(expectedPartnerId, output.partnerId()); + } + + @Test + @DisplayName("Não deve criar um evento quando o Partner não for encontrado") + public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Exception { + // given + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = TSID.fast().toLong(); + final var expectedError = "Partner not found"; + + final var createInput = + new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); + + // when + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + private Partner createPartner(final String cnpj, final String email, final String name) { + final var aPartner = new Partner(); + aPartner.setCnpj(cnpj); + aPartner.setName(name); + aPartner.setEmail(email); + return partnerRepository.save(aPartner); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java index d8c6638f..656abf10 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java @@ -1,10 +1,10 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Event; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.services.EventService; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import io.hypersistence.tsid.TSID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java index 9c9975de..29028957 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java index d5dd8bdd..b53c42c1 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java index 06c4c597..ab76e4e1 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java index 8882ac57..d5d480a0 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java @@ -1,12 +1,12 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.models.Event; -import br.com.fullcycle.hexagonal.models.Ticket; -import br.com.fullcycle.hexagonal.models.TicketStatus; -import br.com.fullcycle.hexagonal.services.CustomerService; -import br.com.fullcycle.hexagonal.services.EventService; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.models.Event; +import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; +import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.services.EventService; import io.hypersistence.tsid.TSID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/MainTests.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java similarity index 83% rename from src/test/java/br/com/fullcycle/hexagonal/MainTests.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java index b6551348..1febd88c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/MainTests.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal; +package br.com.fullcycle.hexagonal.infrastructure; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/br/com/fullcycle/hexagonal/controllers/CustomerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java similarity index 96% rename from src/test/java/br/com/fullcycle/hexagonal/controllers/CustomerControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java index ded41912..b9794c58 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/controllers/CustomerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.controllers; +package br.com.fullcycle.hexagonal.infrastructure.controllers; -import br.com.fullcycle.hexagonal.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; +import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/br/com/fullcycle/hexagonal/controllers/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java similarity index 86% rename from src/test/java/br/com/fullcycle/hexagonal/controllers/EventControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java index cea78058..8e774a4d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/controllers/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java @@ -1,13 +1,13 @@ -package br.com.fullcycle.hexagonal.controllers; - -import br.com.fullcycle.hexagonal.dtos.EventDTO; -import br.com.fullcycle.hexagonal.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.models.Customer; -import br.com.fullcycle.hexagonal.models.Partner; -import br.com.fullcycle.hexagonal.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.repositories.EventRepository; -import br.com.fullcycle.hexagonal.repositories.PartnerRepository; +package br.com.fullcycle.hexagonal.infrastructure.controllers; + +import br.com.fullcycle.hexagonal.infrastructure.dtos.EventDTO; +import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +import br.com.fullcycle.hexagonal.infrastructure.models.Customer; +import br.com.fullcycle.hexagonal.infrastructure.models.Partner; +import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; +import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/br/com/fullcycle/hexagonal/controllers/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java similarity index 96% rename from src/test/java/br/com/fullcycle/hexagonal/controllers/PartnerControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java index 13fdc03e..c6e1f305 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/controllers/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.controllers; +package br.com.fullcycle.hexagonal.infrastructure.controllers; -import br.com.fullcycle.hexagonal.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; From ac2c33be1656e04451e9e25a69f5dc494c57dcf8 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 20:58:54 -0300 Subject: [PATCH 08/22] 08-refatorando-os-adapters-dos-drivers --- .../controllers/CustomerController.java | 40 --------- .../infrastructure/dtos/CustomerDTO.java | 52 ------------ .../infrastructure/dtos/EventDTO.java | 66 --------------- .../infrastructure/dtos/NewCustomerDTO.java | 5 ++ .../infrastructure/dtos/NewEventDTO.java | 10 +++ .../infrastructure/dtos/NewPartnerDTO.java | 5 ++ .../infrastructure/dtos/PartnerDTO.java | 56 ------------- .../infrastructure/dtos/SubscribeDTO.java | 12 +-- .../infrastructure/dtos/TicketDTO.java | 84 ------------------- .../graphql/CustomerResolver.java | 22 ++--- .../infrastructure/graphql/EventResolver.java | 38 +++++++++ .../graphql/PartnerResolver.java | 22 ++--- .../rest/CustomerController.java | 47 +++++++++++ .../EventController.java | 37 ++++---- .../PartnerController.java | 29 ++++--- src/main/resources/graphql/schema.gqls | 27 ++++++ .../CustomerControllerTest.java | 55 ++++++------ .../EventControllerTest.java | 31 +++---- .../PartnerControllerTest.java | 55 ++++++------ 19 files changed, 252 insertions(+), 441 deletions(-) delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java rename src/main/java/br/com/fullcycle/hexagonal/infrastructure/{controllers => rest}/EventController.java (52%) rename src/main/java/br/com/fullcycle/hexagonal/infrastructure/{controllers => rest}/PartnerController.java (50%) rename src/test/java/br/com/fullcycle/hexagonal/infrastructure/{controllers => rest}/CustomerControllerTest.java (73%) rename src/test/java/br/com/fullcycle/hexagonal/infrastructure/{controllers => rest}/EventControllerTest.java (77%) rename src/test/java/br/com/fullcycle/hexagonal/infrastructure/{controllers => rest}/PartnerControllerTest.java (73%) diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java deleted file mode 100644 index 59255a07..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerController.java +++ /dev/null @@ -1,40 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; - -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.net.URI; - -// Adapter -@RestController -@RequestMapping(value = "customers") -public class CustomerController { - - @Autowired - private CustomerService customerService; - - @PostMapping - public ResponseEntity create(@RequestBody CustomerDTO dto) { - try { - final var useCase = new CreateCustomerUseCase(customerService); - final var output = useCase.execute(new CreateCustomerUseCase.Input(dto.getCpf(), dto.getEmail(), dto.getName())); - return ResponseEntity.created(URI.create("/customers/" + output.id())).body(output); - } catch (ValidationException ex) { - return ResponseEntity.unprocessableEntity().body(ex.getMessage()); - } - } - - @GetMapping("/{id}") - public ResponseEntity get(@PathVariable Long id) { - final var useCase = new GetCustomerByIdUseCase(customerService); - return useCase.execute(new GetCustomerByIdUseCase.Input(id)) - .map(ResponseEntity::ok) - .orElseGet(ResponseEntity.notFound()::build); - } -} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java deleted file mode 100644 index eb01e63f..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/CustomerDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; - -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; - -public class CustomerDTO { - private Long id; - private String name; - private String cpf; - private String email; - - public CustomerDTO() { - } - - public CustomerDTO(Customer customer) { - this.id = customer.getId(); - this.name = customer.getName(); - this.cpf = customer.getCpf(); - this.email = customer.getEmail(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCpf() { - return cpf; - } - - public void setCpf(String cpf) { - this.cpf = cpf; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java deleted file mode 100644 index e6cbfd0a..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/EventDTO.java +++ /dev/null @@ -1,66 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; - -import br.com.fullcycle.hexagonal.infrastructure.models.Event; - -import java.time.format.DateTimeFormatter; - -public class EventDTO { - - private Long id; - private String name; - private String date; - private int totalSpots; - private PartnerDTO partner; - - public EventDTO() { - } - - public EventDTO(Event event) { - this.id = event.getId(); - this.name = event.getName(); - this.date = event.getDate().format(DateTimeFormatter.ISO_DATE); - this.totalSpots = event.getTotalSpots(); - this.partner = new PartnerDTO(event.getPartner()); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDate() { - return date; - } - - public void setDate(String date) { - this.date = date; - } - - public int getTotalSpots() { - return totalSpots; - } - - public void setTotalSpots(int totalSpots) { - this.totalSpots = totalSpots; - } - - public PartnerDTO getPartner() { - return partner; - } - - public void setPartner(PartnerDTO partner) { - this.partner = partner; - } - -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java new file mode 100644 index 00000000..9631943d --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.hexagonal.infrastructure.dtos; + +public record NewCustomerDTO(String cpf, String email, String name) { + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java new file mode 100644 index 00000000..5a4790d3 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java @@ -0,0 +1,10 @@ +package br.com.fullcycle.hexagonal.infrastructure.dtos; + +public record NewEventDTO( + String name, + String date, + Integer totalSpots, + Long partnerId +) { + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java new file mode 100644 index 00000000..d3987e8c --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.hexagonal.infrastructure.dtos; + +public record NewPartnerDTO(String cnpj, String email, String name) { + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java deleted file mode 100644 index c4055d65..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/PartnerDTO.java +++ /dev/null @@ -1,56 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; - -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; - -public class PartnerDTO { - private Long id; - private String name; - private String cnpj; - private String email; - - public PartnerDTO() { - } - - public PartnerDTO(Long id) { - this.id = id; - } - - public PartnerDTO(Partner partner) { - this.id = partner.getId(); - this.name = partner.getName(); - this.cnpj = partner.getCnpj(); - this.email = partner.getEmail(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCnpj() { - return cnpj; - } - - public void setCnpj(String cnpj) { - this.cnpj = cnpj; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java index 60682cdc..ec7536e4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java @@ -1,14 +1,4 @@ package br.com.fullcycle.hexagonal.infrastructure.dtos; -public class SubscribeDTO { - - private Long customerId; - - public Long getCustomerId() { - return customerId; - } - - public void setCustomerId(Long customerId) { - this.customerId = customerId; - } +public record SubscribeDTO(Long customerId, Long eventId) { } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java deleted file mode 100644 index 4224a4cb..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/TicketDTO.java +++ /dev/null @@ -1,84 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; - -import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; - -import java.time.Instant; - -public class TicketDTO { - private Long id; - private int spot; - private CustomerDTO customer; - private EventDTO event; - private TicketStatus status; - private Instant paidAt; - private Instant reservedAt; - - public TicketDTO() { - } - - public TicketDTO(Ticket ticket) { - this.id = ticket.getId(); - this.customer = new CustomerDTO(ticket.getCustomer()); - this.event = new EventDTO(ticket.getEvent()); - this.status = ticket.getStatus(); - this.paidAt = ticket.getPaidAt(); - this.reservedAt = ticket.getReservedAt(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public int getSpot() { - return spot; - } - - public void setSpot(int spot) { - this.spot = spot; - } - - public CustomerDTO getCustomer() { - return customer; - } - - public void setCustomer(CustomerDTO customer) { - this.customer = customer; - } - - public EventDTO getEvent() { - return event; - } - - public void setEvent(EventDTO event) { - this.event = event; - } - - public TicketStatus getStatus() { - return status; - } - - public void setStatus(TicketStatus status) { - this.status = status; - } - - public Instant getPaidAt() { - return paidAt; - } - - public void setPaidAt(Instant paidAt) { - this.paidAt = paidAt; - } - - public Instant getReservedAt() { - return reservedAt; - } - - public void setReservedAt(Instant reservedAt) { - this.reservedAt = reservedAt; - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java index 25ee2fd6..258e4e76 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java @@ -2,8 +2,7 @@ import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; @@ -15,21 +14,24 @@ @Controller public class CustomerResolver { - private final CustomerService customerService; + private final CreateCustomerUseCase createCustomerUseCase; + private final GetCustomerByIdUseCase getCustomerByIdUseCase; - public CustomerResolver(final CustomerService customerService) { - this.customerService = Objects.requireNonNull(customerService); + public CustomerResolver( + final CreateCustomerUseCase createCustomerUseCase, + final GetCustomerByIdUseCase getCustomerByIdUseCase + ) { + this.createCustomerUseCase = Objects.requireNonNull(createCustomerUseCase); + this.getCustomerByIdUseCase = Objects.requireNonNull(getCustomerByIdUseCase); } @MutationMapping - public CreateCustomerUseCase.Output createCustomer(@Argument CustomerDTO input) { - final var useCase = new CreateCustomerUseCase(customerService); - return useCase.execute(new CreateCustomerUseCase.Input(input.getCpf(), input.getEmail(), input.getName())); + public CreateCustomerUseCase.Output createCustomer(@Argument NewCustomerDTO input) { + return createCustomerUseCase.execute(new CreateCustomerUseCase.Input(input.cpf(), input.email(), input.name())); } @QueryMapping public GetCustomerByIdUseCase.Output customerOfId(@Argument Long id) { - final var useCase = new GetCustomerByIdUseCase(customerService); - return useCase.execute(new GetCustomerByIdUseCase.Input(id)).orElse(null); + return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id)).orElse(null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java new file mode 100644 index 00000000..b74deea2 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java @@ -0,0 +1,38 @@ +package br.com.fullcycle.hexagonal.infrastructure.graphql; + +import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; +import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +import org.springframework.graphql.data.method.annotation.Argument; +import org.springframework.graphql.data.method.annotation.MutationMapping; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; + +@Controller +public class EventResolver { + + private final CreateEventUseCase createEventUseCase; + private final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase; + + public EventResolver( + final CreateEventUseCase createEventUseCase, + final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase + ) { + this.createEventUseCase = Objects.requireNonNull(createEventUseCase); + this.subscribeCustomerToEventUseCase = Objects.requireNonNull(subscribeCustomerToEventUseCase); + } + + @MutationMapping + public CreateEventUseCase.Output createEvent(@Argument NewEventDTO input) { + return createEventUseCase.execute(new CreateEventUseCase.Input(input.date(), input.name(), input.partnerId(), input.totalSpots())); + } + + @Transactional + @MutationMapping + public SubscribeCustomerToEventUseCase.Output subscribeCustomerToEvent(@Argument SubscribeDTO input) { + return subscribeCustomerToEventUseCase.execute(new SubscribeCustomerToEventUseCase.Input(input.customerId(), input.eventId())); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java index f56a7ca8..76800fa8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java @@ -2,8 +2,7 @@ import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; @@ -15,21 +14,24 @@ @Controller public class PartnerResolver { - private final PartnerService partnerService; + private final CreatePartnerUseCase createPartnerUseCase; + private final GetPartnerByIdUseCase getPartnerByIdUseCase; - public PartnerResolver(final PartnerService partnerService) { - this.partnerService = Objects.requireNonNull(partnerService); + public PartnerResolver( + final CreatePartnerUseCase createPartnerUseCase, + final GetPartnerByIdUseCase getPartnerByIdUseCase + ) { + this.createPartnerUseCase = Objects.requireNonNull(createPartnerUseCase); + this.getPartnerByIdUseCase = Objects.requireNonNull(getPartnerByIdUseCase); } @MutationMapping - public CreatePartnerUseCase.Output createPartner(@Argument PartnerDTO input) { - final var useCase = new CreatePartnerUseCase(partnerService); - return useCase.execute(new CreatePartnerUseCase.Input(input.getCnpj(), input.getEmail(), input.getName())); + public CreatePartnerUseCase.Output createPartner(@Argument NewPartnerDTO input) { + return createPartnerUseCase.execute(new CreatePartnerUseCase.Input(input.cnpj(), input.email(), input.name())); } @QueryMapping public GetPartnerByIdUseCase.Output partnerOfId(@Argument Long id) { - final var useCase = new GetPartnerByIdUseCase(partnerService); - return useCase.execute(new GetPartnerByIdUseCase.Input(id)).orElse(null); + return getPartnerByIdUseCase.execute(new GetPartnerByIdUseCase.Input(id)).orElse(null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java new file mode 100644 index 00000000..dfbba34b --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java @@ -0,0 +1,47 @@ +package br.com.fullcycle.hexagonal.infrastructure.rest; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; +import java.util.Objects; + +// Adapter +@RestController +@RequestMapping(value = "customers") +public class CustomerController { + + private final CreateCustomerUseCase createCustomerUseCase; + private final GetCustomerByIdUseCase getCustomerByIdUseCase; + + public CustomerController( + final CreateCustomerUseCase createCustomerUseCase, + final GetCustomerByIdUseCase getCustomerByIdUseCase + ) { + this.createCustomerUseCase = Objects.requireNonNull(createCustomerUseCase); + this.getCustomerByIdUseCase = Objects.requireNonNull(getCustomerByIdUseCase); + } + + @PostMapping + public ResponseEntity create(@RequestBody NewCustomerDTO dto) { + try { + final var output = + createCustomerUseCase.execute(new CreateCustomerUseCase.Input(dto.cpf(), dto.email(), dto.name())); + + return ResponseEntity.created(URI.create("/customers/" + output.id())).body(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); + } + } + + @GetMapping("/{id}") + public ResponseEntity get(@PathVariable Long id) { + return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id)) + .map(ResponseEntity::ok) + .orElseGet(ResponseEntity.notFound()::build); + } +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java similarity index 52% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java index 2a424c8d..371315ee 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java @@ -1,14 +1,10 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; +package br.com.fullcycle.hexagonal.infrastructure.rest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.EventDTO; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -23,22 +19,24 @@ @RequestMapping(value = "events") public class EventController { - @Autowired - private CustomerService customerService; + private final CreateEventUseCase createEventUseCase; + private final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase; - @Autowired - private EventService eventService; - - @Autowired - private PartnerService partnerService; + public EventController( + final CreateEventUseCase createEventUseCase, + final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase + ) { + this.createEventUseCase = Objects.requireNonNull(createEventUseCase); + this.subscribeCustomerToEventUseCase = Objects.requireNonNull(subscribeCustomerToEventUseCase); + } @PostMapping @ResponseStatus(CREATED) - public ResponseEntity create(@RequestBody EventDTO dto) { + public ResponseEntity create(@RequestBody NewEventDTO dto) { try { - final var partnerId = Objects.requireNonNull(dto.getPartner(), "Partner is required").getId(); - final var useCase = new CreateEventUseCase(eventService, partnerService); - final var output = useCase.execute(new CreateEventUseCase.Input(dto.getDate(), dto.getName(), partnerId, dto.getTotalSpots())); + final var output = + createEventUseCase.execute(new CreateEventUseCase.Input(dto.date(), dto.name(), dto.partnerId(), dto.totalSpots())); + return ResponseEntity.created(URI.create("/events/" + output.id())).body(output); } catch (ValidationException ex) { return ResponseEntity.unprocessableEntity().body(ex.getMessage()); @@ -49,8 +47,9 @@ public ResponseEntity create(@RequestBody EventDTO dto) { @PostMapping(value = "/{id}/subscribe") public ResponseEntity subscribe(@PathVariable Long id, @RequestBody SubscribeDTO dto) { try { - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); - final var output = useCase.execute(new SubscribeCustomerToEventUseCase.Input(dto.getCustomerId(), id)); + final var output = + subscribeCustomerToEventUseCase.execute(new SubscribeCustomerToEventUseCase.Input(dto.customerId(), id)); + return ResponseEntity.ok(output); } catch (ValidationException ex) { return ResponseEntity.unprocessableEntity().body(ex.getMessage()); diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java similarity index 50% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java index e562986e..e48f45f0 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java @@ -1,29 +1,37 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; +package br.com.fullcycle.hexagonal.infrastructure.rest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; -import org.springframework.beans.factory.annotation.Autowired; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; +import java.util.Objects; // Adapter @RestController @RequestMapping(value = "partners") public class PartnerController { - @Autowired - private PartnerService partnerService; + private final CreatePartnerUseCase createPartnerUseCase; + private final GetPartnerByIdUseCase getPartnerByIdUseCase; + + public PartnerController( + final CreatePartnerUseCase createPartnerUseCase, + final GetPartnerByIdUseCase getPartnerByIdUseCase + ) { + this.createPartnerUseCase = Objects.requireNonNull(createPartnerUseCase); + this.getPartnerByIdUseCase = Objects.requireNonNull(getPartnerByIdUseCase); + } @PostMapping - public ResponseEntity create(@RequestBody PartnerDTO dto) { + public ResponseEntity create(@RequestBody NewPartnerDTO dto) { try { - final var useCase = new CreatePartnerUseCase(partnerService); - final var output = useCase.execute(new CreatePartnerUseCase.Input(dto.getCnpj(), dto.getEmail(), dto.getName())); + final var output = + createPartnerUseCase.execute(new CreatePartnerUseCase.Input(dto.cnpj(), dto.email(), dto.name())); + return ResponseEntity.created(URI.create("/partners/" + output.id())).body(output); } catch (ValidationException ex) { return ResponseEntity.unprocessableEntity().body(ex.getMessage()); @@ -32,8 +40,7 @@ public ResponseEntity create(@RequestBody PartnerDTO dto) { @GetMapping("/{id}") public ResponseEntity get(@PathVariable Long id) { - final var useCase = new GetPartnerByIdUseCase(partnerService); - return useCase.execute(new GetPartnerByIdUseCase.Input(id)) + return getPartnerByIdUseCase.execute(new GetPartnerByIdUseCase.Input(id)) .map(ResponseEntity::ok) .orElseGet(ResponseEntity.notFound()::build); } diff --git a/src/main/resources/graphql/schema.gqls b/src/main/resources/graphql/schema.gqls index f251e836..dd4cf22a 100644 --- a/src/main/resources/graphql/schema.gqls +++ b/src/main/resources/graphql/schema.gqls @@ -5,7 +5,9 @@ type Query { type Mutation { createCustomer(input: CustomerInput): Customer! + createEvent(input: EventInput): Event! createPartner(input: PartnerInput): Partner! + subscribeCustomerToEvent(input: SubscribeInput): Subscribe! } type Customer { @@ -21,6 +23,20 @@ input CustomerInput { cpf: String } +type Event { + id: ID! + date: String! + totalSpots: Int! + name: String! +} + +input EventInput { + date: String + totalSpots: Int + name: String + partnerId: ID +} + type Partner { id: ID! name: String @@ -32,4 +48,15 @@ input PartnerInput { name: String email: String cnpj: String +} + +type Subscribe { + eventId: ID! + ticketStatus: String! + reservationDate: String! +} + +input SubscribeInput { + customerId: ID + eventId: ID } \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java similarity index 73% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java index b9794c58..4a94a43c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/CustomerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java @@ -1,9 +1,14 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; +package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.infrastructure.dtos.CustomerDTO; +import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -36,10 +41,7 @@ void tearDown() { @DisplayName("Deve criar um cliente") public void testCreate() throws Exception { - var customer = new CustomerDTO(); - customer.setCpf("12345678901"); - customer.setEmail("john.doe@gmail.com"); - customer.setName("John Doe"); + var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/customers") @@ -51,20 +53,17 @@ public void testCreate() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - var actualResponse = mapper.readValue(result, CustomerDTO.class); - Assertions.assertEquals(customer.getName(), actualResponse.getName()); - Assertions.assertEquals(customer.getCpf(), actualResponse.getCpf()); - Assertions.assertEquals(customer.getEmail(), actualResponse.getEmail()); + var actualResponse = mapper.readValue(result, NewCustomerDTO.class); + Assertions.assertEquals(customer.name(), actualResponse.name()); + Assertions.assertEquals(customer.cpf(), actualResponse.cpf()); + Assertions.assertEquals(customer.email(), actualResponse.email()); } @Test @DisplayName("Não deve cadastrar um cliente com CPF duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { - var customer = new CustomerDTO(); - customer.setCpf("12345678901"); - customer.setEmail("john.doe@gmail.com"); - customer.setName("John Doe"); + var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); // Cria o primeiro cliente this.mvc.perform( @@ -77,7 +76,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - customer.setEmail("john2@gmail.com"); + customer = new NewCustomerDTO("12345678901", "john2@gmail.com", "John Doe"); // Tenta criar o segundo cliente com o mesmo CPF this.mvc.perform( @@ -93,10 +92,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { - var customer = new CustomerDTO(); - customer.setCpf("12345618901"); - customer.setEmail("john.doe@gmail.com"); - customer.setName("John Doe"); + var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); // Cria o primeiro cliente this.mvc.perform( @@ -109,7 +105,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - customer.setCpf("99999918901"); + customer = new NewCustomerDTO("99999918901", "john.doe@gmail.com", "John Doe"); // Tenta criar o segundo cliente com o mesmo CPF this.mvc.perform( @@ -125,10 +121,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { @DisplayName("Deve obter um cliente por id") public void testGet() throws Exception { - var customer = new CustomerDTO(); - customer.setCpf("12345678901"); - customer.setEmail("john.doe@gmail.com"); - customer.setName("John Doe"); + var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/customers") @@ -137,7 +130,7 @@ public void testGet() throws Exception { ) .andReturn().getResponse().getContentAsByteArray(); - var customerId = mapper.readValue(createResult, CustomerDTO.class).getId(); + var customerId = mapper.readValue(createResult, CreateCustomerUseCase.Output.class).id(); final var result = this.mvc.perform( MockMvcRequestBuilders.get("/customers/{id}", customerId) @@ -145,10 +138,10 @@ public void testGet() throws Exception { .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsByteArray(); - var actualResponse = mapper.readValue(result, CustomerDTO.class); - Assertions.assertEquals(customerId, actualResponse.getId()); - Assertions.assertEquals(customer.getName(), actualResponse.getName()); - Assertions.assertEquals(customer.getCpf(), actualResponse.getCpf()); - Assertions.assertEquals(customer.getEmail(), actualResponse.getEmail()); + var actualResponse = mapper.readValue(result, GetCustomerByIdUseCase.Output.class); + Assertions.assertEquals(customerId, actualResponse.id()); + Assertions.assertEquals(customer.name(), actualResponse.name()); + Assertions.assertEquals(customer.cpf(), actualResponse.cpf()); + Assertions.assertEquals(customer.email(), actualResponse.email()); } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java similarity index 77% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index 8e774a4d..f0643f99 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; +package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.infrastructure.dtos.EventDTO; -import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; import br.com.fullcycle.hexagonal.infrastructure.models.Customer; import br.com.fullcycle.hexagonal.infrastructure.models.Partner; @@ -60,11 +60,7 @@ void tearDown() { @DisplayName("Deve criar um evento") public void testCreate() throws Exception { - var event = new EventDTO(); - event.setDate("2021-01-01"); - event.setName("Disney on Ice"); - event.setTotalSpots(100); - event.setPartner(new PartnerDTO(disney.getId())); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId()); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -75,10 +71,10 @@ public void testCreate() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - var actualResponse = mapper.readValue(result, EventDTO.class); - Assertions.assertEquals(event.getDate(), actualResponse.getDate()); - Assertions.assertEquals(event.getTotalSpots(), actualResponse.getTotalSpots()); - Assertions.assertEquals(event.getName(), actualResponse.getName()); + var actualResponse = mapper.readValue(result, NewEventDTO.class); + Assertions.assertEquals(event.date(), actualResponse.date()); + Assertions.assertEquals(event.totalSpots(), actualResponse.totalSpots()); + Assertions.assertEquals(event.name(), actualResponse.name()); } @Test @@ -86,11 +82,7 @@ public void testCreate() throws Exception { @DisplayName("Deve comprar um ticket de um evento") public void testReserveTicket() throws Exception { - var event = new EventDTO(); - event.setDate("2021-01-01"); - event.setName("Disney on Ice"); - event.setTotalSpots(100); - event.setPartner(new PartnerDTO(disney.getId())); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId()); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -101,10 +93,9 @@ public void testReserveTicket() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - var eventId = mapper.readValue(createResult, EventDTO.class).getId(); + var eventId = mapper.readValue(createResult, CreateCustomerUseCase.Output.class).id(); - var sub = new SubscribeDTO(); - sub.setCustomerId(johnDoe.getId()); + var sub = new SubscribeDTO(johnDoe.getId(), null); this.mvc.perform( MockMvcRequestBuilders.post("/events/{id}/subscribe", eventId) diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java similarity index 73% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java rename to src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java index c6e1f305..c808b6de 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/controllers/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java @@ -1,9 +1,14 @@ -package br.com.fullcycle.hexagonal.infrastructure.controllers; +package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.infrastructure.dtos.PartnerDTO; +import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; +import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -36,10 +41,7 @@ void tearDown() { @DisplayName("Deve criar um parceiro") public void testCreate() throws Exception { - var partner = new PartnerDTO(); - partner.setCnpj("41536538000100"); - partner.setEmail("john.doe@gmail.com"); - partner.setName("John Doe"); + var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/partners") @@ -51,20 +53,17 @@ public void testCreate() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - var actualResponse = mapper.readValue(result, PartnerDTO.class); - Assertions.assertEquals(partner.getName(), actualResponse.getName()); - Assertions.assertEquals(partner.getCnpj(), actualResponse.getCnpj()); - Assertions.assertEquals(partner.getEmail(), actualResponse.getEmail()); + var actualResponse = mapper.readValue(result, NewPartnerDTO.class); + Assertions.assertEquals(partner.name(), actualResponse.name()); + Assertions.assertEquals(partner.cnpj(), actualResponse.cnpj()); + Assertions.assertEquals(partner.email(), actualResponse.email()); } @Test @DisplayName("Não deve cadastrar um parceiro com CNPJ duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { - var partner = new PartnerDTO(); - partner.setCnpj("41536538000100"); - partner.setEmail("john.doe@gmail.com"); - partner.setName("John Doe"); + var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); // Cria o primeiro parceiro this.mvc.perform( @@ -77,7 +76,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - partner.setEmail("john2@gmail.com"); + partner = new NewPartnerDTO("41536538000100", "john2@gmail.com", "John Doe"); // Tenta criar o segundo parceiro com o mesmo CPF this.mvc.perform( @@ -93,10 +92,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um parceiro com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { - var partner = new PartnerDTO(); - partner.setCnpj("41536538000100"); - partner.setEmail("john.doe@gmail.com"); - partner.setName("John Doe"); + var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); // Cria o primeiro parceiro this.mvc.perform( @@ -109,7 +105,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - partner.setCnpj("66666538000100"); + partner = new NewPartnerDTO("66666538000100", "john.doe@gmail.com", "John Doe"); // Tenta criar o segundo parceiro com o mesmo CNPJ this.mvc.perform( @@ -125,10 +121,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { @DisplayName("Deve obter um parceiro por id") public void testGet() throws Exception { - var partner = new PartnerDTO(); - partner.setCnpj("41536538000100"); - partner.setEmail("john.doe@gmail.com"); - partner.setName("John Doe"); + var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/partners") @@ -137,7 +130,7 @@ public void testGet() throws Exception { ) .andReturn().getResponse().getContentAsByteArray(); - var partnerId = mapper.readValue(createResult, PartnerDTO.class).getId(); + var partnerId = mapper.readValue(createResult, CreatePartnerUseCase.Output.class).id(); final var result = this.mvc.perform( MockMvcRequestBuilders.get("/partners/{id}", partnerId) @@ -145,10 +138,10 @@ public void testGet() throws Exception { .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsByteArray(); - var actualResponse = mapper.readValue(result, PartnerDTO.class); - Assertions.assertEquals(partnerId, actualResponse.getId()); - Assertions.assertEquals(partner.getName(), actualResponse.getName()); - Assertions.assertEquals(partner.getCnpj(), actualResponse.getCnpj()); - Assertions.assertEquals(partner.getEmail(), actualResponse.getEmail()); + var actualResponse = mapper.readValue(result, GetPartnerByIdUseCase.Output.class); + Assertions.assertEquals(partnerId, actualResponse.id()); + Assertions.assertEquals(partner.name(), actualResponse.name()); + Assertions.assertEquals(partner.cnpj(), actualResponse.cnpj()); + Assertions.assertEquals(partner.email(), actualResponse.email()); } } From 645cf1f042a3fdda0dadb0b2c5f85c1b8f0c56ba Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 22:31:03 -0300 Subject: [PATCH 09/22] 09-modelando-as-entidades-de-dominio-parte-1 --- .../application/entities/Customer.java | 54 ++++++++++++++++ .../application/entities/CustomerId.java | 20 ++++++ .../repositories/CustomerRepository.java | 20 ++++++ .../usecases/CreateCustomerUseCase.java | 24 +++---- .../usecases/GetCustomerByIdUseCase.java | 17 ++--- .../configurations/UseCaseConfig.java | 6 +- .../graphql/CustomerResolver.java | 2 +- .../rest/CustomerController.java | 2 +- .../InMemoryCustomerRepository.java | 54 ++++++++++++++++ .../usecases/CreateCustomerUseCaseTest.java | 62 ++++++------------- .../usecases/GetCustomerByIdUseCaseTest.java | 35 ++++------- .../rest/EventControllerTest.java | 4 +- 12 files changed, 208 insertions(+), 92 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java new file mode 100644 index 00000000..0645b328 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public class Customer { + + private CustomerId customerId; + private String name; + private String cpf; + private String email; + + public Customer(final CustomerId customerId, final String name, final String cpf, final String email) { + if (customerId == null) { + throw new ValidationException("Invalid customerId for Customer"); + } + + if (name == null) { + throw new ValidationException("Invalid name for Customer"); + } + + if (cpf == null || !cpf.matches("^\\d{3}\\.\\d{3}\\.\\d{3}\\-\\d{2}$")) { + throw new ValidationException("Invalid cpf for Customer"); + } + + if (email == null || !email.matches("^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$")) { + throw new ValidationException("Invalid email for Customer"); + } + + this.customerId = customerId; + this.name = name; + this.cpf = cpf; + this.email = email; + } + + public static Customer newCustomer(String name, String cpf, String email) { + return new Customer(CustomerId.unique(), name, cpf, email); + } + + public CustomerId customerId() { + return customerId; + } + + public String name() { + return name; + } + + public String cpf() { + return cpf; + } + + public String email() { + return email; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java new file mode 100644 index 00000000..39873c15 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java @@ -0,0 +1,20 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +import java.util.UUID; + +public record CustomerId(UUID value) { + + public static CustomerId unique() { + return new CustomerId(UUID.randomUUID()); + } + + public static CustomerId with(final String value) { + try { + return new CustomerId(UUID.fromString(value)); + } catch (IllegalArgumentException ex) { + throw new ValidationException("Invalid value for CustomerId"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java new file mode 100644 index 00000000..3228f27a --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java @@ -0,0 +1,20 @@ +package br.com.fullcycle.hexagonal.application.repositories; + +import br.com.fullcycle.hexagonal.application.entities.Customer; +import br.com.fullcycle.hexagonal.application.entities.CustomerId; + +import java.util.Optional; + +public interface CustomerRepository { + + Optional customerOfId(CustomerId anId); + + Optional customerOfCPF(String cpf); + + Optional customerOfEmail(String email); + + Customer create(Customer customer); + + Customer update(Customer customer); + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java index b53d6304..d4e42a52 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -1,41 +1,37 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.entities.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; public class CreateCustomerUseCase extends UseCase { - private final CustomerService customerService; + private final CustomerRepository customerRepository; - public CreateCustomerUseCase(CustomerService customerService) { - this.customerService = customerService; + public CreateCustomerUseCase(CustomerRepository customerRepository) { + this.customerRepository = customerRepository; } @Override public Output execute(final Input input) { - if (customerService.findByCpf(input.cpf).isPresent()) { + if (customerRepository.customerOfCPF(input.cpf).isPresent()) { throw new ValidationException("Customer already exists"); } - if (customerService.findByEmail(input.email).isPresent()) { + if (customerRepository.customerOfEmail(input.email).isPresent()) { throw new ValidationException("Customer already exists"); } - var customer = new Customer(); - customer.setName(input.name); - customer.setCpf(input.cpf); - customer.setEmail(input.email); - customer = customerService.save(customer); + var customer = customerRepository.create(Customer.newCustomer(input.name, input.cpf, input.email)); - return new Output(customer.getId(), customer.getCpf(), customer.getEmail(), customer.getName()); + return new Output(customer.customerId().value().toString(), customer.cpf(), customer.email(), customer.name()); } public record Input(String cpf, String email, String name) { } - public record Output(Long id, String cpf, String email, String name) { + public record Output(String id, String cpf, String email, String name) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java index 1c92fd05..902f02ad 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -1,7 +1,8 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.application.entities.CustomerId; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.Objects; import java.util.Optional; @@ -9,21 +10,21 @@ public class GetCustomerByIdUseCase extends UseCase> { - private final CustomerService customerService; + private final CustomerRepository customerRepository; - public GetCustomerByIdUseCase(final CustomerService customerService) { - this.customerService = Objects.requireNonNull(customerService); + public GetCustomerByIdUseCase(final CustomerRepository customerRepository) { + this.customerRepository = Objects.requireNonNull(customerRepository); } @Override public Optional execute(final Input input) { - return customerService.findById(input.id) - .map(c -> new Output(c.getId(), c.getCpf(), c.getEmail(), c.getName())); + return customerRepository.customerOfId(CustomerId.with(input.id)) + .map(c -> new Output(c.customerId().value().toString(), c.cpf(), c.email(), c.name())); } - public record Input(Long id) { + public record Input(String id) { } - public record Output(Long id, String cpf, String email, String name) { + public record Output(String id, String cpf, String email, String name) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 7a21e6d0..3e891a34 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -28,7 +28,8 @@ public UseCaseConfig( @Bean public CreateCustomerUseCase createCustomerUseCase() { - return new CreateCustomerUseCase(customerService); + // TODO: Fix dependency + return new CreateCustomerUseCase(null); } @Bean @@ -43,7 +44,8 @@ public CreatePartnerUseCase createPartnerUseCase() { @Bean public GetCustomerByIdUseCase getCustomerByIdUseCase() { - return new GetCustomerByIdUseCase(customerService); + // TODO: Fix dependency + return new GetCustomerByIdUseCase(null); } @Bean diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java index 258e4e76..b7b35b3f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java @@ -31,7 +31,7 @@ public CreateCustomerUseCase.Output createCustomer(@Argument NewCustomerDTO inpu } @QueryMapping - public GetCustomerByIdUseCase.Output customerOfId(@Argument Long id) { + public GetCustomerByIdUseCase.Output customerOfId(@Argument String id) { return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id)).orElse(null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java index dfbba34b..03b411ad 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java @@ -39,7 +39,7 @@ public ResponseEntity create(@RequestBody NewCustomerDTO dto) { } @GetMapping("/{id}") - public ResponseEntity get(@PathVariable Long id) { + public ResponseEntity get(@PathVariable String id) { return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id)) .map(ResponseEntity::ok) .orElseGet(ResponseEntity.notFound()::build); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java new file mode 100644 index 00000000..8f8d44fd --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application; + +import br.com.fullcycle.hexagonal.application.entities.Customer; +import br.com.fullcycle.hexagonal.application.entities.CustomerId; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +public class InMemoryCustomerRepository implements CustomerRepository { + + private final Map customers; + private final Map customersByCPF; + private final Map customersByEmail; + + public InMemoryCustomerRepository() { + this.customers = new HashMap<>(); + this.customersByCPF = new HashMap<>(); + this.customersByEmail = new HashMap<>(); + } + + @Override + public Optional customerOfId(CustomerId anId) { + return Optional.ofNullable(this.customers.get(Objects.requireNonNull(anId).value().toString())); + } + + @Override + public Optional customerOfCPF(String cpf) { + return Optional.ofNullable(this.customersByCPF.get(Objects.requireNonNull(cpf))); + } + + @Override + public Optional customerOfEmail(String email) { + return Optional.ofNullable(this.customersByEmail.get(Objects.requireNonNull(email))); + } + + @Override + public Customer create(Customer customer) { + this.customers.put(customer.customerId().value().toString(), customer); + this.customersByCPF.put(customer.cpf(), customer); + this.customersByEmail.put(customer.email(), customer); + return customer; + } + + @Override + public Customer update(Customer customer) { + this.customers.put(customer.customerId().value().toString(), customer); + this.customersByCPF.put(customer.cpf(), customer); + this.customersByEmail.put(customer.email(), customer); + return customer; + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java index 5ac0b921..1930557e 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java @@ -1,18 +1,11 @@ package br.com.fullcycle.hexagonal.application.usecases; +import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.entities.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.util.Optional; -import java.util.UUID; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; public class CreateCustomerUseCaseTest { @@ -20,23 +13,16 @@ public class CreateCustomerUseCaseTest { @DisplayName("Deve criar um cliente") public void testCreateCustomer() { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + final var customerRepository = new InMemoryCustomerRepository(); + // when - final var customerService = Mockito.mock(CustomerService.class); - when(customerService.findByCpf(expectedCPF)).thenReturn(Optional.empty()); - when(customerService.findByEmail(expectedEmail)).thenReturn(Optional.empty()); - when(customerService.save(any())).thenAnswer(a -> { - var customer = a.getArgument(0, Customer.class); - customer.setId(UUID.randomUUID().getMostSignificantBits()); - return customer; - }); - - final var useCase = new CreateCustomerUseCase(customerService); + final var useCase = new CreateCustomerUseCase(customerRepository); final var output = useCase.execute(createInput); // then @@ -50,24 +36,20 @@ public void testCreateCustomer() { @DisplayName("Não deve cadastrar um cliente com CPF duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Customer already exists"; - final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + final var aCustomer = Customer.newCustomer(expectedName, expectedCPF, expectedEmail); - final var aCustomer = new Customer(); - aCustomer.setId(UUID.randomUUID().getMostSignificantBits()); - aCustomer.setCpf(expectedCPF); - aCustomer.setName(expectedName); - aCustomer.setEmail(expectedEmail); + final var customerRepository = new InMemoryCustomerRepository(); + customerRepository.create(aCustomer); - // when - final var customerService = Mockito.mock(CustomerService.class); - when(customerService.findByCpf(expectedCPF)).thenReturn(Optional.of(aCustomer)); + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); - final var useCase = new CreateCustomerUseCase(customerService); + // when + final var useCase = new CreateCustomerUseCase(customerRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); // then @@ -78,24 +60,20 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Customer already exists"; - final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); + final var aCustomer = Customer.newCustomer(expectedName, expectedCPF, expectedEmail); - final var aCustomer = new Customer(); - aCustomer.setId(UUID.randomUUID().getMostSignificantBits()); - aCustomer.setCpf(expectedCPF); - aCustomer.setName(expectedName); - aCustomer.setEmail(expectedEmail); + final var customerRepository = new InMemoryCustomerRepository(); + customerRepository.create(aCustomer); - // when - final var customerService = Mockito.mock(CustomerService.class); - when(customerService.findByEmail(expectedEmail)).thenReturn(Optional.of(aCustomer)); + final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); - final var useCase = new CreateCustomerUseCase(customerService); + // when + final var useCase = new CreateCustomerUseCase(customerRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); // then diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java index b53c42c1..889c347b 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java @@ -1,41 +1,34 @@ package br.com.fullcycle.hexagonal.application.usecases; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; +import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.entities.Customer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import java.util.Optional; import java.util.UUID; -import static org.mockito.Mockito.when; - class GetCustomerByIdUseCaseTest { @Test @DisplayName("Deve obter um cliente por id") public void testGetById() { // given - final var expectedID = UUID.randomUUID().getMostSignificantBits(); - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; - final var aCustomer = new Customer(); - aCustomer.setId(expectedID); - aCustomer.setCpf(expectedCPF); - aCustomer.setName(expectedName); - aCustomer.setEmail(expectedEmail); + final var aCustomer = Customer.newCustomer(expectedName, expectedCPF, expectedEmail); + + final var customerRepository = new InMemoryCustomerRepository(); + customerRepository.create(aCustomer); + final var expectedID = aCustomer.customerId().value().toString(); + final var input = new GetCustomerByIdUseCase.Input(expectedID); // when - final var customerService = Mockito.mock(CustomerService.class); - when(customerService.findById(expectedID)).thenReturn(Optional.of(aCustomer)); - - final var useCase = new GetCustomerByIdUseCase(customerService); + final var useCase = new GetCustomerByIdUseCase(customerRepository); final var output = useCase.execute(input).get(); // then @@ -49,15 +42,13 @@ public void testGetById() { @DisplayName("Deve obter vazio ao tentar recuperar um cliente não existente por id") public void testGetByIdWIthInvalidId() { // given - final var expectedID = UUID.randomUUID().getMostSignificantBits(); + final var expectedID = UUID.randomUUID().toString(); final var input = new GetCustomerByIdUseCase.Input(expectedID); // when - final var customerService = Mockito.mock(CustomerService.class); - when(customerService.findById(expectedID)).thenReturn(Optional.empty()); - - final var useCase = new GetCustomerByIdUseCase(customerService); + final var customerRepository = new InMemoryCustomerRepository(); + final var useCase = new GetCustomerByIdUseCase(customerRepository); final var output = useCase.execute(input); // then diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index f0643f99..78ced5f1 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -1,6 +1,6 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; import br.com.fullcycle.hexagonal.infrastructure.models.Customer; @@ -93,7 +93,7 @@ public void testReserveTicket() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) .andReturn().getResponse().getContentAsByteArray(); - var eventId = mapper.readValue(createResult, CreateCustomerUseCase.Output.class).id(); + var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); var sub = new SubscribeDTO(johnDoe.getId(), null); From 4d82dca418f4c44da57d7e17994ca674bec2f18d Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 13 Aug 2023 22:59:28 -0300 Subject: [PATCH 10/22] 10-modelando-as-entidades-de-dominio-parte-1-e-2 --- .../hexagonal/application/entities/Cnpj.java | 12 ++++ .../hexagonal/application/entities/Cpf.java | 12 ++++ .../application/entities/Customer.java | 30 +++------ .../application/entities/CustomerId.java | 6 ++ .../hexagonal/application/entities/Email.java | 12 ++++ .../hexagonal/application/entities/Name.java | 12 ++++ .../application/entities/Partner.java | 42 +++++++++++++ .../application/entities/PartnerId.java | 26 ++++++++ .../repositories/PartnerRepository.java | 20 ++++++ .../usecases/CreateCustomerUseCase.java | 7 ++- .../usecases/CreatePartnerUseCase.java | 30 ++++----- .../usecases/GetCustomerByIdUseCase.java | 7 ++- .../usecases/GetPartnerByIdUseCase.java | 22 ++++--- .../configurations/UseCaseConfig.java | 4 +- .../graphql/PartnerResolver.java | 2 +- .../rest/PartnerController.java | 2 +- .../InMemoryCustomerRepository.java | 8 +-- .../InMemoryPartnerRepository.java | 54 ++++++++++++++++ .../usecases/CreatePartnerUseCaseTest.java | 61 ++++++------------- .../usecases/GetPartnerByIdUseCaseTest.java | 31 ++++------ 20 files changed, 286 insertions(+), 114 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java new file mode 100644 index 00000000..7c407e45 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public record Cnpj(String value) { + + public Cnpj { + if (value == null || !value.matches("^\\d{2}\\.\\d{3}\\.\\d{3}\\/\\d{4}\\-\\d{2}$")) { + throw new ValidationException("Invalid value for Cnpj"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java new file mode 100644 index 00000000..877ee273 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public record Cpf(String value) { + + public Cpf { + if (value == null || !value.matches("^\\d{3}\\.\\d{3}\\.\\d{3}\\-\\d{2}$")) { + throw new ValidationException("Invalid value for Cpf"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java index 0645b328..50be5385 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java @@ -5,31 +5,19 @@ public class Customer { private CustomerId customerId; - private String name; - private String cpf; - private String email; + private Name name; + private Cpf cpf; + private Email email; public Customer(final CustomerId customerId, final String name, final String cpf, final String email) { if (customerId == null) { throw new ValidationException("Invalid customerId for Customer"); } - if (name == null) { - throw new ValidationException("Invalid name for Customer"); - } - - if (cpf == null || !cpf.matches("^\\d{3}\\.\\d{3}\\.\\d{3}\\-\\d{2}$")) { - throw new ValidationException("Invalid cpf for Customer"); - } - - if (email == null || !email.matches("^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$")) { - throw new ValidationException("Invalid email for Customer"); - } - this.customerId = customerId; - this.name = name; - this.cpf = cpf; - this.email = email; + this.name = new Name(name); + this.cpf = new Cpf(cpf); + this.email = new Email(email); } public static Customer newCustomer(String name, String cpf, String email) { @@ -40,15 +28,15 @@ public CustomerId customerId() { return customerId; } - public String name() { + public Name name() { return name; } - public String cpf() { + public Cpf cpf() { return cpf; } - public String email() { + public Email email() { return email; } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java index 39873c15..a106b5b3 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java @@ -6,6 +6,12 @@ public record CustomerId(UUID value) { + public CustomerId { + if (value == null) { + throw new ValidationException("Invalid value for CustomerId"); + } + } + public static CustomerId unique() { return new CustomerId(UUID.randomUUID()); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java new file mode 100644 index 00000000..dc131c40 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public record Email(String value) { + + public Email { + if (value == null || !value.matches("^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$")) { + throw new ValidationException("Invalid value for Email"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java new file mode 100644 index 00000000..51256642 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public record Name(String value) { + + public Name { + if (value == null) { + throw new ValidationException("Invalid value for Name"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java new file mode 100644 index 00000000..b26aeda7 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java @@ -0,0 +1,42 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public class Partner { + + private PartnerId partnerId; + private Name name; + private Cnpj cnpj; + private Email email; + + public Partner(final PartnerId partnerId, final String name, final String cnpj, final String email) { + if (partnerId == null) { + throw new ValidationException("Invalid partnerId for Partner"); + } + + this.partnerId = partnerId; + this.name = new Name(name); + this.cnpj = new Cnpj(cnpj); + this.email = new Email(email); + } + + public static Partner newPartner(String name, String cnpj, String email) { + return new Partner(PartnerId.unique(), name, cnpj, email); + } + + public PartnerId partnerId() { + return partnerId; + } + + public Name name() { + return name; + } + + public Cnpj cnpj() { + return cnpj; + } + + public Email email() { + return email; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java new file mode 100644 index 00000000..10e4fa04 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java @@ -0,0 +1,26 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +import java.util.UUID; + +public record PartnerId(UUID value) { + + public PartnerId { + if (value == null) { + throw new ValidationException("Invalid value for CustomerId"); + } + } + + public static PartnerId unique() { + return new PartnerId(UUID.randomUUID()); + } + + public static PartnerId with(final String value) { + try { + return new PartnerId(UUID.fromString(value)); + } catch (IllegalArgumentException ex) { + throw new ValidationException("Invalid value for PartnerId"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java new file mode 100644 index 00000000..8f43196f --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java @@ -0,0 +1,20 @@ +package br.com.fullcycle.hexagonal.application.repositories; + +import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; + +import java.util.Optional; + +public interface PartnerRepository { + + Optional partnerOfId(PartnerId anId); + + Optional partnerOfCNPJ(String cpf); + + Optional partnerOfEmail(String email); + + Partner create(Partner partner); + + Partner update(Partner partner); + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java index d4e42a52..652e1c4c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -26,7 +26,12 @@ public Output execute(final Input input) { var customer = customerRepository.create(Customer.newCustomer(input.name, input.cpf, input.email)); - return new Output(customer.customerId().value().toString(), customer.cpf(), customer.email(), customer.name()); + return new Output( + customer.customerId().value().toString(), + customer.cpf().value(), + customer.email().value(), + customer.name().value() + ); } public record Input(String cpf, String email, String name) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java index ab6b8b4a..d6c86011 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java @@ -1,43 +1,43 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.entities.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.Objects; public class CreatePartnerUseCase extends UseCase { - private final PartnerService partnerService; + private final PartnerRepository partnerRepository; - public CreatePartnerUseCase(final PartnerService partnerService) { - this.partnerService = Objects.requireNonNull(partnerService); + public CreatePartnerUseCase(final PartnerRepository partnerRepository) { + this.partnerRepository = Objects.requireNonNull(partnerRepository); } @Override public Output execute(final Input input) { - if (partnerService.findByCnpj(input.cnpj).isPresent()) { + if (partnerRepository.partnerOfCNPJ(input.cnpj).isPresent()) { throw new ValidationException("Partner already exists"); } - if (partnerService.findByEmail(input.email).isPresent()) { + if (partnerRepository.partnerOfEmail(input.email).isPresent()) { throw new ValidationException("Partner already exists"); } - var partner = new Partner(); - partner.setName(input.name); - partner.setCnpj(input.cnpj); - partner.setEmail(input.email); + var partner = partnerRepository.create(Partner.newPartner(input.name, input.cnpj, input.email)); - partner = partnerService.save(partner); - - return new Output(partner.getId(), partner.getCnpj(), partner.getEmail(), partner.getName()); + return new Output( + partner.partnerId().value().toString(), + partner.cnpj().value(), + partner.email().value(), + partner.name().value() + ); } public record Input(String cnpj, String email, String name) { } - public record Output(Long id, String cnpj, String email, String name) { + public record Output(String id, String cnpj, String email, String name) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java index 902f02ad..5bf74506 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -19,7 +19,12 @@ public GetCustomerByIdUseCase(final CustomerRepository customerRepository) { @Override public Optional execute(final Input input) { return customerRepository.customerOfId(CustomerId.with(input.id)) - .map(c -> new Output(c.customerId().value().toString(), c.cpf(), c.email(), c.name())); + .map(c -> new Output( + c.customerId().value().toString(), + c.cpf().value(), + c.email().value(), + c.name().value()) + ); } public record Input(String id) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java index 339737d2..068023a5 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java @@ -1,7 +1,8 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.Objects; import java.util.Optional; @@ -9,21 +10,26 @@ public class GetPartnerByIdUseCase extends UseCase> { - private final PartnerService partnerService; + private final PartnerRepository partnerRepository; - public GetPartnerByIdUseCase(final PartnerService partnerService) { - this.partnerService = Objects.requireNonNull(partnerService); + public GetPartnerByIdUseCase(final PartnerRepository partnerRepository) { + this.partnerRepository = Objects.requireNonNull(partnerRepository); } @Override public Optional execute(final Input input) { - return partnerService.findById(input.id) - .map(p -> new Output(p.getId(), p.getCnpj(), p.getEmail(), p.getName())); + return partnerRepository.partnerOfId(PartnerId.with(input.id)) + .map(partner -> new Output( + partner.partnerId().value().toString(), + partner.cnpj().value(), + partner.email().value(), + partner.name().value() + )); } - public record Input(Long id) { + public record Input(String id) { } - public record Output(Long id, String cnpj, String email, String name) { + public record Output(String id, String cnpj, String email, String name) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 3e891a34..edcd60b8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -39,7 +39,7 @@ public CreateEventUseCase createEventUseCase() { @Bean public CreatePartnerUseCase createPartnerUseCase() { - return new CreatePartnerUseCase(partnerService); + return new CreatePartnerUseCase(null); } @Bean @@ -50,7 +50,7 @@ public GetCustomerByIdUseCase getCustomerByIdUseCase() { @Bean public GetPartnerByIdUseCase getPartnerByIdUseCase() { - return new GetPartnerByIdUseCase(partnerService); + return new GetPartnerByIdUseCase(null); } @Bean diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java index 76800fa8..9dba3b2d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java @@ -31,7 +31,7 @@ public CreatePartnerUseCase.Output createPartner(@Argument NewPartnerDTO input) } @QueryMapping - public GetPartnerByIdUseCase.Output partnerOfId(@Argument Long id) { + public GetPartnerByIdUseCase.Output partnerOfId(@Argument String id) { return getPartnerByIdUseCase.execute(new GetPartnerByIdUseCase.Input(id)).orElse(null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java index e48f45f0..d0c78953 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java @@ -39,7 +39,7 @@ public ResponseEntity create(@RequestBody NewPartnerDTO dto) { } @GetMapping("/{id}") - public ResponseEntity get(@PathVariable Long id) { + public ResponseEntity get(@PathVariable String id) { return getPartnerByIdUseCase.execute(new GetPartnerByIdUseCase.Input(id)) .map(ResponseEntity::ok) .orElseGet(ResponseEntity.notFound()::build); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java index 8f8d44fd..44f55cf5 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java @@ -39,16 +39,16 @@ public Optional customerOfEmail(String email) { @Override public Customer create(Customer customer) { this.customers.put(customer.customerId().value().toString(), customer); - this.customersByCPF.put(customer.cpf(), customer); - this.customersByEmail.put(customer.email(), customer); + this.customersByCPF.put(customer.cpf().value(), customer); + this.customersByEmail.put(customer.email().value(), customer); return customer; } @Override public Customer update(Customer customer) { this.customers.put(customer.customerId().value().toString(), customer); - this.customersByCPF.put(customer.cpf(), customer); - this.customersByEmail.put(customer.email(), customer); + this.customersByCPF.put(customer.cpf().value(), customer); + this.customersByEmail.put(customer.email().value(), customer); return customer; } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java new file mode 100644 index 00000000..76ad2a7f --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application; + +import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +public class InMemoryPartnerRepository implements PartnerRepository { + + private final Map partners; + private final Map partnersByCNPJ; + private final Map partnersByEmail; + + public InMemoryPartnerRepository() { + this.partners = new HashMap<>(); + this.partnersByCNPJ = new HashMap<>(); + this.partnersByEmail = new HashMap<>(); + } + + @Override + public Optional partnerOfId(PartnerId anId) { + return Optional.ofNullable(this.partners.get(Objects.requireNonNull(anId).value().toString())); + } + + @Override + public Optional partnerOfCNPJ(String cnpj) { + return Optional.ofNullable(this.partnersByCNPJ.get(Objects.requireNonNull(cnpj))); + } + + @Override + public Optional partnerOfEmail(String email) { + return Optional.ofNullable(this.partnersByEmail.get(Objects.requireNonNull(email))); + } + + @Override + public Partner create(Partner partner) { + this.partners.put(partner.partnerId().value().toString(), partner); + this.partnersByCNPJ.put(partner.cnpj().value(), partner); + this.partnersByEmail.put(partner.email().value(), partner); + return partner; + } + + @Override + public Partner update(Partner partner) { + this.partners.put(partner.partnerId().value().toString(), partner); + this.partnersByCNPJ.put(partner.cnpj().value(), partner); + this.partnersByEmail.put(partner.email().value(), partner); + return partner; + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java index 29028957..8c7e34e9 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java @@ -1,18 +1,11 @@ package br.com.fullcycle.hexagonal.application.usecases; +import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.entities.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.util.Optional; -import java.util.UUID; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; public class CreatePartnerUseCaseTest { @@ -20,23 +13,15 @@ public class CreatePartnerUseCaseTest { @DisplayName("Deve criar um parceiro") public void testCreatePartner() { // given - final var expectedCNPJ = "41536538000100"; + final var expectedCNPJ = "41.536.538/0001-00"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); // when - final var partnerService = Mockito.mock(PartnerService.class); - when(partnerService.findByCnpj(expectedCNPJ)).thenReturn(Optional.empty()); - when(partnerService.findByEmail(expectedEmail)).thenReturn(Optional.empty()); - when(partnerService.save(any())).thenAnswer(a -> { - var customer = a.getArgument(0, Partner.class); - customer.setId(UUID.randomUUID().getMostSignificantBits()); - return customer; - }); - - final var useCase = new CreatePartnerUseCase(partnerService); + final var partnerRepository = new InMemoryPartnerRepository(); + final var useCase = new CreatePartnerUseCase(partnerRepository); final var output = useCase.execute(createInput); // then @@ -50,24 +35,20 @@ public void testCreatePartner() { @DisplayName("Não deve cadastrar um parceiro com CNPJ duplicado") public void testCreateWithDuplicatedCNPJShouldFail() throws Exception { // given - final var expectedCNPJ = "41536538000100"; + final var expectedCNPJ = "41.536.538/0001-00"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Partner already exists"; - final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); + final var aPartner = Partner.newPartner(expectedName, "41.536.538/0002-00", expectedEmail); - final var aPartner = new Partner(); - aPartner.setId(UUID.randomUUID().getMostSignificantBits()); - aPartner.setCnpj(expectedCNPJ); - aPartner.setName(expectedName); - aPartner.setEmail(expectedEmail); + final var partnerRepository = new InMemoryPartnerRepository(); + partnerRepository.create(aPartner); - // when - final var partnerService = Mockito.mock(PartnerService.class); - when(partnerService.findByCnpj(expectedCNPJ)).thenReturn(Optional.of(aPartner)); + final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); - final var useCase = new CreatePartnerUseCase(partnerService); + // when + final var useCase = new CreatePartnerUseCase(partnerRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); // then @@ -78,24 +59,20 @@ public void testCreateWithDuplicatedCNPJShouldFail() throws Exception { @DisplayName("Não deve cadastrar um parceiro com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { // given - final var expectedCNPJ = "41536538000100"; + final var expectedCNPJ = "41.536.538/0001-00"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Partner already exists"; - final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); + final var aPartner = Partner.newPartner(expectedName, "41.536.538/0002-00", expectedEmail); - final var aPartner = new Partner(); - aPartner.setId(UUID.randomUUID().getMostSignificantBits()); - aPartner.setCnpj(expectedCNPJ); - aPartner.setName(expectedName); - aPartner.setEmail(expectedEmail); + final var partnerRepository = new InMemoryPartnerRepository(); + partnerRepository.create(aPartner); - // when - final var partnerService = Mockito.mock(PartnerService.class); - when(partnerService.findByEmail(expectedEmail)).thenReturn(Optional.of(aPartner)); + final var createInput = new CreatePartnerUseCase.Input(expectedCNPJ, expectedEmail, expectedName); - final var useCase = new CreatePartnerUseCase(partnerService); + // when + final var useCase = new CreatePartnerUseCase(partnerRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); // then diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java index ab76e4e1..61cb76ff 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.entities.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -18,24 +18,21 @@ class GetPartnerByIdUseCaseTest { @DisplayName("Deve obter um parceiro por id") public void testGetById() { // given - final var expectedID = UUID.randomUUID().getMostSignificantBits(); - final var expectedCNPJ = "41536538000100"; + final var expectedCNPJ = "41.536.538/0001-00"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; - final var aPartner = new Partner(); - aPartner.setId(expectedID); - aPartner.setCnpj(expectedCNPJ); - aPartner.setName(expectedName); - aPartner.setEmail(expectedEmail); + final var aPartner = Partner.newPartner(expectedName, expectedCNPJ, expectedEmail); + + final var partnerRepository = new InMemoryPartnerRepository(); + partnerRepository.create(aPartner); + + final var expectedID = aPartner.partnerId().value().toString(); final var input = new GetPartnerByIdUseCase.Input(expectedID); // when - final var partnerService = Mockito.mock(PartnerService.class); - when(partnerService.findById(expectedID)).thenReturn(Optional.of(aPartner)); - - final var useCase = new GetPartnerByIdUseCase(partnerService); + final var useCase = new GetPartnerByIdUseCase(partnerRepository); final var output = useCase.execute(input).get(); // then @@ -49,15 +46,13 @@ public void testGetById() { @DisplayName("Deve obter vazio ao tentar recuperar um parceiro não existente por id") public void testGetByIdWIthInvalidId() { // given - final var expectedID = UUID.randomUUID().getMostSignificantBits(); + final var expectedID = UUID.randomUUID().toString(); final var input = new GetPartnerByIdUseCase.Input(expectedID); // when - final var partnerService = Mockito.mock(PartnerService.class); - when(partnerService.findById(expectedID)).thenReturn(Optional.empty()); - - final var useCase = new GetPartnerByIdUseCase(partnerService); + final var partnerRepository = new InMemoryPartnerRepository(); + final var useCase = new GetPartnerByIdUseCase(partnerRepository); final var output = useCase.execute(input); // then From 367164cc05d262cf3f4e6d411578cf8e666cef99 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 20 Aug 2023 17:49:02 -0300 Subject: [PATCH 11/22] 11-modelando-as-entidades-de-dominio-parte-3 --- .../application/entities/Customer.java | 2 +- .../application/entities/CustomerId.java | 6 +- .../hexagonal/application/entities/Event.java | 63 +++++++++++++++++++ .../application/entities/EventId.java | 26 ++++++++ .../application/entities/Partner.java | 2 +- .../application/entities/PartnerId.java | 8 +-- .../repositories/EventRepository.java | 16 +++++ .../usecases/CreateCustomerUseCase.java | 2 +- .../usecases/CreateEventUseCase.java | 49 +++++++-------- .../usecases/CreatePartnerUseCase.java | 2 +- .../usecases/GetCustomerByIdUseCase.java | 2 +- .../usecases/GetPartnerByIdUseCase.java | 2 +- .../configurations/UseCaseConfig.java | 3 +- .../infrastructure/dtos/NewEventDTO.java | 2 +- .../application/InMemoryEventRepository.java | 36 +++++++++++ .../usecases/CreateEventUseCaseIT.java | 5 +- .../usecases/CreateEventUseCaseTest.java | 50 +++++---------- .../rest/EventControllerTest.java | 6 +- 18 files changed, 204 insertions(+), 78 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java index 50be5385..50200ae7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java @@ -4,7 +4,7 @@ public class Customer { - private CustomerId customerId; + private final CustomerId customerId; private Name name; private Cpf cpf; private Email email; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java index a106b5b3..466ccdde 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java @@ -4,7 +4,7 @@ import java.util.UUID; -public record CustomerId(UUID value) { +public record CustomerId(String value) { public CustomerId { if (value == null) { @@ -13,12 +13,12 @@ public record CustomerId(UUID value) { } public static CustomerId unique() { - return new CustomerId(UUID.randomUUID()); + return new CustomerId(UUID.randomUUID().toString()); } public static CustomerId with(final String value) { try { - return new CustomerId(UUID.fromString(value)); + return new CustomerId(UUID.fromString(value).toString()); } catch (IllegalArgumentException ex) { throw new ValidationException("Invalid value for CustomerId"); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java new file mode 100644 index 00000000..09dfcdca --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java @@ -0,0 +1,63 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class Event { + + private final EventId eventId; + private Name name; + private LocalDate date; + private int totalSpots; + private PartnerId partnerId; + + public Event(final EventId eventId, final String name, final String date, final Integer totalSpots, final PartnerId partnerId) { + if (eventId == null) { + throw new ValidationException("Invalid eventId for Event"); + } + + if (date == null) { + throw new ValidationException("Invalid date for Event"); + } + + if (totalSpots == null) { + throw new ValidationException("Invalid totalSpots for Event"); + } + + if (partnerId == null) { + throw new ValidationException("Invalid totalSpots for Event"); + } + + this.eventId = eventId; + this.name = new Name(name); + this.date = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE); + this.totalSpots = totalSpots; + this.partnerId = partnerId; + } + + public static Event newEvent(final String name, final String date, final Integer totalSpots, final Partner partner) { + return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId()); + } + + public EventId eventId() { + return eventId; + } + + public Name name() { + return name; + } + + public LocalDate date() { + return date; + } + + public int totalSpots() { + return totalSpots; + } + + public PartnerId partnerId() { + return partnerId; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java new file mode 100644 index 00000000..3234c00d --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java @@ -0,0 +1,26 @@ +package br.com.fullcycle.hexagonal.application.entities; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +import java.util.UUID; + +public record EventId(String value) { + + public EventId { + if (value == null) { + throw new ValidationException("Invalid value for EventId"); + } + } + + public static EventId unique() { + return new EventId(UUID.randomUUID().toString()); + } + + public static EventId with(final String value) { + try { + return new EventId(UUID.fromString(value).toString()); + } catch (IllegalArgumentException ex) { + throw new ValidationException("Invalid value for EventId"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java index b26aeda7..be51dc58 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java @@ -4,7 +4,7 @@ public class Partner { - private PartnerId partnerId; + private final PartnerId partnerId; private Name name; private Cnpj cnpj; private Email email; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java index 10e4fa04..3c5e8c2a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java @@ -4,21 +4,21 @@ import java.util.UUID; -public record PartnerId(UUID value) { +public record PartnerId(String value) { public PartnerId { if (value == null) { - throw new ValidationException("Invalid value for CustomerId"); + throw new ValidationException("Invalid value for PartnerId"); } } public static PartnerId unique() { - return new PartnerId(UUID.randomUUID()); + return new PartnerId(UUID.randomUUID().toString()); } public static PartnerId with(final String value) { try { - return new PartnerId(UUID.fromString(value)); + return new PartnerId(UUID.fromString(value).toString()); } catch (IllegalArgumentException ex) { throw new ValidationException("Invalid value for PartnerId"); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java new file mode 100644 index 00000000..2f6d876a --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java @@ -0,0 +1,16 @@ +package br.com.fullcycle.hexagonal.application.repositories; + +import br.com.fullcycle.hexagonal.application.entities.Event; +import br.com.fullcycle.hexagonal.application.entities.EventId; + +import java.util.Optional; + +public interface EventRepository { + + Optional eventOfId(EventId anId); + + Event create(Event event); + + Event update(Event event); + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java index 652e1c4c..1afb0977 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -27,7 +27,7 @@ public Output execute(final Input input) { var customer = customerRepository.create(Customer.newCustomer(input.name, input.cpf, input.email)); return new Output( - customer.customerId().value().toString(), + customer.customerId().value(), customer.cpf().value(), customer.email().value(), customer.name().value() diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java index 187a70c9..25de9ee7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java @@ -1,45 +1,44 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.entities.Event; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Event; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.Objects; public class CreateEventUseCase extends UseCase { - private final EventService eventService; - private final PartnerService partnerService; + private final EventRepository eventRepository; + private final PartnerRepository partnerRepository; - public CreateEventUseCase(final EventService eventService, final PartnerService partnerService) { - this.eventService = Objects.requireNonNull(eventService); - this.partnerService = Objects.requireNonNull(partnerService); + public CreateEventUseCase(final EventRepository eventRepository, final PartnerRepository partnerRepository) { + this.eventRepository = Objects.requireNonNull(eventRepository); + this.partnerRepository = Objects.requireNonNull(partnerRepository); } @Override public Output execute(final Input input) { - var event = new Event(); - event.setDate(LocalDate.parse(input.date, DateTimeFormatter.ISO_DATE)); - event.setName(input.name); - event.setTotalSpots(input.totalSpots); - - partnerService.findById(input.partnerId) - .ifPresentOrElse(event::setPartner, () -> { - throw new ValidationException("Partner not found"); - }); - - event = eventService.save(event); - - return new Output(event.getId(), input.date, event.getName(), input.totalSpots, input.partnerId); + final var aPartner = partnerRepository.partnerOfId(PartnerId.with(input.partnerId)) + .orElseThrow(() -> new ValidationException("Partner not found")); + + final var anEvent = + eventRepository.create(Event.newEvent(input.name, input.date, input.totalSpots, aPartner)); + + return new Output( + anEvent.eventId().value(), + input.date, + anEvent.name().value(), + anEvent.totalSpots(), + anEvent.partnerId().value() + ); } - public record Input(String date, String name, Long partnerId, Integer totalSpots) { + public record Input(String date, String name, String partnerId, Integer totalSpots) { } - public record Output(Long id, String date, String name, int totalSpots, Long partnerId) { + public record Output(String id, String date, String name, int totalSpots, String partnerId) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java index d6c86011..1081b065 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java @@ -28,7 +28,7 @@ public Output execute(final Input input) { var partner = partnerRepository.create(Partner.newPartner(input.name, input.cnpj, input.email)); return new Output( - partner.partnerId().value().toString(), + partner.partnerId().value(), partner.cnpj().value(), partner.email().value(), partner.name().value() diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java index 5bf74506..bad46b80 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -20,7 +20,7 @@ public GetCustomerByIdUseCase(final CustomerRepository customerRepository) { public Optional execute(final Input input) { return customerRepository.customerOfId(CustomerId.with(input.id)) .map(c -> new Output( - c.customerId().value().toString(), + c.customerId().value(), c.cpf().value(), c.email().value(), c.name().value()) diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java index 068023a5..e00c67ad 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java @@ -20,7 +20,7 @@ public GetPartnerByIdUseCase(final PartnerRepository partnerRepository) { public Optional execute(final Input input) { return partnerRepository.partnerOfId(PartnerId.with(input.id)) .map(partner -> new Output( - partner.partnerId().value().toString(), + partner.partnerId().value(), partner.cnpj().value(), partner.email().value(), partner.name().value() diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index edcd60b8..63358f20 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -34,7 +34,8 @@ public CreateCustomerUseCase createCustomerUseCase() { @Bean public CreateEventUseCase createEventUseCase() { - return new CreateEventUseCase(eventService, partnerService); + // TODO: Fix dependency + return new CreateEventUseCase(null, null); } @Bean diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java index 5a4790d3..aee49d71 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java @@ -4,7 +4,7 @@ public record NewEventDTO( String name, String date, Integer totalSpots, - Long partnerId + String partnerId ) { } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java new file mode 100644 index 00000000..c56270c8 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java @@ -0,0 +1,36 @@ +package br.com.fullcycle.hexagonal.application; + +import br.com.fullcycle.hexagonal.application.entities.Event; +import br.com.fullcycle.hexagonal.application.entities.EventId; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +public class InMemoryEventRepository implements EventRepository { + + private final Map events; + + public InMemoryEventRepository() { + this.events = new HashMap<>(); + } + + @Override + public Optional eventOfId(EventId anId) { + return Optional.ofNullable(this.events.get(Objects.requireNonNull(anId).value())); + } + + @Override + public Event create(Event event) { + this.events.put(event.eventId().value(), event); + return event; + } + + @Override + public Event update(Event event) { + this.events.put(event.eventId().value(), event); + return event; + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java index b4fef1e6..a29bd2e4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java @@ -1,6 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.IntegrationTest; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.infrastructure.models.Partner; import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; @@ -37,7 +38,7 @@ public void testCreate() throws Exception { final var expectedDate = "2021-01-01"; final var expectedName = "Disney on Ice"; final var expectedTotalSpots = 10; - final var expectedPartnerId = partner.getId(); + final var expectedPartnerId = partner.getId().toString(); final var createInput = new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); @@ -60,7 +61,7 @@ public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Ex final var expectedDate = "2021-01-01"; final var expectedName = "Disney on Ice"; final var expectedTotalSpots = 10; - final var expectedPartnerId = TSID.fast().toLong(); + final var expectedPartnerId = PartnerId.unique().value(); final var expectedError = "Partner not found"; final var createInput = diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java index 656abf10..82023dd0 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java @@ -1,21 +1,13 @@ package br.com.fullcycle.hexagonal.application.usecases; +import br.com.fullcycle.hexagonal.application.InMemoryEventRepository; +import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.entities.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Event; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; -import io.hypersistence.tsid.TSID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.util.Optional; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; class CreateEventUseCaseTest { @@ -23,28 +15,23 @@ class CreateEventUseCaseTest { @DisplayName("Deve criar um evento") public void testCreate() throws Exception { // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); final var expectedDate = "2021-01-01"; final var expectedName = "Disney on Ice"; final var expectedTotalSpots = 10; - final var expectedPartnerId = TSID.fast().toLong(); + final var expectedPartnerId = aPartner.partnerId().value(); final var createInput = new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); - // when - final var eventService = Mockito.mock(EventService.class); - final var partnerService = Mockito.mock(PartnerService.class); - - when(partnerService.findById(eq(expectedPartnerId))) - .thenReturn(Optional.of(new Partner())); + final var eventRepository = new InMemoryEventRepository(); + final var partnerRepository = new InMemoryPartnerRepository(); - when(eventService.save(any())).thenAnswer(a -> { - final var e = a.getArgument(0, Event.class); - e.setId(TSID.fast().toLong()); - return e; - }); + partnerRepository.create(aPartner); - final var useCase = new CreateEventUseCase(eventService, partnerService); + // when + final var useCase = new CreateEventUseCase(eventRepository, partnerRepository); final var output = useCase.execute(createInput); // then @@ -62,20 +49,17 @@ public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Ex final var expectedDate = "2021-01-01"; final var expectedName = "Disney on Ice"; final var expectedTotalSpots = 10; - final var expectedPartnerId = TSID.fast().toLong(); + final var expectedPartnerId = PartnerId.unique().value(); final var expectedError = "Partner not found"; final var createInput = new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); - // when - final var eventService = Mockito.mock(EventService.class); - final var partnerService = Mockito.mock(PartnerService.class); - - when(partnerService.findById(eq(expectedPartnerId))) - .thenReturn(Optional.empty()); + final var eventRepository = new InMemoryEventRepository(); + final var partnerRepository = new InMemoryPartnerRepository(); - final var useCase = new CreateEventUseCase(eventService, partnerService); + // when + final var useCase = new CreateEventUseCase(eventRepository, partnerRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(createInput)); // then diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index 78ced5f1..78593d89 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -60,7 +60,7 @@ void tearDown() { @DisplayName("Deve criar um evento") public void testCreate() throws Exception { - var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId()); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId().toString()); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -82,7 +82,7 @@ public void testCreate() throws Exception { @DisplayName("Deve comprar um ticket de um evento") public void testReserveTicket() throws Exception { - var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId()); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId().toString()); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -105,7 +105,7 @@ public void testReserveTicket() throws Exception { .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsByteArray(); - var actualEvent = eventRepository.findById(eventId).get(); + var actualEvent = eventRepository.findById(Long.parseLong(eventId)).get(); Assertions.assertEquals(1, actualEvent.getTickets().size()); } } \ No newline at end of file From 637f0e05901eb5e26025b90626ebeefaa77ef2e7 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 20 Aug 2023 20:27:42 -0300 Subject: [PATCH 12/22] 12-modelando-as-entidades-de-dominio-parte-4 --- .../{entities => domain}/Cnpj.java | 2 +- .../application/{entities => domain}/Cpf.java | 2 +- .../{entities => domain}/Customer.java | 20 ++- .../{entities => domain}/CustomerId.java | 2 +- .../{entities => domain}/Email.java | 2 +- .../{entities => domain}/Event.java | 86 ++++++++-- .../{entities => domain}/EventId.java | 2 +- .../application/domain/EventTicket.java | 54 +++++++ .../{entities => domain}/Name.java | 2 +- .../{entities => domain}/Partner.java | 20 ++- .../{entities => domain}/PartnerId.java | 2 +- .../hexagonal/application/domain/Ticket.java | 96 +++++++++++ .../application/domain/TicketId.java | 26 +++ .../repositories/CustomerRepository.java | 4 +- .../repositories/EventRepository.java | 4 +- .../repositories/PartnerRepository.java | 4 +- .../repositories/TicketRepository.java | 16 ++ .../usecases/CreateCustomerUseCase.java | 2 +- .../usecases/CreateEventUseCase.java | 4 +- .../usecases/CreatePartnerUseCase.java | 2 +- .../usecases/GetCustomerByIdUseCase.java | 2 +- .../usecases/GetPartnerByIdUseCase.java | 2 +- .../SubscribeCustomerToEventUseCase.java | 58 +++---- .../configurations/UseCaseConfig.java | 5 +- .../infrastructure/dtos/SubscribeDTO.java | 2 +- .../infrastructure/rest/EventController.java | 2 +- .../InMemoryCustomerRepository.java | 4 +- .../application/InMemoryEventRepository.java | 4 +- .../InMemoryPartnerRepository.java | 4 +- .../application/InMemoryTicketRepository.java | 36 +++++ .../usecases/CreateCustomerUseCaseTest.java | 2 +- .../usecases/CreateEventUseCaseIT.java | 3 +- .../usecases/CreateEventUseCaseTest.java | 4 +- .../usecases/CreatePartnerUseCaseTest.java | 2 +- .../usecases/GetCustomerByIdUseCaseTest.java | 2 +- .../usecases/GetPartnerByIdUseCaseTest.java | 6 +- .../SubscribeCustomerToEventUseCaseTest.java | 152 +++++++++--------- .../rest/EventControllerTest.java | 2 +- 38 files changed, 471 insertions(+), 173 deletions(-) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Cnpj.java (84%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Cpf.java (84%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Customer.java (76%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/CustomerId.java (92%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Email.java (85%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Event.java (52%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/EventId.java (92%) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Name.java (81%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/Partner.java (76%) rename src/main/java/br/com/fullcycle/hexagonal/application/{entities => domain}/PartnerId.java (92%) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java similarity index 84% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java index 7c407e45..ec2ea3d5 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cnpj.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java similarity index 84% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java index 877ee273..65d16d3a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Cpf.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java similarity index 76% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java index 50200ae7..9a5653a4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; @@ -15,9 +15,9 @@ public Customer(final CustomerId customerId, final String name, final String cpf } this.customerId = customerId; - this.name = new Name(name); - this.cpf = new Cpf(cpf); - this.email = new Email(email); + this.setName(name); + this.setCpf(cpf); + this.setEmail(email); } public static Customer newCustomer(String name, String cpf, String email) { @@ -39,4 +39,16 @@ public Cpf cpf() { public Email email() { return email; } + + private void setCpf(final String cpf) { + this.cpf = new Cpf(cpf); + } + + private void setEmail(final String email) { + this.email = new Email(email); + } + + private void setName(final String name) { + this.name = new Name(name); + } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java similarity index 92% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java index 466ccdde..1cdfffbe 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/CustomerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java similarity index 85% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java index dc131c40..992ca890 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Email.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java similarity index 52% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java index 09dfcdca..c63880c8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java @@ -1,46 +1,66 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; public class Event { + private static final int ONE = 1; + private final EventId eventId; private Name name; private LocalDate date; private int totalSpots; private PartnerId partnerId; + private Set tickets; public Event(final EventId eventId, final String name, final String date, final Integer totalSpots, final PartnerId partnerId) { + this(eventId); + this.setName(name); + this.setDate(date); + this.setTotalSpots(totalSpots); + this.setPartnerId(partnerId); + } + + private Event(final EventId eventId) { if (eventId == null) { throw new ValidationException("Invalid eventId for Event"); } - if (date == null) { - throw new ValidationException("Invalid date for Event"); - } - - if (totalSpots == null) { - throw new ValidationException("Invalid totalSpots for Event"); - } - - if (partnerId == null) { - throw new ValidationException("Invalid totalSpots for Event"); - } - this.eventId = eventId; - this.name = new Name(name); - this.date = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE); - this.totalSpots = totalSpots; - this.partnerId = partnerId; + this.tickets = new HashSet<>(0); } public static Event newEvent(final String name, final String date, final Integer totalSpots, final Partner partner) { return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId()); } + public Ticket reserveTicket(final CustomerId aCustomerId) { + this.allTickets().stream() + .filter(it -> Objects.equals(it.customerId(), aCustomerId)) + .findFirst() + .ifPresent(it -> { + throw new ValidationException("Email already registered"); + }); + + if (totalSpots() < allTickets().size() + ONE) { + throw new ValidationException("Event sold out"); + } + + final var newTicket = + Ticket.newTicket(aCustomerId, eventId()); + + this.tickets.add(new EventTicket(newTicket.ticketId(), eventId(), aCustomerId, allTickets().size() + 1)); + + return newTicket; + } + public EventId eventId() { return eventId; } @@ -60,4 +80,36 @@ public int totalSpots() { public PartnerId partnerId() { return partnerId; } + + public Set allTickets() { + return Collections.unmodifiableSet(tickets); + } + + private void setName(final String name) { + this.name = new Name(name); + } + + private void setDate(final String date) { + if (date == null) { + throw new ValidationException("Invalid date for Event"); + } + + this.date = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE); + } + + private void setPartnerId(final PartnerId partnerId) { + if (partnerId == null) { + throw new ValidationException("Invalid totalSpots for Event"); + } + + this.partnerId = partnerId; + } + + private void setTotalSpots(final Integer totalSpots) { + if (totalSpots == null) { + throw new ValidationException("Invalid totalSpots for Event"); + } + + this.totalSpots = totalSpots; + } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java similarity index 92% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java index 3234c00d..7a3233cf 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/EventId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java new file mode 100644 index 00000000..c37cfcc0 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application.domain; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +public class EventTicket { + + private final TicketId ticketId; + private final EventId eventId; + private final CustomerId customerId; + private int ordering; + + protected EventTicket(final TicketId ticketId, final EventId eventId, final CustomerId customerId, final Integer ordering) { + if (ticketId == null) { + throw new ValidationException("Invalid ticketId for EventTicket"); + } + + if (eventId == null) { + throw new ValidationException("Invalid eventId for EventTicket"); + } + + if (customerId == null) { + throw new ValidationException("Invalid customerId for EventTicket"); + } + + this.ticketId = ticketId; + this.eventId = eventId; + this.customerId = customerId; + this.setOrdering(ordering); + } + + public TicketId ticketId() { + return ticketId; + } + + public EventId eventId() { + return eventId; + } + + public int ordering() { + return ordering; + } + + public CustomerId customerId() { + return customerId; + } + + private void setOrdering(final Integer ordering) { + if (ordering == null) { + throw new ValidationException("Invalid ordering for EventTicket"); + } + + this.ordering = ordering; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java similarity index 81% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java index 51256642..adc4304d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Name.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java similarity index 76% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java index be51dc58..ff880a23 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/Partner.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; @@ -15,9 +15,9 @@ public Partner(final PartnerId partnerId, final String name, final String cnpj, } this.partnerId = partnerId; - this.name = new Name(name); - this.cnpj = new Cnpj(cnpj); - this.email = new Email(email); + this.setName(name); + this.setCnpj(cnpj); + this.setEmail(email); } public static Partner newPartner(String name, String cnpj, String email) { @@ -39,4 +39,16 @@ public Cnpj cnpj() { public Email email() { return email; } + + private void setCnpj(final String cnpj) { + this.cnpj = new Cnpj(cnpj); + } + + private void setEmail(final String email) { + this.email = new Email(email); + } + + private void setName(final String name) { + this.name = new Name(name); + } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java similarity index 92% rename from src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java index 3c5e8c2a..2c6ebfc4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/entities/PartnerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.entities; +package br.com.fullcycle.hexagonal.application.domain; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java new file mode 100644 index 00000000..fffe672f --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java @@ -0,0 +1,96 @@ +package br.com.fullcycle.hexagonal.application.domain; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; + +import java.time.Instant; + +public class Ticket { + + private final TicketId ticketId; + private CustomerId customerId; + private EventId eventId; + private TicketStatus status; + private Instant paidAt; + private Instant reservedAt; + + public Ticket( + final TicketId ticketId, + final CustomerId customerId, + final EventId eventId, + final TicketStatus status, + final Instant paidAt, + final Instant reservedAt + ) { + this.ticketId = ticketId; + this.setCustomerId(customerId); + this.setEventId(eventId); + this.setStatus(status); + this.setPaidAt(paidAt); + this.setReservedAt(reservedAt); + } + + public static Ticket newTicket(final CustomerId customerId, final EventId eventId) { + return new Ticket(TicketId.unique(), customerId, eventId, TicketStatus.PENDING, null, Instant.now()); + } + + public TicketId ticketId() { + return ticketId; + } + + public CustomerId customerId() { + return customerId; + } + + public EventId eventId() { + return eventId; + } + + public TicketStatus status() { + return status; + } + + public Instant paidAt() { + return paidAt; + } + + public Instant reservedAt() { + return reservedAt; + } + + private void setCustomerId(final CustomerId customerId) { + if (customerId == null) { + throw new ValidationException("Invalid customerId for Ticket"); + } + + this.customerId = customerId; + } + + private void setEventId(final EventId eventId) { + if (eventId == null) { + throw new ValidationException("Invalid eventId for Ticket"); + } + + this.eventId = eventId; + } + + private void setStatus(final TicketStatus status) { + if (status == null) { + throw new ValidationException("Invalid status for Ticket"); + } + + this.status = status; + } + + private void setPaidAt(Instant paidAt) { + this.paidAt = paidAt; + } + + private void setReservedAt(Instant reservedAt) { + if (reservedAt == null) { + throw new ValidationException("Invalid reservedAt for Ticket"); + } + + this.reservedAt = reservedAt; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java new file mode 100644 index 00000000..3f767bde --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java @@ -0,0 +1,26 @@ +package br.com.fullcycle.hexagonal.application.domain; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; + +import java.util.UUID; + +public record TicketId(String value) { + + public TicketId { + if (value == null) { + throw new ValidationException("Invalid value for TicketId"); + } + } + + public static TicketId unique() { + return new TicketId(UUID.randomUUID().toString()); + } + + public static TicketId with(final String value) { + try { + return new TicketId(UUID.fromString(value).toString()); + } catch (IllegalArgumentException ex) { + throw new ValidationException("Invalid value for TicketId"); + } + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java index 3228f27a..9b05a495 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.entities.Customer; -import br.com.fullcycle.hexagonal.application.entities.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.Customer; +import br.com.fullcycle.hexagonal.application.domain.CustomerId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java index 2f6d876a..4c28f536 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.entities.Event; -import br.com.fullcycle.hexagonal.application.entities.EventId; +import br.com.fullcycle.hexagonal.application.domain.Event; +import br.com.fullcycle.hexagonal.application.domain.EventId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java index 8f43196f..0c6ed151 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.entities.Partner; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java new file mode 100644 index 00000000..ae3ed19c --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java @@ -0,0 +1,16 @@ +package br.com.fullcycle.hexagonal.application.repositories; + +import br.com.fullcycle.hexagonal.application.domain.Ticket; +import br.com.fullcycle.hexagonal.application.domain.TicketId; + +import java.util.Optional; + +public interface TicketRepository { + + Optional ticketOfId(TicketId anId); + + Ticket create(Ticket ticket); + + Ticket update(Ticket ticket); + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java index 1afb0977..ae620b92 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.entities.Customer; +import br.com.fullcycle.hexagonal.application.domain.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java index 25de9ee7..baf50115 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.entities.Event; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.Event; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java index 1081b065..be88a0fd 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.domain.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java index bad46b80..62e8fca1 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.entities.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.CustomerId; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java index e00c67ad..405ef380 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java index 77f60e56..01487385 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java @@ -1,58 +1,52 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.UseCase; +import br.com.fullcycle.hexagonal.application.domain.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.EventId; +import br.com.fullcycle.hexagonal.application.domain.Ticket; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; import java.time.Instant; import java.util.Objects; public class SubscribeCustomerToEventUseCase extends UseCase { - private final CustomerService customerService; - private final EventService eventService; - - public SubscribeCustomerToEventUseCase(final CustomerService customerService, final EventService eventService) { - this.customerService = Objects.requireNonNull(customerService); - this.eventService = Objects.requireNonNull(eventService); + private final CustomerRepository customerRepository; + private final EventRepository eventRepository; + private final TicketRepository ticketRepository; + + public SubscribeCustomerToEventUseCase( + final CustomerRepository customerRepository, + final EventRepository eventRepository, + final TicketRepository ticketRepository + ) { + this.customerRepository = Objects.requireNonNull(customerRepository); + this.eventRepository = Objects.requireNonNull(eventRepository); + this.ticketRepository = Objects.requireNonNull(ticketRepository); } @Override public Output execute(final Input input) { - var customer = customerService.findById(input.customerId()) + var aCustomer = customerRepository.customerOfId(CustomerId.with(input.customerId())) .orElseThrow(() -> new ValidationException("Customer not found")); - var event = eventService.findById(input.eventId) + var anEvent = eventRepository.eventOfId(EventId.with(input.eventId())) .orElseThrow(() -> new ValidationException("Event not found")); - eventService.findTicketByEventIdAndCustomerId(input.eventId, input.customerId) - .ifPresent(t -> { - throw new ValidationException("Email already registered"); - }); - - if (event.getTotalSpots() < event.getTickets().size() + 1) { - throw new ValidationException("Event sold out"); - } - - var ticket = new Ticket(); - ticket.setEvent(event); - ticket.setCustomer(customer); - ticket.setReservedAt(Instant.now()); - ticket.setStatus(TicketStatus.PENDING); - - event.getTickets().add(ticket); + final Ticket ticket = anEvent.reserveTicket(aCustomer.customerId()); - eventService.save(event); + ticketRepository.create(ticket); + eventRepository.update(anEvent); - return new Output(event.getId(), ticket.getStatus().name(), ticket.getReservedAt()); + return new Output(anEvent.eventId().value(), ticket.ticketId().value(), ticket.status().name(), ticket.reservedAt()); } - public record Input(Long customerId, Long eventId) { + public record Input(String customerId, String eventId) { } - public record Output(Long eventId, String ticketStatus, Instant reservationDate) { + public record Output(String eventId, String ticketId, String ticketStatus, Instant reservationDate) { } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 63358f20..0d071ba7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -40,6 +40,7 @@ public CreateEventUseCase createEventUseCase() { @Bean public CreatePartnerUseCase createPartnerUseCase() { + // TODO: Fix dependency return new CreatePartnerUseCase(null); } @@ -51,11 +52,13 @@ public GetCustomerByIdUseCase getCustomerByIdUseCase() { @Bean public GetPartnerByIdUseCase getPartnerByIdUseCase() { + // TODO: Fix dependency return new GetPartnerByIdUseCase(null); } @Bean public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { - return new SubscribeCustomerToEventUseCase(customerService, eventService); + // TODO: Fix dependency + return new SubscribeCustomerToEventUseCase(null, null, null); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java index ec7536e4..7018cc1e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java @@ -1,4 +1,4 @@ package br.com.fullcycle.hexagonal.infrastructure.dtos; -public record SubscribeDTO(Long customerId, Long eventId) { +public record SubscribeDTO(String customerId, String eventId) { } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java index 371315ee..587ebda1 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java @@ -45,7 +45,7 @@ public ResponseEntity create(@RequestBody NewEventDTO dto) { @Transactional @PostMapping(value = "/{id}/subscribe") - public ResponseEntity subscribe(@PathVariable Long id, @RequestBody SubscribeDTO dto) { + public ResponseEntity subscribe(@PathVariable String id, @RequestBody SubscribeDTO dto) { try { final var output = subscribeCustomerToEventUseCase.execute(new SubscribeCustomerToEventUseCase.Input(dto.customerId(), id)); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java index 44f55cf5..4ca8dec6 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application; -import br.com.fullcycle.hexagonal.application.entities.Customer; -import br.com.fullcycle.hexagonal.application.entities.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.Customer; +import br.com.fullcycle.hexagonal.application.domain.CustomerId; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java index c56270c8..374228f5 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application; -import br.com.fullcycle.hexagonal.application.entities.Event; -import br.com.fullcycle.hexagonal.application.entities.EventId; +import br.com.fullcycle.hexagonal.application.domain.Event; +import br.com.fullcycle.hexagonal.application.domain.EventId; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java index 76ad2a7f..ae8aeaf6 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application; -import br.com.fullcycle.hexagonal.application.entities.Partner; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java new file mode 100644 index 00000000..e5db8f48 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java @@ -0,0 +1,36 @@ +package br.com.fullcycle.hexagonal.application; + +import br.com.fullcycle.hexagonal.application.domain.Ticket; +import br.com.fullcycle.hexagonal.application.domain.TicketId; +import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +public class InMemoryTicketRepository implements TicketRepository { + + private final Map tickets; + + public InMemoryTicketRepository() { + this.tickets = new HashMap<>(); + } + + @Override + public Optional ticketOfId(TicketId anId) { + return Optional.ofNullable(this.tickets.get(Objects.requireNonNull(anId).value())); + } + + @Override + public Ticket create(Ticket ticket) { + this.tickets.put(ticket.ticketId().value(), ticket); + return ticket; + } + + @Override + public Ticket update(Ticket ticket) { + this.tickets.put(ticket.ticketId().value(), ticket); + return ticket; + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java index 1930557e..4c4bbc98 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.entities.Customer; +import br.com.fullcycle.hexagonal.application.domain.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java index a29bd2e4..d2e28f27 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java @@ -1,12 +1,11 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.IntegrationTest; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.infrastructure.models.Partner; import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; -import io.hypersistence.tsid.TSID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java index 82023dd0..e43304d9 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java @@ -2,8 +2,8 @@ import br.com.fullcycle.hexagonal.application.InMemoryEventRepository; import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.entities.Partner; -import br.com.fullcycle.hexagonal.application.entities.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.domain.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java index 8c7e34e9..ee5c4d09 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.domain.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java index 889c347b..6fe1016c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.entities.Customer; +import br.com.fullcycle.hexagonal.application.domain.Customer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java index 61cb76ff..78fe5c0c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java @@ -1,17 +1,13 @@ package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.entities.Partner; +import br.com.fullcycle.hexagonal.application.domain.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import java.util.Optional; import java.util.UUID; -import static org.mockito.Mockito.when; - class GetPartnerByIdUseCaseTest { @Test diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java index d5d480a0..a4326042 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java @@ -1,23 +1,15 @@ package br.com.fullcycle.hexagonal.application.usecases; +import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.InMemoryEventRepository; +import br.com.fullcycle.hexagonal.application.InMemoryTicketRepository; +import br.com.fullcycle.hexagonal.application.domain.*; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.models.Event; -import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; -import io.hypersistence.tsid.TSID; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.Optional; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - class SubscribeCustomerToEventUseCaseTest { @Test @@ -26,37 +18,35 @@ public void testReserveTicket() throws Exception { // given final var expectedTicketsSize = 1; - final var customerID = TSID.fast().toLong(); - final var eventID = TSID.fast().toLong(); + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); - final var aEvent = new Event(); - aEvent.setId(eventID); - aEvent.setName("Disney"); - aEvent.setTotalSpots(10); + final var customerID = aCustomer.customerId().value(); + final var eventID = anEvent.eventId().value(); final var subscribeInput = - new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); + + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + final var ticketRepository = new InMemoryTicketRepository(); + + customerRepository.create(aCustomer); + eventRepository.create(anEvent); // when - final var customerService = mock(CustomerService.class); - final var eventService = mock(EventService.class); - - when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); - when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); - when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.empty()); - when(eventService.save(any())).thenAnswer(a -> { - final var e = a.getArgument(0, Event.class); - Assertions.assertEquals(expectedTicketsSize, e.getTickets().size()); - return e; - }); - - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); final var output = useCase.execute(subscribeInput); // then Assertions.assertEquals(eventID, output.eventId()); + Assertions.assertNotNull(output.ticketId()); Assertions.assertNotNull(output.reservationDate()); Assertions.assertEquals(TicketStatus.PENDING.name(), output.ticketStatus()); + + final var actualEvent = eventRepository.eventOfId(anEvent.eventId()); + Assertions.assertEquals(expectedTicketsSize, actualEvent.get().allTickets().size()); } @Test @@ -65,19 +55,23 @@ public void testReserveTicketWithoutCustomer() throws Exception { // given final var expectedError = "Customer not found"; - final var customerID = TSID.fast().toLong(); - final var eventID = TSID.fast().toLong(); + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var customerID = CustomerId.unique().value(); + final var eventID = anEvent.eventId().value(); final var subscribeInput = new SubscribeCustomerToEventUseCase.Input(customerID, eventID); - // when - final var customerService = mock(CustomerService.class); - final var eventService = mock(EventService.class); + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + final var ticketRepository = new InMemoryTicketRepository(); - when(customerService.findById(customerID)).thenReturn(Optional.empty()); + eventRepository.create(anEvent); - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + // when + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -90,20 +84,22 @@ public void testReserveTicketWithoutEvent() throws Exception { // given final var expectedError = "Event not found"; - final var customerID = TSID.fast().toLong(); - final var eventID = TSID.fast().toLong(); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); + + final var customerID = aCustomer.customerId().value(); + final var eventID = EventId.unique().value(); final var subscribeInput = new SubscribeCustomerToEventUseCase.Input(customerID, eventID); - // when - final var customerService = mock(CustomerService.class); - final var eventService = mock(EventService.class); + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + final var ticketRepository = new InMemoryTicketRepository(); - when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); - when(eventService.findById(eventID)).thenReturn(Optional.empty()); + customerRepository.create(aCustomer); - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + // when + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -116,26 +112,28 @@ public void testReserveTicketMoreThanOnce() throws Exception { // given final var expectedError = "Email already registered"; - final var customerID = TSID.fast().toLong(); - final var eventID = TSID.fast().toLong(); + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); - final var aEvent = new Event(); - aEvent.setId(eventID); - aEvent.setName("Disney"); - aEvent.setTotalSpots(10); + final var customerID = aCustomer.customerId().value(); + final var eventID = anEvent.eventId().value(); final var subscribeInput = - new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); - // when - final var customerService = mock(CustomerService.class); - final var eventService = mock(EventService.class); + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + final var ticketRepository = new InMemoryTicketRepository(); + + final var ticket = anEvent.reserveTicket(aCustomer.customerId()); - when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); - when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); - when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.of(new Ticket())); + customerRepository.create(aCustomer); + eventRepository.create(anEvent); + ticketRepository.create(ticket); - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + // when + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -148,26 +146,30 @@ public void testReserveTicketWithoutSlots() throws Exception { // given final var expectedError = "Event sold out"; - final var customerID = TSID.fast().toLong(); - final var eventID = TSID.fast().toLong(); + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 1, aPartner); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); + final var aCustomer2 = Customer.newCustomer("Pedro Doe", "123.111.789-01", "pedro.doe@gmail.com"); - final var aEvent = new Event(); - aEvent.setId(eventID); - aEvent.setName("Disney"); - aEvent.setTotalSpots(0); + final var customerID = aCustomer.customerId().value(); + final var eventID = anEvent.eventId().value(); final var subscribeInput = - new SubscribeCustomerToEventUseCase.Input(customerID, aEvent.getId()); + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); - // when - final var customerService = mock(CustomerService.class); - final var eventService = mock(EventService.class); + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + final var ticketRepository = new InMemoryTicketRepository(); - when(customerService.findById(customerID)).thenReturn(Optional.of(new Customer())); - when(eventService.findById(eventID)).thenReturn(Optional.of(aEvent)); - when(eventService.findTicketByEventIdAndCustomerId(eventID, customerID)).thenReturn(Optional.empty()); + final var ticket = anEvent.reserveTicket(aCustomer2.customerId()); - final var useCase = new SubscribeCustomerToEventUseCase(customerService, eventService); + customerRepository.create(aCustomer); + customerRepository.create(aCustomer2); + eventRepository.create(anEvent); + ticketRepository.create(ticket); + + // when + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index 78593d89..9ebd0792 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -95,7 +95,7 @@ public void testReserveTicket() throws Exception { var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); - var sub = new SubscribeDTO(johnDoe.getId(), null); + var sub = new SubscribeDTO(johnDoe.getId().toString(), null); this.mvc.perform( MockMvcRequestBuilders.post("/events/{id}/subscribe", eventId) From 42cff770c1f509ba3bb39f1e406b1db3fc5c9281 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 20 Aug 2023 21:02:08 -0300 Subject: [PATCH 13/22] 13-modelando-as-entidades-de-dominio-consideracoes-finais-e-testes-de-domain --- .../domain/{ => customer}/Customer.java | 5 +- .../domain/{ => customer}/CustomerId.java | 2 +- .../application/domain/{ => event}/Event.java | 13 +- .../domain/{ => event}/EventId.java | 2 +- .../domain/{ => event}/EventTicket.java | 4 +- .../domain/{ => event/ticket}/Ticket.java | 4 +- .../domain/{ => event/ticket}/TicketId.java | 2 +- .../domain/{ => partner}/Partner.java | 5 +- .../domain/{ => partner}/PartnerId.java | 2 +- .../application/domain/{ => person}/Cnpj.java | 2 +- .../application/domain/{ => person}/Cpf.java | 2 +- .../domain/{ => person}/Email.java | 2 +- .../application/domain/{ => person}/Name.java | 2 +- .../repositories/CustomerRepository.java | 4 +- .../repositories/EventRepository.java | 4 +- .../repositories/PartnerRepository.java | 4 +- .../repositories/TicketRepository.java | 4 +- .../{ => usecases}/NullaryUseCase.java | 2 +- .../{ => usecases}/UnitUseCase.java | 2 +- .../application/{ => usecases}/UseCase.java | 2 +- .../{ => customer}/CreateCustomerUseCase.java | 6 +- .../GetCustomerByIdUseCase.java | 6 +- .../{ => event}/CreateEventUseCase.java | 8 +- .../SubscribeCustomerToEventUseCase.java | 10 +- .../{ => partner}/CreatePartnerUseCase.java | 6 +- .../{ => partner}/GetPartnerByIdUseCase.java | 6 +- .../configurations/UseCaseConfig.java | 7 +- .../graphql/CustomerResolver.java | 4 +- .../infrastructure/graphql/EventResolver.java | 4 +- .../graphql/PartnerResolver.java | 4 +- .../rest/CustomerController.java | 4 +- .../infrastructure/rest/EventController.java | 4 +- .../rest/PartnerController.java | 4 +- .../hexagonal/application/Dummy.java | 4 - .../domain/customer/CustomerTest.java | 77 ++++++++ .../application/domain/event/EventTest.java | 182 ++++++++++++++++++ .../domain/event/ticket/TicketTest.java | 43 +++++ .../domain/partner/PartnerTest.java | 76 ++++++++ .../application/domain/person/CnpjTest.java | 54 ++++++ .../application/domain/person/CpfTest.java | 54 ++++++ .../application/domain/person/EmailTest.java | 54 ++++++ .../InMemoryCustomerRepository.java | 6 +- .../InMemoryEventRepository.java | 6 +- .../InMemoryPartnerRepository.java | 6 +- .../InMemoryTicketRepository.java | 6 +- .../CreateCustomerUseCaseIT.java | 3 +- .../CreateCustomerUseCaseTest.java | 6 +- .../GetCustomerByIdUseCaseTest.java | 7 +- .../{ => event}/CreateEventUseCaseIT.java | 5 +- .../{ => event}/CreateEventUseCaseTest.java | 11 +- .../SubscribeCustomerToEventUseCaseTest.java | 17 +- .../CreatePartnerUseCaseTest.java | 7 +- .../GetPartnerByIdUseCaseTest.java | 7 +- .../rest/CustomerControllerTest.java | 4 +- .../rest/EventControllerTest.java | 2 +- .../rest/PartnerControllerTest.java | 4 +- 56 files changed, 677 insertions(+), 106 deletions(-) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => customer}/Customer.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => customer}/CustomerId.java (91%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => event}/Event.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => event}/EventId.java (91%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => event}/EventTicket.java (86%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => event/ticket}/Ticket.java (91%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => event/ticket}/TicketId.java (90%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => partner}/Partner.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => partner}/PartnerId.java (91%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => person}/Cnpj.java (83%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => person}/Cpf.java (83%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => person}/Email.java (84%) rename src/main/java/br/com/fullcycle/hexagonal/application/domain/{ => person}/Name.java (80%) rename src/main/java/br/com/fullcycle/hexagonal/application/{ => usecases}/NullaryUseCase.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/{ => usecases}/UnitUseCase.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/{ => usecases}/UseCase.java (82%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => customer}/CreateCustomerUseCase.java (86%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => customer}/GetCustomerByIdUseCase.java (83%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => event}/CreateEventUseCase.java (85%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => event}/SubscribeCustomerToEventUseCase.java (85%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => partner}/CreatePartnerUseCase.java (87%) rename src/main/java/br/com/fullcycle/hexagonal/application/usecases/{ => partner}/GetPartnerByIdUseCase.java (83%) delete mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java create mode 100644 src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java rename src/test/java/br/com/fullcycle/hexagonal/application/{ => repository}/InMemoryCustomerRepository.java (89%) rename src/test/java/br/com/fullcycle/hexagonal/application/{ => repository}/InMemoryEventRepository.java (80%) rename src/test/java/br/com/fullcycle/hexagonal/application/{ => repository}/InMemoryPartnerRepository.java (89%) rename src/test/java/br/com/fullcycle/hexagonal/application/{ => repository}/InMemoryTicketRepository.java (80%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => customer}/CreateCustomerUseCaseIT.java (95%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => customer}/CreateCustomerUseCaseTest.java (93%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => customer}/GetCustomerByIdUseCaseTest.java (85%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => event}/CreateEventUseCaseIT.java (93%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => event}/CreateEventUseCaseTest.java (85%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => event}/SubscribeCustomerToEventUseCaseTest.java (91%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => partner}/CreatePartnerUseCaseTest.java (91%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{ => partner}/GetPartnerByIdUseCaseTest.java (85%) diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java index 9a5653a4..c05b04a8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java @@ -1,5 +1,8 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.customer; +import br.com.fullcycle.hexagonal.application.domain.person.Cpf; +import br.com.fullcycle.hexagonal.application.domain.person.Email; +import br.com.fullcycle.hexagonal.application.domain.person.Name; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; public class Customer { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java similarity index 91% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java index 1cdfffbe..00a37293 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/CustomerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java index c63880c8..7073ab59 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java @@ -1,5 +1,10 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.event; +import br.com.fullcycle.hexagonal.application.domain.person.Name; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import java.time.LocalDate; @@ -94,7 +99,11 @@ private void setDate(final String date) { throw new ValidationException("Invalid date for Event"); } - this.date = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE); + try { + this.date = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE); + } catch (RuntimeException ex) { + throw new ValidationException("Invalid date for Event", ex); + } } private void setPartnerId(final PartnerId partnerId) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java similarity index 91% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java index 7a3233cf..bf7501d2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.event; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java similarity index 86% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java index c37cfcc0..b410cfcb 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/EventTicket.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java @@ -1,5 +1,7 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.event; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; public class EventTicket { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java similarity index 91% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java index fffe672f..944ce92e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Ticket.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java @@ -1,5 +1,7 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.event.ticket; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java similarity index 90% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java index 3f767bde..1adf4dfd 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/TicketId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.event.ticket; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java index ff880a23..942501d2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Partner.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java @@ -1,5 +1,8 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.partner; +import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; +import br.com.fullcycle.hexagonal.application.domain.person.Email; +import br.com.fullcycle.hexagonal.application.domain.person.Name; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; public class Partner { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java similarity index 91% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java index 2c6ebfc4..af3d4399 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/PartnerId.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java index ec2ea3d5..6ea42c77 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cnpj.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.person; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java index 65d16d3a..9582ebcf 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Cpf.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.person; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java similarity index 84% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java index 992ca890..c8b852f9 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Email.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.person; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java rename to src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java index adc4304d..88362edf 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/Name.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.domain; +package br.com.fullcycle.hexagonal.application.domain.person; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java index 9b05a495..4966ed9e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.domain.Customer; -import br.com.fullcycle.hexagonal.application.domain.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java index 4c28f536..48586b9d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.domain.Event; -import br.com.fullcycle.hexagonal.application.domain.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java index 0c6ed151..f24b5830 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.domain.Partner; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java index ae3ed19c..cd3ab43e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.application.repositories; -import br.com.fullcycle.hexagonal.application.domain.Ticket; -import br.com.fullcycle.hexagonal.application.domain.TicketId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java index 3c8a6827..cb2cc894 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/NullaryUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.usecases; public abstract class NullaryUseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java index c0748911..c0d178c5 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/UnitUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.usecases; public abstract class UnitUseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java index 7e8fb8ca..a33e82f8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/UseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.usecases; public abstract class UseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java similarity index 86% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java index ae620b92..6fb016ca 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.customer; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.Customer; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java index 62e8fca1..bbb48a51 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.customer; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.CustomerId; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java similarity index 85% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java index baf50115..37bd9fea 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.event; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.Event; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java similarity index 85% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java index 01487385..550a4c01 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.event; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.EventId; -import br.com.fullcycle.hexagonal.application.domain.Ticket; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java index be88a0fd..572b2995 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.partner; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java rename to src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java index 405ef380..519ccc7c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.partner; -import br.com.fullcycle.hexagonal.application.UseCase; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.usecases.UseCase; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 0d071ba7..9a50d18c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -1,6 +1,11 @@ package br.com.fullcycle.hexagonal.infrastructure.configurations; -import br.com.fullcycle.hexagonal.application.usecases.*; +import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; import br.com.fullcycle.hexagonal.infrastructure.services.EventService; import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java index b7b35b3f..0fadf904 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java index b74deea2..401b4559 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; import org.springframework.graphql.data.method.annotation.Argument; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java index 9dba3b2d..c5c72c82 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java index 03b411ad..78eca03d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java index 587ebda1..b0d11b05 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java index d0c78953..21236e0c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java @@ -1,8 +1,8 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java b/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java deleted file mode 100644 index 1ced5a49..00000000 --- a/src/test/java/br/com/fullcycle/hexagonal/application/Dummy.java +++ /dev/null @@ -1,4 +0,0 @@ -package br.com.fullcycle.hexagonal.application; - -public class Dummy { -} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java new file mode 100644 index 00000000..1d9f3e1f --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java @@ -0,0 +1,77 @@ +package br.com.fullcycle.hexagonal.application.domain.customer; + +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class CustomerTest { + + @Test + @DisplayName("Deve instanciar um cliente") + public void testCreateCustomer() { + // given + final var expectedCPF = "123.456.789-01"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + // when + final var actualCustomer = Customer.newCustomer(expectedName, expectedCPF, expectedEmail); + + // then + Assertions.assertNotNull(actualCustomer.customerId()); + Assertions.assertEquals(expectedCPF, actualCustomer.cpf().value()); + Assertions.assertEquals(expectedEmail, actualCustomer.email().value()); + Assertions.assertEquals(expectedName, actualCustomer.name().value()); + } + + @Test + @DisplayName("Não deve instanciar um cliente com CPF invalido") + public void testCreateCustomerWithInvalidCPF() { + // given + final var expectedError = "Invalid value for Cpf"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Customer.newCustomer("John Doe", "123456.789-01", "john.doe@gmail.com") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve instanciar um cliente com nome invalido") + public void testCreateCustomerWithInvalidName() { + // given + final var expectedError = "Invalid value for Name"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Customer.newCustomer(null, "123.456.789-01", "john.doe@gmail.com") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + + @Test + @DisplayName("Não deve instanciar um cliente com email invalido") + public void testCreateCustomerWithInvalidEmail() { + // given + final var expectedError = "Invalid value for Email"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java new file mode 100644 index 00000000..3cd035a5 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java @@ -0,0 +1,182 @@ +package br.com.fullcycle.hexagonal.application.domain.event; + +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.format.DateTimeFormatter; + +public class EventTest { + + @Test + @DisplayName("Deve criar um evento") + public void testCreateEvent() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = aPartner.partnerId().value(); + final var expectedTickets = 0; + + // when + final var actualEvent = Event.newEvent(expectedName, expectedDate, expectedTotalSpots, aPartner); + + // then + Assertions.assertNotNull(actualEvent.eventId()); + Assertions.assertEquals(expectedDate, actualEvent.date().format(DateTimeFormatter.ISO_LOCAL_DATE)); + Assertions.assertEquals(expectedName, actualEvent.name().value()); + Assertions.assertEquals(expectedTotalSpots, actualEvent.totalSpots()); + Assertions.assertEquals(expectedPartnerId, actualEvent.partnerId().value()); + Assertions.assertEquals(expectedTickets, actualEvent.allTickets().size()); + } + + @Test + @DisplayName("Não deve criar um evento com nome inválido") + public void testCreateEventWithInvalidName() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var expectedError = "Invalid value for Name"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Event.newEvent(null, "2021-01-01", 10, aPartner) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve criar um evento com data inválido") + public void testCreateEventWithInvalidDate() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var expectedError = "Invalid date for Event"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Event.newEvent("Disney", "20210101", 10, aPartner) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Deve reservar um ticket quando é possível") + public void testReserveTicket() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var expectedCustomerId = aCustomer.customerId(); + final var expectedDate = "2021-01-01"; + final var expectedName = "Disney on Ice"; + final var expectedTotalSpots = 10; + final var expectedPartnerId = aPartner.partnerId().value(); + final var expectedTickets = 1; + final var expectedTicketOrder = 1; + final var expectedTicketStatus = TicketStatus.PENDING; + + final var actualEvent = Event.newEvent(expectedName, expectedDate, expectedTotalSpots, aPartner); + + final var expectedEventId = actualEvent.eventId(); + + // when + final var actualTicket = actualEvent.reserveTicket(aCustomer.customerId()); + + // then + Assertions.assertNotNull(actualTicket.ticketId()); + Assertions.assertNotNull(actualTicket.reservedAt()); + Assertions.assertNull(actualTicket.paidAt()); + Assertions.assertEquals(expectedEventId, actualTicket.eventId()); + Assertions.assertEquals(expectedCustomerId, actualTicket.customerId()); + Assertions.assertEquals(expectedTicketStatus, actualTicket.status()); + + Assertions.assertEquals(expectedDate, actualEvent.date().format(DateTimeFormatter.ISO_LOCAL_DATE)); + Assertions.assertEquals(expectedName, actualEvent.name().value()); + Assertions.assertEquals(expectedTotalSpots, actualEvent.totalSpots()); + Assertions.assertEquals(expectedPartnerId, actualEvent.partnerId().value()); + Assertions.assertEquals(expectedTickets, actualEvent.allTickets().size()); + + final var actualEventTicket = actualEvent.allTickets().iterator().next(); + Assertions.assertEquals(expectedTicketOrder, actualEventTicket.ordering()); + Assertions.assertEquals(expectedEventId, actualEventTicket.eventId()); + Assertions.assertEquals(expectedCustomerId, actualEventTicket.customerId()); + Assertions.assertEquals(actualTicket.ticketId(), actualEventTicket.ticketId()); + } + + @Test + @DisplayName("Não deve reservar um ticket quando o evento está esgotado") + public void testReserveTicketWhenEventIsSoldOut() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var aCustomer2 = + Customer.newCustomer("John1 Doe", "111.456.789-01", "john1.doe@gmail.com"); + + + final var expectedTotalSpots = 1; + final var expectedError = "Event sold out"; + + final var actualEvent = Event.newEvent("Disney on Ice", "2021-01-01", expectedTotalSpots, aPartner); + + actualEvent.reserveTicket(aCustomer.customerId()); + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> actualEvent.reserveTicket(aCustomer2.customerId()) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve reservar dois tickets para um mesmo cliente") + public void testReserveTwoTicketsForTheSameClient() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var expectedTotalSpots = 1; + final var expectedError = "Email already registered"; + + final var actualEvent = Event.newEvent("Disney on Ice", "2021-01-01", expectedTotalSpots, aPartner); + + actualEvent.reserveTicket(aCustomer.customerId()); + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> actualEvent.reserveTicket(aCustomer.customerId()) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java new file mode 100644 index 00000000..b4de7c4f --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java @@ -0,0 +1,43 @@ +package br.com.fullcycle.hexagonal.application.domain.event.ticket; + +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TicketTest { + + @Test + @DisplayName("Deve criar um ticket") + public void testReserveTicket() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var anEvent = + Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var expectedTickets = 1; + final var expectedTicketOrder = 1; + final var expectedTicketStatus = TicketStatus.PENDING; + final var expectedEventId = anEvent.eventId(); + final var expectedCustomerId = aCustomer.customerId(); + + // when + final var actualTicket = Ticket.newTicket(aCustomer.customerId(), anEvent.eventId()); + + // then + Assertions.assertNotNull(actualTicket.ticketId()); + Assertions.assertNotNull(actualTicket.reservedAt()); + Assertions.assertNull(actualTicket.paidAt()); + Assertions.assertEquals(expectedEventId, actualTicket.eventId()); + Assertions.assertEquals(expectedCustomerId, actualTicket.customerId()); + Assertions.assertEquals(expectedTicketStatus, actualTicket.status()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java new file mode 100644 index 00000000..3ef2299b --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java @@ -0,0 +1,76 @@ +package br.com.fullcycle.hexagonal.application.domain.partner; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class PartnerTest { + + @Test + @DisplayName("Deve instanciar um partner") + public void testCreatePartner() { + // given + final var expectedCNPJ = "41.536.538/0001-00"; + final var expectedEmail = "john.doe@gmail.com"; + final var expectedName = "John Doe"; + + // when + final var actualPartner = Partner.newPartner(expectedName, expectedCNPJ, expectedEmail); + + // then + Assertions.assertNotNull(actualPartner.partnerId()); + Assertions.assertEquals(expectedCNPJ, actualPartner.cnpj().value()); + Assertions.assertEquals(expectedEmail, actualPartner.email().value()); + Assertions.assertEquals(expectedName, actualPartner.name().value()); + } + + @Test + @DisplayName("Não deve instanciar um partner com CNPJ invalido") + public void testCreatePartnerWithInvalidCNPJ() { + // given + final var expectedError = "Invalid value for Cnpj"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Partner.newPartner("John Doe", "123456.789-01", "john.doe@gmail.com") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve instanciar um partner com nome invalido") + public void testCreatePartnerWithInvalidName() { + // given + final var expectedError = "Invalid value for Name"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Partner.newPartner(null, "41.536.538/0001-00", "john.doe@gmail.com") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + + @Test + @DisplayName("Não deve instanciar um partner com email invalido") + public void testCreatePartnerWithInvalidEmail() { + // given + final var expectedError = "Invalid value for Email"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java new file mode 100644 index 00000000..1cfd5a62 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application.domain.person; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CnpjTest { + + @Test + @DisplayName("Deve instanciar um CNPJ valido") + public void testCreateCNPJ() { + // given + final var expectedCNPJ = "41.536.538/0001-00"; + + // when + final var actualCnpj = new Cnpj(expectedCNPJ); + + // then + Assertions.assertEquals(expectedCNPJ, actualCnpj.value()); + } + + @Test + @DisplayName("Não deve instanciar um CNPJ invalido") + public void testCreateCNPJWithInvalidValue() { + // given + final var expectedError = "Invalid value for Cnpj"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Cnpj("123456.789-01") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve instanciar um CNPJ null") + public void testCreateCNPJWithNullValue() { + // given + final var expectedError = "Invalid value for Cnpj"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Cnpj(null) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java new file mode 100644 index 00000000..fc44e758 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application.domain.person; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CpfTest { + + @Test + @DisplayName("Deve instanciar um CPF valido") + public void testCreateCPF() { + // given + final var expectedCPF = "411.536.538-00"; + + // when + final var actualCpf = new Cpf(expectedCPF); + + // then + Assertions.assertEquals(expectedCPF, actualCpf.value()); + } + + @Test + @DisplayName("Não deve instanciar um CPF invalido") + public void testCreateCPFWithInvalidValue() { + // given + final var expectedError = "Invalid value for Cpf"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Cpf("123456.789-01") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve instanciar um CPF null") + public void testCreateCPFWithNullValue() { + // given + final var expectedError = "Invalid value for Cpf"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Cpf(null) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java new file mode 100644 index 00000000..6354c179 --- /dev/null +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java @@ -0,0 +1,54 @@ +package br.com.fullcycle.hexagonal.application.domain.person; + +import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class EmailTest { + + @Test + @DisplayName("Deve instanciar um Email valido") + public void testCreateEmail() { + // given + final var expectedEmail = "john@gmail.com"; + + // when + final var actualEmail = new Email(expectedEmail); + + // then + Assertions.assertEquals(expectedEmail, actualEmail.value()); + } + + @Test + @DisplayName("Não deve instanciar um Email invalido") + public void testCreateEmailWithInvalidValue() { + // given + final var expectedError = "Invalid value for Email"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Email("josh@s") + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve instanciar um Email null") + public void testCreateEmailWithNullValue() { + // given + final var expectedError = "Invalid value for Email"; + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> new Email(null) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java similarity index 89% rename from src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java rename to src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java index 4ca8dec6..93e2cc92 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryCustomerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.repository; -import br.com.fullcycle.hexagonal.application.domain.Customer; -import br.com.fullcycle.hexagonal.application.domain.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java similarity index 80% rename from src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java rename to src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java index 374228f5..289d4c60 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryEventRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.repository; -import br.com.fullcycle.hexagonal.application.domain.Event; -import br.com.fullcycle.hexagonal.application.domain.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java similarity index 89% rename from src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java rename to src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java index ae8aeaf6..412a0962 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryPartnerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.repository; -import br.com.fullcycle.hexagonal.application.domain.Partner; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java similarity index 80% rename from src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java rename to src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java index e5db8f48..74c68a81 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/InMemoryTicketRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.hexagonal.application.repository; -import br.com.fullcycle.hexagonal.application.domain.Ticket; -import br.com.fullcycle.hexagonal.application.domain.TicketId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; import java.util.HashMap; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java similarity index 95% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java index e00c3639..ea0914a4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java @@ -1,7 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.customer; import br.com.fullcycle.hexagonal.IntegrationTest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.infrastructure.models.Customer; import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java similarity index 93% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java index 4c4bbc98..b370c915 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateCustomerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.customer; -import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.domain.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java index 6fe1016c..4d3dbadf 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetCustomerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java @@ -1,7 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.customer; -import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.domain.Customer; +import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java similarity index 93% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java index d2e28f27..02f5ed73 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java @@ -1,8 +1,9 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.event; import br.com.fullcycle.hexagonal.IntegrationTest; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.models.Partner; import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java index e43304d9..053ed237 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java @@ -1,10 +1,11 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.event; -import br.com.fullcycle.hexagonal.application.InMemoryEventRepository; -import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.Partner; -import br.com.fullcycle.hexagonal.application.domain.PartnerId; +import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; +import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java similarity index 91% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java index a4326042..be8c29e6 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/SubscribeCustomerToEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java @@ -1,10 +1,15 @@ -package br.com.fullcycle.hexagonal.application.usecases; - -import br.com.fullcycle.hexagonal.application.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.InMemoryEventRepository; -import br.com.fullcycle.hexagonal.application.InMemoryTicketRepository; -import br.com.fullcycle.hexagonal.application.domain.*; +package br.com.fullcycle.hexagonal.application.usecases.event; + +import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; +import br.com.fullcycle.hexagonal.application.repository.InMemoryTicketRepository; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java similarity index 91% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java index ee5c4d09..20b23fe4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreatePartnerUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java @@ -1,8 +1,9 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.partner; -import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java index 78fe5c0c..475be382 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/GetPartnerByIdUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java @@ -1,7 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.hexagonal.application.usecases.partner; -import br.com.fullcycle.hexagonal.application.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.Partner; +import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java index 4a94a43c..258f21d4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.usecases.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetCustomerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index 9ebd0792..f3e00410 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -1,6 +1,6 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.usecases.CreateEventUseCase; +import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; import br.com.fullcycle.hexagonal.infrastructure.models.Customer; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java index c808b6de..c7e83509 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java @@ -1,7 +1,7 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.usecases.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.GetPartnerByIdUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; +import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; import com.fasterxml.jackson.databind.ObjectMapper; From a6f40db370e0c5776dbb7fe87819cf40bcabba46 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 20 Aug 2023 22:15:05 -0300 Subject: [PATCH 14/22] 14-interface-adapters-de-customer-partner-and-ticket --- .../application/domain/customer/Customer.java | 16 +++ .../application/domain/event/Event.java | 13 ++ .../domain/event/ticket/Ticket.java | 15 +- .../domain/event/ticket/TicketStatus.java | 5 + .../application/domain/partner/Partner.java | 15 ++ .../repositories/CustomerRepository.java | 6 +- .../repositories/PartnerRepository.java | 6 +- .../customer/CreateCustomerUseCase.java | 6 +- .../partner/CreatePartnerUseCase.java | 6 +- .../configurations/UseCaseConfig.java | 28 ++-- .../entities/CustomerEntity.java} | 36 +++-- .../entities/EventEntity.java} | 22 +-- .../jpa/entities/PartnerEntity.java | 78 ++++++++++ .../jpa/entities/TicketEntity.java | 133 ++++++++++++++++++ .../repositories/CustomerJpaRepository.java | 14 ++ .../jpa/repositories/EventJpaRepository.java | 8 ++ .../repositories/PartnerJpaRepository.java | 14 ++ .../jpa/repositories/TicketJpaRepository.java | 10 ++ .../infrastructure/models/Partner.java | 65 --------- .../infrastructure/models/Ticket.java | 103 -------------- .../infrastructure/models/TicketStatus.java | 5 - .../CustomerDatabaseRepository.java | 61 ++++++++ .../repositories/CustomerRepository.java | 13 -- .../repositories/EventRepository.java | 8 -- .../PartnerDatabaseRepository.java | 61 ++++++++ .../repositories/PartnerRepository.java | 13 -- .../TicketDatabaseRepository.java | 45 ++++++ .../repositories/TicketRepository.java | 11 -- .../services/CustomerService.java | 34 ----- .../infrastructure/services/EventService.java | 37 ----- .../services/PartnerService.java | 34 ----- .../application/domain/event/EventTest.java | 2 +- .../domain/event/ticket/TicketTest.java | 1 - .../InMemoryCustomerRepository.java | 10 +- .../repository/InMemoryPartnerRepository.java | 12 +- .../customer/CreateCustomerUseCaseIT.java | 11 +- .../usecases/event/CreateEventUseCaseIT.java | 15 +- .../SubscribeCustomerToEventUseCaseTest.java | 9 +- .../rest/CustomerControllerTest.java | 4 +- .../rest/EventControllerTest.java | 24 ++-- .../rest/PartnerControllerTest.java | 4 +- 41 files changed, 600 insertions(+), 413 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java rename src/main/java/br/com/fullcycle/hexagonal/infrastructure/{models/Customer.java => jpa/entities/CustomerEntity.java} (53%) rename src/main/java/br/com/fullcycle/hexagonal/infrastructure/{models/Event.java => jpa/entities/EventEntity.java} (75%) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java index c05b04a8..3ebaaa42 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java @@ -5,6 +5,8 @@ import br.com.fullcycle.hexagonal.application.domain.person.Name; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import java.util.Objects; + public class Customer { private final CustomerId customerId; @@ -43,6 +45,19 @@ public Email email() { return email; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Customer customer = (Customer) o; + return Objects.equals(customerId, customer.customerId); + } + + @Override + public int hashCode() { + return Objects.hash(customerId); + } + private void setCpf(final String cpf) { this.cpf = new Cpf(cpf); } @@ -54,4 +69,5 @@ private void setEmail(final String email) { private void setName(final String name) { this.name = new Name(name); } + } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java index 7073ab59..5ff73cfe 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java @@ -90,6 +90,19 @@ public Set allTickets() { return Collections.unmodifiableSet(tickets); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Event event = (Event) o; + return Objects.equals(eventId, event.eventId); + } + + @Override + public int hashCode() { + return Objects.hash(eventId); + } + private void setName(final String name) { this.name = new Name(name); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java index 944ce92e..86ccb13f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java @@ -3,9 +3,9 @@ import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import br.com.fullcycle.hexagonal.application.domain.event.EventId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; import java.time.Instant; +import java.util.Objects; public class Ticket { @@ -60,6 +60,19 @@ public Instant reservedAt() { return reservedAt; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Ticket ticket = (Ticket) o; + return Objects.equals(ticketId, ticket.ticketId); + } + + @Override + public int hashCode() { + return Objects.hash(ticketId); + } + private void setCustomerId(final CustomerId customerId) { if (customerId == null) { throw new ValidationException("Invalid customerId for Ticket"); diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java new file mode 100644 index 00000000..f9016aa3 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.hexagonal.application.domain.event.ticket; + +public enum TicketStatus { + PENDING, PROCESSING, PAID; +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java index 942501d2..c005cca8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java @@ -5,6 +5,8 @@ import br.com.fullcycle.hexagonal.application.domain.person.Name; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import java.util.Objects; + public class Partner { private final PartnerId partnerId; @@ -43,6 +45,19 @@ public Email email() { return email; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Partner partner = (Partner) o; + return Objects.equals(partnerId, partner.partnerId); + } + + @Override + public int hashCode() { + return Objects.hash(partnerId); + } + private void setCnpj(final String cnpj) { this.cnpj = new Cnpj(cnpj); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java index 4966ed9e..ebee262d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java @@ -2,6 +2,8 @@ import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cpf; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import java.util.Optional; @@ -9,9 +11,9 @@ public interface CustomerRepository { Optional customerOfId(CustomerId anId); - Optional customerOfCPF(String cpf); + Optional customerOfCPF(Cpf cpf); - Optional customerOfEmail(String email); + Optional customerOfEmail(Email email); Customer create(Customer customer); diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java index f24b5830..fb261f01 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java @@ -2,6 +2,8 @@ import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import java.util.Optional; @@ -9,9 +11,9 @@ public interface PartnerRepository { Optional partnerOfId(PartnerId anId); - Optional partnerOfCNPJ(String cpf); + Optional partnerOfCNPJ(Cnpj cnpj); - Optional partnerOfEmail(String email); + Optional partnerOfEmail(Email email); Partner create(Partner partner); diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java index 6fb016ca..d58d3ff0 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java @@ -1,5 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases.customer; +import br.com.fullcycle.hexagonal.application.domain.person.Cpf; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import br.com.fullcycle.hexagonal.application.usecases.UseCase; import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; @@ -16,11 +18,11 @@ public CreateCustomerUseCase(CustomerRepository customerRepository) { @Override public Output execute(final Input input) { - if (customerRepository.customerOfCPF(input.cpf).isPresent()) { + if (customerRepository.customerOfCPF(new Cpf(input.cpf)).isPresent()) { throw new ValidationException("Customer already exists"); } - if (customerRepository.customerOfEmail(input.email).isPresent()) { + if (customerRepository.customerOfEmail(new Email(input.email)).isPresent()) { throw new ValidationException("Customer already exists"); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java index 572b2995..f7abce2f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java @@ -1,5 +1,7 @@ package br.com.fullcycle.hexagonal.application.usecases.partner; +import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import br.com.fullcycle.hexagonal.application.usecases.UseCase; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; @@ -17,11 +19,11 @@ public CreatePartnerUseCase(final PartnerRepository partnerRepository) { @Override public Output execute(final Input input) { - if (partnerRepository.partnerOfCNPJ(input.cnpj).isPresent()) { + if (partnerRepository.partnerOfCNPJ(new Cnpj(input.cnpj)).isPresent()) { throw new ValidationException("Partner already exists"); } - if (partnerRepository.partnerOfEmail(input.email).isPresent()) { + if (partnerRepository.partnerOfEmail(new Email(input.email)).isPresent()) { throw new ValidationException("Partner already exists"); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 9a50d18c..2f5a7423 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -1,14 +1,15 @@ package br.com.fullcycle.hexagonal.infrastructure.configurations; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.services.CustomerService; -import br.com.fullcycle.hexagonal.infrastructure.services.EventService; -import br.com.fullcycle.hexagonal.infrastructure.services.PartnerService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,18 +18,21 @@ @Configuration public class UseCaseConfig { - private final CustomerService customerService; - private final EventService eventService; - private final PartnerService partnerService; + private final CustomerRepository customerRepository; + private final EventRepository eventRepository; + private final PartnerRepository partnerRepository; + private final TicketRepository ticketRepository; public UseCaseConfig( - final CustomerService customerService, - final EventService eventService, - final PartnerService partnerService + final CustomerRepository customerRepository, + final EventRepository eventRepository, + final PartnerRepository partnerRepository, + final TicketRepository ticketRepository ) { - this.customerService = Objects.requireNonNull(customerService); - this.eventService = Objects.requireNonNull(eventService); - this.partnerService = Objects.requireNonNull(partnerService); + this.customerRepository = Objects.requireNonNull(customerRepository); + this.eventRepository = Objects.requireNonNull(eventRepository); + this.partnerRepository = Objects.requireNonNull(partnerRepository); + this.ticketRepository = Objects.requireNonNull(ticketRepository); } @Bean diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java similarity index 53% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java index 624811a3..971e93e7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Customer.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java @@ -1,21 +1,20 @@ -package br.com.fullcycle.hexagonal.infrastructure.models; +package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.util.Objects; - -import static jakarta.persistence.GenerationType.*; +import java.util.UUID; @Entity @Table(name = "customers") -public class Customer { +public class CustomerEntity { @Id - @GeneratedValue(strategy = IDENTITY) - private Long id; + private UUID id; private String name; @@ -23,21 +22,34 @@ public class Customer { private String email; - public Customer() { + public CustomerEntity() { } - public Customer(Long id, String name, String cpf, String email) { + public CustomerEntity(UUID id, String name, String cpf, String email) { this.id = id; this.name = name; this.cpf = cpf; this.email = email; } - public Long getId() { + public static CustomerEntity of(final Customer customer) { + return new CustomerEntity( + UUID.fromString(customer.customerId().value()), + customer.name().value(), + customer.cpf().value(), + customer.email().value() + ); + } + + public Customer toCustomer() { + return new Customer(CustomerId.with(this.id.toString()), this.name, this.cpf, this.email); + } + + public UUID getId() { return id; } - public void setId(Long id) { + public void setId(UUID id) { this.id = id; } @@ -69,7 +81,7 @@ public void setEmail(String email) { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - Customer customer = (Customer) o; + CustomerEntity customer = (CustomerEntity) o; return Objects.equals(id, customer.id); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java similarity index 75% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java rename to src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java index a6177b4f..6ea3d3e2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure.models; +package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; import jakarta.persistence.*; @@ -11,7 +11,7 @@ @Entity @Table(name = "events") -public class Event { +public class EventEntity { @Id @GeneratedValue(strategy = IDENTITY) @@ -24,16 +24,16 @@ public class Event { private int totalSpots; @ManyToOne(fetch = FetchType.LAZY) - private Partner partner; + private PartnerEntity partner; @OneToMany(cascade = CascadeType.ALL, mappedBy = "event") - private Set tickets; + private Set tickets; - public Event() { + public EventEntity() { this.tickets = new HashSet<>(); } - public Event(Long id, String name, LocalDate date, int totalSpots, Set tickets) { + public EventEntity(Long id, String name, LocalDate date, int totalSpots, Set tickets) { this.id = id; this.name = name; this.date = date; @@ -73,19 +73,19 @@ public void setTotalSpots(int totalSpots) { this.totalSpots = totalSpots; } - public Partner getPartner() { + public PartnerEntity getPartner() { return partner; } - public void setPartner(Partner partner) { + public void setPartner(PartnerEntity partner) { this.partner = partner; } - public Set getTickets() { + public Set getTickets() { return tickets; } - public void setTickets(Set tickets) { + public void setTickets(Set tickets) { this.tickets = tickets; } @@ -93,7 +93,7 @@ public void setTickets(Set tickets) { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - Event event = (Event) o; + EventEntity event = (EventEntity) o; return Objects.equals(id, event.id); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java new file mode 100644 index 00000000..d538cc8f --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java @@ -0,0 +1,78 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; + +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import java.util.UUID; + +@Entity +@Table(name = "partners") +public class PartnerEntity { + + @Id + private UUID id; + + private String name; + + private String cnpj; + + private String email; + + public PartnerEntity() { + } + + public PartnerEntity(UUID id, String name, String cnpj, String email) { + this.id = id; + this.name = name; + this.cnpj = cnpj; + this.email = email; + } + + public static PartnerEntity of(Partner partner) { + return new PartnerEntity( + UUID.fromString(partner.partnerId().value()), + partner.name().value(), + partner.cnpj().value(), + partner.email().value() + ); + } + + public Partner toPartner() { + return new Partner(PartnerId.with(this.id.toString()), this.name, this.cnpj, this.email); + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCnpj() { + return cnpj; + } + + public void setCnpj(String cnpj) { + this.cnpj = cnpj; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java new file mode 100644 index 00000000..74b7fd4f --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java @@ -0,0 +1,133 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; + +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.Objects; +import java.util.UUID; + +@Entity +@Table(name = "tickets") +public class TicketEntity { + + @Id + private UUID id; + + private UUID customerId; + + private UUID eventId; + + @Enumerated(EnumType.STRING) + private TicketStatus status; + + private Instant paidAt; + + private Instant reservedAt; + + public TicketEntity() { + } + + public TicketEntity( + final UUID id, + final UUID customerId, + final UUID eventId, + final TicketStatus status, + final Instant paidAt, + final Instant reservedAt + ) { + this.id = id; + this.customerId = customerId; + this.eventId = eventId; + this.status = status; + this.paidAt = paidAt; + this.reservedAt = reservedAt; + } + + public static TicketEntity of(final Ticket ticket) { + return new TicketEntity( + UUID.fromString(ticket.ticketId().value()), + UUID.fromString(ticket.customerId().value()), + UUID.fromString(ticket.eventId().value()), + ticket.status(), + ticket.paidAt(), + ticket.reservedAt() + ); + } + + public Ticket toTicket() { + return new Ticket( + TicketId.with(this.id.toString()), + CustomerId.with(this.customerId.toString()), + EventId.with(this.eventId.toString()), + this.status, + this.paidAt, + this.reservedAt + ); + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public UUID customerId() { + return customerId; + } + + public void setCustomerId(UUID customerId) { + this.customerId = customerId; + } + + public UUID eventId() { + return eventId; + } + + public void setEventId(UUID eventId) { + this.eventId = eventId; + } + + public TicketStatus getStatus() { + return status; + } + + public void setStatus(TicketStatus status) { + this.status = status; + } + + public Instant getPaidAt() { + return paidAt; + } + + public void setPaidAt(Instant paidAt) { + this.paidAt = paidAt; + } + + public Instant getReservedAt() { + return reservedAt; + } + + public void setReservedAt(Instant reservedAt) { + this.reservedAt = reservedAt; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TicketEntity that = (TicketEntity) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java new file mode 100644 index 00000000..810190e4 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java @@ -0,0 +1,14 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; + +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface CustomerJpaRepository extends CrudRepository { + + Optional findByCpf(String cpf); + + Optional findByEmail(String email); +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java new file mode 100644 index 00000000..1306fae4 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java @@ -0,0 +1,8 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; + +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.EventEntity; +import org.springframework.data.repository.CrudRepository; + +public interface EventJpaRepository extends CrudRepository { + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java new file mode 100644 index 00000000..96d02396 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java @@ -0,0 +1,14 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; + +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface PartnerJpaRepository extends CrudRepository { + + Optional findByCnpj(String cnpj); + + Optional findByEmail(String email); +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java new file mode 100644 index 00000000..6e0a2956 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java @@ -0,0 +1,10 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; + +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.TicketEntity; +import org.springframework.data.repository.CrudRepository; + +import java.util.UUID; + +public interface TicketJpaRepository extends CrudRepository { + +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java deleted file mode 100644 index 0c6d7ad0..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Partner.java +++ /dev/null @@ -1,65 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.models; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -import static jakarta.persistence.GenerationType.IDENTITY; - -@Entity -@Table(name = "partners") -public class Partner { - - @Id - @GeneratedValue(strategy = IDENTITY) - private Long id; - - private String name; - - private String cnpj; - - private String email; - - public Partner() { - } - - public Partner(Long id, String name, String cnpj, String email) { - this.id = id; - this.name = name; - this.cnpj = cnpj; - this.email = email; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCnpj() { - return cnpj; - } - - public void setCnpj(String cnpj) { - this.cnpj = cnpj; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java deleted file mode 100644 index 39699486..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/Ticket.java +++ /dev/null @@ -1,103 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.models; - -import jakarta.persistence.*; - -import java.time.Instant; -import java.util.Objects; - -import static jakarta.persistence.GenerationType.IDENTITY; - -@Entity -@Table(name = "tickets") -public class Ticket { - - @Id - @GeneratedValue(strategy = IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private Customer customer; - - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - @Enumerated(EnumType.STRING) - private TicketStatus status; - - private Instant paidAt; - - private Instant reservedAt; - - public Ticket() { - } - - public Ticket(Long id, Customer customer, Event event, TicketStatus status, Instant paidAt, Instant reservedAt) { - this.id = id; - this.customer = customer; - this.event = event; - this.status = status; - this.paidAt = paidAt; - this.reservedAt = reservedAt; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Customer getCustomer() { - return customer; - } - - public void setCustomer(Customer customer) { - this.customer = customer; - } - - public Event getEvent() { - return event; - } - - public void setEvent(Event event) { - this.event = event; - } - - public TicketStatus getStatus() { - return status; - } - - public void setStatus(TicketStatus status) { - this.status = status; - } - - public Instant getPaidAt() { - return paidAt; - } - - public void setPaidAt(Instant paidAt) { - this.paidAt = paidAt; - } - - public Instant getReservedAt() { - return reservedAt; - } - - public void setReservedAt(Instant reservedAt) { - this.reservedAt = reservedAt; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Ticket ticket = (Ticket) o; - return Objects.equals(customer, ticket.customer) && Objects.equals(event, ticket.event); - } - - @Override - public int hashCode() { - return Objects.hash(customer, event); - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java deleted file mode 100644 index fa667ff8..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/models/TicketStatus.java +++ /dev/null @@ -1,5 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.models; - -public enum TicketStatus { - PENDING, PROCESSING, PAID; -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java new file mode 100644 index 00000000..5c827ac2 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java @@ -0,0 +1,61 @@ +package br.com.fullcycle.hexagonal.infrastructure.repositories; + +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cpf; +import br.com.fullcycle.hexagonal.application.domain.person.Email; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +// Interface Adapter +@Component +public class CustomerDatabaseRepository implements CustomerRepository { + + private final CustomerJpaRepository customerJpaRepository; + + public CustomerDatabaseRepository(final CustomerJpaRepository customerJpaRepository) { + this.customerJpaRepository = Objects.requireNonNull(customerJpaRepository); + } + + @Override + public Optional customerOfId(final CustomerId anId) { + Objects.requireNonNull(anId, "id cannot be null"); + return this.customerJpaRepository.findById(UUID.fromString(anId.value())) + .map(CustomerEntity::toCustomer); + } + + @Override + public Optional customerOfCPF(final Cpf cpf) { + Objects.requireNonNull(cpf, "Cpf cannot be null"); + return this.customerJpaRepository.findByCpf(cpf.value()) + .map(CustomerEntity::toCustomer); + } + + @Override + public Optional customerOfEmail(final Email email) { + Objects.requireNonNull(email, "Email cannot be null"); + return this.customerJpaRepository.findByEmail(email.value()) + .map(CustomerEntity::toCustomer); + } + + @Override + @Transactional + public Customer create(final Customer customer) { + return this.customerJpaRepository.save(CustomerEntity.of(customer)) + .toCustomer(); + } + + @Override + @Transactional + public Customer update(Customer customer) { + return this.customerJpaRepository.save(CustomerEntity.of(customer)) + .toCustomer(); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java deleted file mode 100644 index 40fbb754..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; - -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import org.springframework.data.repository.CrudRepository; - -import java.util.Optional; - -public interface CustomerRepository extends CrudRepository { - - Optional findByCpf(String cpf); - - Optional findByEmail(String email); -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java deleted file mode 100644 index 0137717a..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; - -import br.com.fullcycle.hexagonal.infrastructure.models.Event; -import org.springframework.data.repository.CrudRepository; - -public interface EventRepository extends CrudRepository { - -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java new file mode 100644 index 00000000..ac93a2ab --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java @@ -0,0 +1,61 @@ +package br.com.fullcycle.hexagonal.infrastructure.repositories; + +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; +import br.com.fullcycle.hexagonal.application.domain.person.Email; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +// Interface Adapter +@Component +public class PartnerDatabaseRepository implements PartnerRepository { + + private final PartnerJpaRepository partnerJpaRepository; + + public PartnerDatabaseRepository(final PartnerJpaRepository partnerJpaRepository) { + this.partnerJpaRepository = Objects.requireNonNull(partnerJpaRepository); + } + + @Override + public Optional partnerOfId(final PartnerId anId) { + Objects.requireNonNull(anId, "id cannot be null"); + return this.partnerJpaRepository.findById(UUID.fromString(anId.value())) + .map(PartnerEntity::toPartner); + } + + @Override + public Optional partnerOfCNPJ(final Cnpj cnpj) { + Objects.requireNonNull(cnpj, "Cnpj cannot be null"); + return this.partnerJpaRepository.findByCnpj(cnpj.value()) + .map(PartnerEntity::toPartner); + } + + @Override + public Optional partnerOfEmail(final Email email) { + Objects.requireNonNull(email, "Email cannot be null"); + return this.partnerJpaRepository.findByEmail(email.value()) + .map(PartnerEntity::toPartner); + } + + @Override + @Transactional + public Partner create(final Partner partner) { + return this.partnerJpaRepository.save(PartnerEntity.of(partner)) + .toPartner(); + } + + @Override + @Transactional + public Partner update(Partner partner) { + return this.partnerJpaRepository.save(PartnerEntity.of(partner)) + .toPartner(); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java deleted file mode 100644 index f29d681e..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; - -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import org.springframework.data.repository.CrudRepository; - -import java.util.Optional; - -public interface PartnerRepository extends CrudRepository { - - Optional findByCnpj(String cnpj); - - Optional findByEmail(String email); -} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java new file mode 100644 index 00000000..17ed1bff --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java @@ -0,0 +1,45 @@ +package br.com.fullcycle.hexagonal.infrastructure.repositories; + +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; +import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.TicketEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.TicketJpaRepository; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +// Interface Adapter +@Component +public class TicketDatabaseRepository implements TicketRepository { + + private final TicketJpaRepository ticketJpaRepository; + + public TicketDatabaseRepository(final TicketJpaRepository ticketJpaRepository) { + this.ticketJpaRepository = Objects.requireNonNull(ticketJpaRepository); + } + + @Override + public Optional ticketOfId(final TicketId anId) { + Objects.requireNonNull(anId, "id cannot be null"); + return this.ticketJpaRepository.findById(UUID.fromString(anId.value())) + .map(TicketEntity::toTicket); + } + + @Override + @Transactional + public Ticket create(final Ticket ticket) { + return this.ticketJpaRepository.save(TicketEntity.of(ticket)) + .toTicket(); + } + + @Override + @Transactional + public Ticket update(Ticket ticket) { + return this.ticketJpaRepository.save(TicketEntity.of(ticket)) + .toTicket(); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java deleted file mode 100644 index 0174ae92..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; - -import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; -import org.springframework.data.repository.CrudRepository; - -import java.util.Optional; - -public interface TicketRepository extends CrudRepository { - - Optional findByEventIdAndCustomerId(Long id, Long customerId); -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java deleted file mode 100644 index cb670971..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/CustomerService.java +++ /dev/null @@ -1,34 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.services; - -import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -@Service -public class CustomerService { - - @Autowired - private CustomerRepository repository; - - @Transactional - public Customer save(Customer customer) { - return repository.save(customer); - } - - public Optional findById(Long id) { - return repository.findById(id); - } - - public Optional findByCpf(String cpf) { - return repository.findByCpf(cpf); - } - - public Optional findByEmail(String email) { - return repository.findByEmail(email); - } - -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java deleted file mode 100644 index 1f85128a..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/EventService.java +++ /dev/null @@ -1,37 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.services; - -import br.com.fullcycle.hexagonal.infrastructure.repositories.TicketRepository; -import br.com.fullcycle.hexagonal.infrastructure.models.Event; -import br.com.fullcycle.hexagonal.infrastructure.models.Ticket; -import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -@Service -public class EventService { - - @Autowired - private CustomerService customerService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private TicketRepository ticketRepository; - - @Transactional - public Event save(Event event) { - return eventRepository.save(event); - } - - public Optional findById(Long id) { - return eventRepository.findById(id); - } - - public Optional findTicketByEventIdAndCustomerId(Long id, Long customerId) { - return ticketRepository.findByEventIdAndCustomerId(id, customerId); - } -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java deleted file mode 100644 index 01357a3c..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/services/PartnerService.java +++ /dev/null @@ -1,34 +0,0 @@ -package br.com.fullcycle.hexagonal.infrastructure.services; - -import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -@Service -public class PartnerService { - - @Autowired - private PartnerRepository repository; - - @Transactional - public Partner save(Partner customer) { - return repository.save(customer); - } - - public Optional findById(Long id) { - return repository.findById(id); - } - - public Optional findByCnpj(String cnpj) { - return repository.findByCnpj(cnpj); - } - - public Optional findByEmail(String email) { - return repository.findByEmail(email); - } - -} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java index 3cd035a5..a79bab58 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java @@ -1,9 +1,9 @@ package br.com.fullcycle.hexagonal.application.domain.event; import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java index b4de7c4f..c26a1b79 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java @@ -3,7 +3,6 @@ import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.domain.event.Event; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java index 93e2cc92..e77bac8b 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java @@ -2,6 +2,8 @@ import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cpf; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import java.util.HashMap; @@ -27,13 +29,13 @@ public Optional customerOfId(CustomerId anId) { } @Override - public Optional customerOfCPF(String cpf) { - return Optional.ofNullable(this.customersByCPF.get(Objects.requireNonNull(cpf))); + public Optional customerOfCPF(Cpf cpf) { + return Optional.ofNullable(this.customersByCPF.get(cpf.value())); } @Override - public Optional customerOfEmail(String email) { - return Optional.ofNullable(this.customersByEmail.get(Objects.requireNonNull(email))); + public Optional customerOfEmail(Email email) { + return Optional.ofNullable(this.customersByEmail.get(email.value())); } @Override diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java index 412a0962..20d99b97 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java @@ -2,6 +2,8 @@ import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; +import br.com.fullcycle.hexagonal.application.domain.person.Email; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import java.util.HashMap; @@ -23,17 +25,17 @@ public InMemoryPartnerRepository() { @Override public Optional partnerOfId(PartnerId anId) { - return Optional.ofNullable(this.partners.get(Objects.requireNonNull(anId).value().toString())); + return Optional.ofNullable(this.partners.get(Objects.requireNonNull(anId).value())); } @Override - public Optional partnerOfCNPJ(String cnpj) { - return Optional.ofNullable(this.partnersByCNPJ.get(Objects.requireNonNull(cnpj))); + public Optional partnerOfCNPJ(Cnpj cnpj) { + return Optional.ofNullable(this.partnersByCNPJ.get(Objects.requireNonNull(cnpj).value())); } @Override - public Optional partnerOfEmail(String email) { - return Optional.ofNullable(this.partnersByEmail.get(Objects.requireNonNull(email))); + public Optional partnerOfEmail(Email email) { + return Optional.ofNullable(this.partnersByEmail.get(Objects.requireNonNull(email).value())); } @Override diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java index ea0914a4..45b5de4d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java @@ -2,9 +2,8 @@ import br.com.fullcycle.hexagonal.IntegrationTest; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -17,7 +16,7 @@ public class CreateCustomerUseCaseIT extends IntegrationTest { private CreateCustomerUseCase useCase; @Autowired - private CustomerRepository customerRepository; + private CustomerJpaRepository customerRepository; @AfterEach void tearDown() { @@ -84,8 +83,8 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { Assertions.assertEquals(expectedError, actualException.getMessage()); } - private Customer createCustomer(final String cpf, final String email, final String name) { - final var aCustomer = new Customer(); + private CustomerEntity createCustomer(final String cpf, final String email, final String name) { + final var aCustomer = new CustomerEntity(); aCustomer.setCpf(cpf); aCustomer.setName(name); aCustomer.setEmail(email); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java index 02f5ed73..ca001f50 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java @@ -3,10 +3,9 @@ import br.com.fullcycle.hexagonal.IntegrationTest; import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; -import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -19,10 +18,10 @@ class CreateEventUseCaseIT extends IntegrationTest { private CreateEventUseCase useCase; @Autowired - private EventRepository eventRepository; + private EventJpaRepository eventRepository; @Autowired - private PartnerRepository partnerRepository; + private PartnerJpaRepository partnerRepository; @BeforeEach void tearDown() { @@ -74,8 +73,8 @@ public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Ex Assertions.assertEquals(expectedError, actualException.getMessage()); } - private Partner createPartner(final String cnpj, final String email, final String name) { - final var aPartner = new Partner(); + private PartnerEntity createPartner(final String cnpj, final String email, final String name) { + final var aPartner = new PartnerEntity(); aPartner.setCnpj(cnpj); aPartner.setName(name); aPartner.setEmail(email); diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java index be8c29e6..a5c8c6dc 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java @@ -1,16 +1,15 @@ package br.com.fullcycle.hexagonal.application.usecases.event; -import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; -import br.com.fullcycle.hexagonal.application.repository.InMemoryTicketRepository; import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; import br.com.fullcycle.hexagonal.application.domain.event.Event; import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.models.TicketStatus; +import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; +import br.com.fullcycle.hexagonal.application.repository.InMemoryTicketRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java index 258f21d4..5f63dcd4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java @@ -3,7 +3,7 @@ import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; -import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -30,7 +30,7 @@ public class CustomerControllerTest { private ObjectMapper mapper; @Autowired - private CustomerRepository customerRepository; + private CustomerJpaRepository customerRepository; @AfterEach void tearDown() { diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index f3e00410..eb2fca90 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -3,11 +3,11 @@ import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.infrastructure.models.Customer; -import br.com.fullcycle.hexagonal.infrastructure.models.Partner; -import br.com.fullcycle.hexagonal.infrastructure.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.infrastructure.repositories.EventRepository; -import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; @@ -32,21 +32,21 @@ class EventControllerTest { private ObjectMapper mapper; @Autowired - private CustomerRepository customerRepository; + private CustomerJpaRepository customerRepository; @Autowired - private PartnerRepository partnerRepository; + private PartnerJpaRepository partnerRepository; @Autowired - private EventRepository eventRepository; + private EventJpaRepository eventRepository; - private Customer johnDoe; - private Partner disney; + private CustomerEntity johnDoe; + private PartnerEntity disney; @BeforeEach void setUp() { - johnDoe = customerRepository.save(new Customer(null, "John Doe", "123", "john@gmail.com")); - disney = partnerRepository.save(new Partner(null, "Disney", "456", "disney@gmail.com")); + johnDoe = customerRepository.save(new CustomerEntity(null, "John Doe", "123", "john@gmail.com")); + disney = partnerRepository.save(new PartnerEntity(null, "Disney", "456", "disney@gmail.com")); } @AfterEach diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java index c7e83509..12b56a4b 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java @@ -3,7 +3,7 @@ import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; -import br.com.fullcycle.hexagonal.infrastructure.repositories.PartnerRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -30,7 +30,7 @@ public class PartnerControllerTest { private ObjectMapper mapper; @Autowired - private PartnerRepository partnerRepository; + private PartnerJpaRepository partnerRepository; @AfterEach void tearDown() { From b2535007245273ce9523bdda917a5ace7376c1e0 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Fri, 25 Aug 2023 23:11:30 -0300 Subject: [PATCH 15/22] 15-interface-adapters-de-event --- .../application/domain/event/Event.java | 32 ++++-- .../application/domain/event/EventTicket.java | 2 +- .../repositories/CustomerRepository.java | 1 + .../repositories/EventRepository.java | 1 + .../repositories/PartnerRepository.java | 1 + .../repositories/TicketRepository.java | 1 + .../configurations/UseCaseConfig.java | 18 +-- .../jpa/entities/CustomerEntity.java | 2 +- .../jpa/entities/EventEntity.java | 77 +++++++++---- .../jpa/entities/EventTicketEntity.java | 103 ++++++++++++++++++ .../jpa/entities/PartnerEntity.java | 2 +- .../jpa/entities/TicketEntity.java | 2 +- .../jpa/repositories/EventJpaRepository.java | 4 +- .../CustomerDatabaseRepository.java | 5 + .../repositories/EventDatabaseRepository.java | 50 +++++++++ .../PartnerDatabaseRepository.java | 5 + .../TicketDatabaseRepository.java | 5 + .../InMemoryCustomerRepository.java | 7 ++ .../repository/InMemoryEventRepository.java | 5 + .../repository/InMemoryPartnerRepository.java | 7 ++ .../repository/InMemoryTicketRepository.java | 5 + .../customer/CreateCustomerUseCaseIT.java | 29 ++--- .../usecases/event/CreateEventUseCaseIT.java | 21 ++-- .../rest/CustomerControllerTest.java | 24 ++-- .../rest/EventControllerTest.java | 49 +++++---- .../rest/PartnerControllerTest.java | 30 +++-- 26 files changed, 362 insertions(+), 126 deletions(-) create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java create mode 100644 src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java index 5ff73cfe..0d99a5e2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java @@ -1,10 +1,10 @@ package br.com.fullcycle.hexagonal.application.domain.event; -import br.com.fullcycle.hexagonal.application.domain.person.Name; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import br.com.fullcycle.hexagonal.application.domain.person.Name; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import java.time.LocalDate; @@ -25,25 +25,43 @@ public class Event { private PartnerId partnerId; private Set tickets; - public Event(final EventId eventId, final String name, final String date, final Integer totalSpots, final PartnerId partnerId) { - this(eventId); + public Event( + final EventId eventId, + final String name, + final String date, + final Integer totalSpots, + final PartnerId partnerId, + final Set tickets + ) { + this(eventId, tickets); this.setName(name); this.setDate(date); this.setTotalSpots(totalSpots); this.setPartnerId(partnerId); } - private Event(final EventId eventId) { + private Event(final EventId eventId, final Set tickets) { if (eventId == null) { throw new ValidationException("Invalid eventId for Event"); } this.eventId = eventId; - this.tickets = new HashSet<>(0); + this.tickets = tickets != null ? tickets : new HashSet<>(0); } public static Event newEvent(final String name, final String date, final Integer totalSpots, final Partner partner) { - return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId()); + return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId(), null); + } + + public static Event restore( + final String id, + final String name, + final String date, + final int totalSpots, + final String partnerId, + final Set tickets + ) { + return new Event(EventId.with(id), name, date, totalSpots, PartnerId.with(partnerId), tickets); } public Ticket reserveTicket(final CustomerId aCustomerId) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java index b410cfcb..269c375c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java @@ -11,7 +11,7 @@ public class EventTicket { private final CustomerId customerId; private int ordering; - protected EventTicket(final TicketId ticketId, final EventId eventId, final CustomerId customerId, final Integer ordering) { + public EventTicket(final TicketId ticketId, final EventId eventId, final CustomerId customerId, final Integer ordering) { if (ticketId == null) { throw new ValidationException("Invalid ticketId for EventTicket"); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java index ebee262d..d15f3010 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java @@ -19,4 +19,5 @@ public interface CustomerRepository { Customer update(Customer customer); + void deleteAll(); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java index 48586b9d..cc441cf5 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java @@ -13,4 +13,5 @@ public interface EventRepository { Event update(Event event); + void deleteAll(); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java index fb261f01..c26c9642 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java @@ -19,4 +19,5 @@ public interface PartnerRepository { Partner update(Partner partner); + void deleteAll(); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java index cd3ab43e..dad8fad8 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java @@ -13,4 +13,5 @@ public interface TicketRepository { Ticket update(Ticket ticket); + void deleteAll(); } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java index 2f5a7423..d754fc2b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java @@ -37,37 +37,31 @@ public UseCaseConfig( @Bean public CreateCustomerUseCase createCustomerUseCase() { - // TODO: Fix dependency - return new CreateCustomerUseCase(null); + return new CreateCustomerUseCase(customerRepository); } @Bean public CreateEventUseCase createEventUseCase() { - // TODO: Fix dependency - return new CreateEventUseCase(null, null); + return new CreateEventUseCase(eventRepository, partnerRepository); } @Bean public CreatePartnerUseCase createPartnerUseCase() { - // TODO: Fix dependency - return new CreatePartnerUseCase(null); + return new CreatePartnerUseCase(partnerRepository); } @Bean public GetCustomerByIdUseCase getCustomerByIdUseCase() { - // TODO: Fix dependency - return new GetCustomerByIdUseCase(null); + return new GetCustomerByIdUseCase(customerRepository); } @Bean public GetPartnerByIdUseCase getPartnerByIdUseCase() { - // TODO: Fix dependency - return new GetPartnerByIdUseCase(null); + return new GetPartnerByIdUseCase(partnerRepository); } @Bean public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { - // TODO: Fix dependency - return new SubscribeCustomerToEventUseCase(null, null, null); + return new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java index 971e93e7..d9477a72 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java @@ -9,7 +9,7 @@ import java.util.Objects; import java.util.UUID; -@Entity +@Entity(name = "Customer") @Table(name = "customers") public class CustomerEntity { diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java index 6ea3d3e2..2b7ee3da 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java @@ -1,21 +1,23 @@ package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.event.EventTicket; import jakarta.persistence.*; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.HashSet; import java.util.Objects; import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; -import static jakarta.persistence.GenerationType.IDENTITY; - -@Entity +@Entity(name = "Event") @Table(name = "events") public class EventEntity { @Id - @GeneratedValue(strategy = IDENTITY) - private Long id; + private UUID id; private String name; @@ -23,33 +25,64 @@ public class EventEntity { private int totalSpots; - @ManyToOne(fetch = FetchType.LAZY) - private PartnerEntity partner; + private UUID partnerId; - @OneToMany(cascade = CascadeType.ALL, mappedBy = "event") - private Set tickets; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "event") + private Set tickets; public EventEntity() { this.tickets = new HashSet<>(); } - public EventEntity(Long id, String name, LocalDate date, int totalSpots, Set tickets) { + public EventEntity(UUID id, String name, LocalDate date, int totalSpots, UUID partnerId) { + this(); this.id = id; this.name = name; this.date = date; this.totalSpots = totalSpots; - this.tickets = tickets != null ? tickets : new HashSet<>(); + this.partnerId = partnerId; + } + + public static EventEntity of(final Event event) { + final var entity = new EventEntity( + UUID.fromString(event.eventId().value()), + event.name().value(), + event.date(), + event.totalSpots(), + UUID.fromString(event.partnerId().value()) + ); + + event.allTickets().forEach(entity::addTicket); + + return entity; + } + + public Event toEvent() { + return Event.restore( + this.id().toString(), + this.name(), + this.date().format(DateTimeFormatter.ISO_LOCAL_DATE), + this.totalSpots(), + this.partnerId().toString(), + this.tickets().stream() + .map(EventTicketEntity::toEventTicket) + .collect(Collectors.toSet()) + ); + } + + private void addTicket(final EventTicket ticket) { + this.tickets.add(EventTicketEntity.of(this, ticket)); } - public Long getId() { + public UUID id() { return id; } - public void setId(Long id) { + public void setId(UUID id) { this.id = id; } - public String getName() { + public String name() { return name; } @@ -57,7 +90,7 @@ public void setName(String name) { this.name = name; } - public LocalDate getDate() { + public LocalDate date() { return date; } @@ -65,7 +98,7 @@ public void setDate(LocalDate date) { this.date = date; } - public int getTotalSpots() { + public int totalSpots() { return totalSpots; } @@ -73,19 +106,19 @@ public void setTotalSpots(int totalSpots) { this.totalSpots = totalSpots; } - public PartnerEntity getPartner() { - return partner; + public UUID partnerId() { + return partnerId; } - public void setPartner(PartnerEntity partner) { - this.partner = partner; + public void setPartnerId(UUID partnerId) { + this.partnerId = partnerId; } - public Set getTickets() { + public Set tickets() { return tickets; } - public void setTickets(Set tickets) { + public void setTickets(Set tickets) { this.tickets = tickets; } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java new file mode 100644 index 00000000..000443a2 --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java @@ -0,0 +1,103 @@ +package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; + +import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.event.EventTicket; +import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; +import jakarta.persistence.*; + +import java.util.Objects; +import java.util.UUID; + +@Entity(name = "EventTicket") +@Table(name = "events_tickets") +public class EventTicketEntity { + + @Id + private UUID ticketId; + + private UUID customerId; + + private int ordering; + + @ManyToOne(fetch = FetchType.LAZY) + private EventEntity event; + + public EventTicketEntity() { + } + + public EventTicketEntity( + final UUID ticketId, + final UUID customerId, + final int ordering, + final EventEntity event + ) { + this.ticketId = ticketId; + this.customerId = customerId; + this.event = event; + this.ordering = ordering; + } + + public static EventTicketEntity of(final EventEntity event, final EventTicket ev) { + return new EventTicketEntity( + UUID.fromString(ev.ticketId().value()), + UUID.fromString(ev.customerId().value()), + ev.ordering(), + event + ); + } + + public EventTicket toEventTicket() { + return new EventTicket( + TicketId.with(this.ticketId.toString()), + EventId.with(this.event.id().toString()), + CustomerId.with(this.customerId.toString()), + this.ordering + ); + } + + public UUID ticketId() { + return ticketId; + } + + public void setTicketId(UUID ticketId) { + this.ticketId = ticketId; + } + + public UUID customerId() { + return customerId; + } + + public void setCustomerId(UUID customerId) { + this.customerId = customerId; + } + + public int ordering() { + return ordering; + } + + public void setOrdering(int ordering) { + this.ordering = ordering; + } + + public EventEntity event() { + return event; + } + + public void setEvent(EventEntity event) { + this.event = event; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EventTicketEntity that = (EventTicketEntity) o; + return ordering == that.ordering && Objects.equals(ticketId, that.ticketId) && Objects.equals(customerId, that.customerId) && Objects.equals(event, that.event); + } + + @Override + public int hashCode() { + return Objects.hash(ticketId, customerId, ordering, event); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java index d538cc8f..1255ee22 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java @@ -8,7 +8,7 @@ import java.util.UUID; -@Entity +@Entity(name = "Partner") @Table(name = "partners") public class PartnerEntity { diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java index 74b7fd4f..a9ee8724 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java @@ -11,7 +11,7 @@ import java.util.Objects; import java.util.UUID; -@Entity +@Entity(name = "Ticket") @Table(name = "tickets") public class TicketEntity { diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java index 1306fae4..8ade8c17 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java @@ -3,6 +3,8 @@ import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.EventEntity; import org.springframework.data.repository.CrudRepository; -public interface EventJpaRepository extends CrudRepository { +import java.util.UUID; + +public interface EventJpaRepository extends CrudRepository { } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java index 5c827ac2..7c45c44a 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java @@ -58,4 +58,9 @@ public Customer update(Customer customer) { return this.customerJpaRepository.save(CustomerEntity.of(customer)) .toCustomer(); } + + @Override + public void deleteAll() { + this.customerJpaRepository.deleteAll(); + } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java new file mode 100644 index 00000000..ac81385c --- /dev/null +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java @@ -0,0 +1,50 @@ +package br.com.fullcycle.hexagonal.infrastructure.repositories; + +import br.com.fullcycle.hexagonal.application.domain.event.Event; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.EventEntity; +import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +// Interface Adapter +@Component +public class EventDatabaseRepository implements EventRepository { + + private final EventJpaRepository eventJpaRepository; + + public EventDatabaseRepository(final EventJpaRepository EventJpaRepository) { + this.eventJpaRepository = Objects.requireNonNull(EventJpaRepository); + } + + @Override + public Optional eventOfId(final EventId anId) { + Objects.requireNonNull(anId, "id cannot be null"); + return this.eventJpaRepository.findById(UUID.fromString(anId.value())) + .map(EventEntity::toEvent); + } + + @Override + @Transactional + public Event create(final Event Event) { + return this.eventJpaRepository.save(EventEntity.of(Event)) + .toEvent(); + } + + @Override + @Transactional + public Event update(Event Event) { + return this.eventJpaRepository.save(EventEntity.of(Event)) + .toEvent(); + } + + @Override + public void deleteAll() { + this.eventJpaRepository.deleteAll(); + } +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java index ac93a2ab..54979b2c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java @@ -58,4 +58,9 @@ public Partner update(Partner partner) { return this.partnerJpaRepository.save(PartnerEntity.of(partner)) .toPartner(); } + + @Override + public void deleteAll() { + this.partnerJpaRepository.deleteAll(); + } } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java index 17ed1bff..bf3c0499 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java +++ b/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java @@ -42,4 +42,9 @@ public Ticket update(Ticket ticket) { return this.ticketJpaRepository.save(TicketEntity.of(ticket)) .toTicket(); } + + @Override + public void deleteAll() { + this.ticketJpaRepository.deleteAll(); + } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java index e77bac8b..b69999b8 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java @@ -53,4 +53,11 @@ public Customer update(Customer customer) { this.customersByEmail.put(customer.email().value(), customer); return customer; } + + @Override + public void deleteAll() { + this.customers.clear(); + this.customersByCPF.clear(); + this.customersByEmail.clear(); + } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java index 289d4c60..34a80af7 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java @@ -33,4 +33,9 @@ public Event update(Event event) { this.events.put(event.eventId().value(), event); return event; } + + @Override + public void deleteAll() { + this.events.clear(); + } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java index 20d99b97..37e44d8c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java @@ -53,4 +53,11 @@ public Partner update(Partner partner) { this.partnersByEmail.put(partner.email().value(), partner); return partner; } + + @Override + public void deleteAll() { + this.partners.clear(); + this.partnersByCNPJ.clear(); + this.partnersByEmail.clear(); + } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java index 74c68a81..73d2baa8 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java @@ -33,4 +33,9 @@ public Ticket update(Ticket ticket) { this.tickets.put(ticket.ticketId().value(), ticket); return ticket; } + + @Override + public void deleteAll() { + this.tickets.clear(); + } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java index 45b5de4d..17551a71 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java @@ -1,11 +1,11 @@ package br.com.fullcycle.hexagonal.application.usecases.customer; import br.com.fullcycle.hexagonal.IntegrationTest; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; -import org.junit.jupiter.api.AfterEach; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -16,10 +16,10 @@ public class CreateCustomerUseCaseIT extends IntegrationTest { private CreateCustomerUseCase useCase; @Autowired - private CustomerJpaRepository customerRepository; + private CustomerRepository customerRepository; - @AfterEach - void tearDown() { + @BeforeEach + void setUp() { customerRepository.deleteAll(); } @@ -27,7 +27,7 @@ void tearDown() { @DisplayName("Deve criar um cliente") public void testCreateCustomer() { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; @@ -47,7 +47,7 @@ public void testCreateCustomer() { @DisplayName("Não deve cadastrar um cliente com CPF duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Customer already exists"; @@ -67,12 +67,12 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { // given - final var expectedCPF = "12345678901"; + final var expectedCPF = "123.456.789-01"; final var expectedEmail = "john.doe@gmail.com"; final var expectedName = "John Doe"; final var expectedError = "Customer already exists"; - createCustomer("23132131231", expectedEmail, expectedName); + createCustomer("231.321.312-31", expectedEmail, expectedName); final var createInput = new CreateCustomerUseCase.Input(expectedCPF, expectedEmail, expectedName); @@ -83,12 +83,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { Assertions.assertEquals(expectedError, actualException.getMessage()); } - private CustomerEntity createCustomer(final String cpf, final String email, final String name) { - final var aCustomer = new CustomerEntity(); - aCustomer.setCpf(cpf); - aCustomer.setName(name); - aCustomer.setEmail(email); - - return customerRepository.save(aCustomer); + private Customer createCustomer(final String cpf, final String email, final String name) { + return customerRepository.create(Customer.newCustomer(name, cpf, email)); } } diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java index ca001f50..96168ddf 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java @@ -1,8 +1,11 @@ package br.com.fullcycle.hexagonal.application.usecases.event; import br.com.fullcycle.hexagonal.IntegrationTest; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; @@ -18,13 +21,13 @@ class CreateEventUseCaseIT extends IntegrationTest { private CreateEventUseCase useCase; @Autowired - private EventJpaRepository eventRepository; + private EventRepository eventRepository; @Autowired - private PartnerJpaRepository partnerRepository; + private PartnerRepository partnerRepository; @BeforeEach - void tearDown() { + void setUp() { eventRepository.deleteAll(); partnerRepository.deleteAll(); } @@ -33,11 +36,11 @@ void tearDown() { @DisplayName("Deve criar um evento") public void testCreate() throws Exception { // given - final var partner = createPartner("41536538000100", "john.doe@gmail.com", "John Doe"); + final var partner = createPartner("41.536.538/0001-00", "john.doe@gmail.com", "John Doe"); final var expectedDate = "2021-01-01"; final var expectedName = "Disney on Ice"; final var expectedTotalSpots = 10; - final var expectedPartnerId = partner.getId().toString(); + final var expectedPartnerId = partner.partnerId().value(); final var createInput = new CreateEventUseCase.Input(expectedDate, expectedName, expectedPartnerId, expectedTotalSpots); @@ -73,11 +76,7 @@ public void testCreateEvent_whenPartnerDoesntExists_ShouldThrowError() throws Ex Assertions.assertEquals(expectedError, actualException.getMessage()); } - private PartnerEntity createPartner(final String cnpj, final String email, final String name) { - final var aPartner = new PartnerEntity(); - aPartner.setCnpj(cnpj); - aPartner.setName(name); - aPartner.setEmail(email); - return partnerRepository.save(aPartner); + private Partner createPartner(final String cnpj, final String email, final String name) { + return partnerRepository.create(Partner.newPartner(name, cnpj, email)); } } \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java index 5f63dcd4..5df0534a 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java @@ -5,8 +5,8 @@ import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,8 +32,8 @@ public class CustomerControllerTest { @Autowired private CustomerJpaRepository customerRepository; - @AfterEach - void tearDown() { + @BeforeEach + void setUp() { customerRepository.deleteAll(); } @@ -41,7 +41,7 @@ void tearDown() { @DisplayName("Deve criar um cliente") public void testCreate() throws Exception { - var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); + var customer = new NewCustomerDTO("123.456.789-01", "john.doe@gmail.com", "John Doe"); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/customers") @@ -50,7 +50,7 @@ public void testCreate() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); var actualResponse = mapper.readValue(result, NewCustomerDTO.class); @@ -63,7 +63,7 @@ public void testCreate() throws Exception { @DisplayName("Não deve cadastrar um cliente com CPF duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { - var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); + var customer = new NewCustomerDTO("123.456.789-01", "john.doe@gmail.com", "John Doe"); // Cria o primeiro cliente this.mvc.perform( @@ -73,10 +73,10 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); - customer = new NewCustomerDTO("12345678901", "john2@gmail.com", "John Doe"); + customer = new NewCustomerDTO("123.456.789-01", "john2@gmail.com", "John Doe"); // Tenta criar o segundo cliente com o mesmo CPF this.mvc.perform( @@ -92,7 +92,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um cliente com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { - var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); + var customer = new NewCustomerDTO("123.456.789-01", "john.doe@gmail.com", "John Doe"); // Cria o primeiro cliente this.mvc.perform( @@ -102,10 +102,10 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); - customer = new NewCustomerDTO("99999918901", "john.doe@gmail.com", "John Doe"); + customer = new NewCustomerDTO("999.999.189-01", "john.doe@gmail.com", "John Doe"); // Tenta criar o segundo cliente com o mesmo CPF this.mvc.perform( @@ -121,7 +121,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { @DisplayName("Deve obter um cliente por id") public void testGet() throws Exception { - var customer = new NewCustomerDTO("12345678901", "john.doe@gmail.com", "John Doe"); + var customer = new NewCustomerDTO("123.456.789-01", "john.doe@gmail.com", "John Doe"); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/customers") diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java index eb2fca90..02e4d02d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java @@ -1,15 +1,19 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; +import br.com.fullcycle.hexagonal.application.domain.customer.Customer; +import br.com.fullcycle.hexagonal.application.domain.event.EventId; +import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -32,35 +36,32 @@ class EventControllerTest { private ObjectMapper mapper; @Autowired - private CustomerJpaRepository customerRepository; + private CustomerRepository customerRepository; @Autowired - private PartnerJpaRepository partnerRepository; + private PartnerRepository partnerRepository; @Autowired - private EventJpaRepository eventRepository; + private EventRepository eventRepository; - private CustomerEntity johnDoe; - private PartnerEntity disney; + private Customer johnDoe; + private Partner disney; @BeforeEach void setUp() { - johnDoe = customerRepository.save(new CustomerEntity(null, "John Doe", "123", "john@gmail.com")); - disney = partnerRepository.save(new PartnerEntity(null, "Disney", "456", "disney@gmail.com")); - } - - @AfterEach - void tearDown() { eventRepository.deleteAll(); customerRepository.deleteAll(); partnerRepository.deleteAll(); + + johnDoe = customerRepository.create(Customer.newCustomer("John Doe", "123.456.789-00", "john@gmail.com")); + disney = partnerRepository.create(Partner.newPartner("Disney", "45.123.123/0001-12", "disney@gmail.com")); } @Test @DisplayName("Deve criar um evento") public void testCreate() throws Exception { - var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId().toString()); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -68,7 +69,7 @@ public void testCreate() throws Exception { .content(mapper.writeValueAsString(event)) ) .andExpect(MockMvcResultMatchers.status().isCreated()) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); var actualResponse = mapper.readValue(result, NewEventDTO.class); @@ -82,7 +83,7 @@ public void testCreate() throws Exception { @DisplayName("Deve comprar um ticket de um evento") public void testReserveTicket() throws Exception { - var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.getId().toString()); + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/events") @@ -90,12 +91,12 @@ public void testReserveTicket() throws Exception { .content(mapper.writeValueAsString(event)) ) .andExpect(MockMvcResultMatchers.status().isCreated()) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); - var sub = new SubscribeDTO(johnDoe.getId().toString(), null); + var sub = new SubscribeDTO(johnDoe.customerId().value(), null); this.mvc.perform( MockMvcRequestBuilders.post("/events/{id}/subscribe", eventId) @@ -105,7 +106,7 @@ public void testReserveTicket() throws Exception { .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn().getResponse().getContentAsByteArray(); - var actualEvent = eventRepository.findById(Long.parseLong(eventId)).get(); - Assertions.assertEquals(1, actualEvent.getTickets().size()); + var actualEvent = eventRepository.eventOfId(EventId.with(eventId)).get(); + Assertions.assertEquals(1, actualEvent.allTickets().size()); } } \ No newline at end of file diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java index 12b56a4b..ac59fcda 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java @@ -1,14 +1,12 @@ package br.com.fullcycle.hexagonal.infrastructure.rest; +import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -30,10 +28,10 @@ public class PartnerControllerTest { private ObjectMapper mapper; @Autowired - private PartnerJpaRepository partnerRepository; + private PartnerRepository partnerRepository; - @AfterEach - void tearDown() { + @BeforeEach + void setUP() { partnerRepository.deleteAll(); } @@ -41,7 +39,7 @@ void tearDown() { @DisplayName("Deve criar um parceiro") public void testCreate() throws Exception { - var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); + var partner = new NewPartnerDTO("41.536.538/0001-00", "john.doe@gmail.com", "John Doe"); final var result = this.mvc.perform( MockMvcRequestBuilders.post("/partners") @@ -50,7 +48,7 @@ public void testCreate() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); var actualResponse = mapper.readValue(result, NewPartnerDTO.class); @@ -63,7 +61,7 @@ public void testCreate() throws Exception { @DisplayName("Não deve cadastrar um parceiro com CNPJ duplicado") public void testCreateWithDuplicatedCPFShouldFail() throws Exception { - var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); + var partner = new NewPartnerDTO("41.536.538/0001-00", "john.doe@gmail.com", "John Doe"); // Cria o primeiro parceiro this.mvc.perform( @@ -73,10 +71,10 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); - partner = new NewPartnerDTO("41536538000100", "john2@gmail.com", "John Doe"); + partner = new NewPartnerDTO("41.536.538/0001-00", "john2@gmail.com", "John Doe"); // Tenta criar o segundo parceiro com o mesmo CPF this.mvc.perform( @@ -92,7 +90,7 @@ public void testCreateWithDuplicatedCPFShouldFail() throws Exception { @DisplayName("Não deve cadastrar um parceiro com e-mail duplicado") public void testCreateWithDuplicatedEmailShouldFail() throws Exception { - var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); + var partner = new NewPartnerDTO("41.536.538/0001-00", "john.doe@gmail.com", "John Doe"); // Cria o primeiro parceiro this.mvc.perform( @@ -102,10 +100,10 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { ) .andExpect(MockMvcResultMatchers.status().isCreated()) .andExpect(MockMvcResultMatchers.header().exists("Location")) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").isString()) .andReturn().getResponse().getContentAsByteArray(); - partner = new NewPartnerDTO("66666538000100", "john.doe@gmail.com", "John Doe"); + partner = new NewPartnerDTO("66.666.538/0001-00", "john.doe@gmail.com", "John Doe"); // Tenta criar o segundo parceiro com o mesmo CNPJ this.mvc.perform( @@ -121,7 +119,7 @@ public void testCreateWithDuplicatedEmailShouldFail() throws Exception { @DisplayName("Deve obter um parceiro por id") public void testGet() throws Exception { - var partner = new NewPartnerDTO("41536538000100", "john.doe@gmail.com", "John Doe"); + var partner = new NewPartnerDTO("41.536.538/0001-00", "john.doe@gmail.com", "John Doe"); final var createResult = this.mvc.perform( MockMvcRequestBuilders.post("/partners") From b9616389be1eac6f6ffd456d819fa601796000dc Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 3 Sep 2023 21:16:17 -0300 Subject: [PATCH 16/22] 01-segregando-as-camadas-de-domain-e-application --- application/build.gradle.kts | 21 ++++++++++ .../application}/NullaryUseCase.java | 2 +- .../fullcycle/application}/UnitUseCase.java | 2 +- .../com/fullcycle/application}/UseCase.java | 2 +- .../customer/CreateCustomerUseCase.java | 16 +++---- .../customer/GetCustomerByIdUseCase.java | 8 ++-- .../event/CreateEventUseCase.java | 16 +++---- .../SubscribeCustomerToEventUseCase.java | 20 ++++----- .../partner/CreatePartnerUseCase.java | 16 +++---- .../partner/GetPartnerByIdUseCase.java | 8 ++-- .../customer/CreateCustomerUseCaseTest.java | 8 ++-- .../customer/GetCustomerByIdUseCaseTest.java | 7 ++-- .../event/CreateEventUseCaseTest.java | 13 +++--- .../SubscribeCustomerToEventUseCaseTest.java | 24 +++++------ .../partner/CreatePartnerUseCaseTest.java | 9 ++-- .../partner/GetPartnerByIdUseCaseTest.java | 7 ++-- .../InMemoryCustomerRepository.java | 12 +++--- .../repository/InMemoryEventRepository.java | 8 ++-- .../repository/InMemoryPartnerRepository.java | 12 +++--- .../repository/InMemoryTicketRepository.java | 8 ++-- domain/build.gradle.kts | 19 +++++++++ .../fullcycle}/domain/customer/Customer.java | 10 ++--- .../domain/customer/CustomerId.java | 4 +- .../domain/customer/CustomerRepository.java | 21 ++++++++++ .../br/com/fullcycle}/domain/event/Event.java | 16 +++---- .../com/fullcycle}/domain/event/EventId.java | 4 +- .../domain/event}/EventRepository.java | 5 +-- .../fullcycle}/domain/event/EventTicket.java | 8 ++-- .../domain/event/ticket/Ticket.java | 8 ++-- .../domain/event/ticket/TicketId.java | 4 +- .../domain/event/ticket/TicketRepository.java | 14 +++++++ .../domain/event/ticket/TicketStatus.java | 5 +++ .../exceptions/ValidationException.java | 2 +- .../fullcycle}/domain/partner/Partner.java | 10 ++--- .../fullcycle}/domain/partner/PartnerId.java | 4 +- .../domain/partner/PartnerRepository.java | 21 ++++++++++ .../br/com/fullcycle}/domain/person/Cnpj.java | 4 +- .../br/com/fullcycle}/domain/person/Cpf.java | 4 +- .../com/fullcycle}/domain/person/Email.java | 4 +- .../br/com/fullcycle}/domain/person/Name.java | 4 +- .../domain/customer/CustomerTest.java | 5 +-- .../fullcycle}/domain/event/EventTest.java | 10 ++--- .../domain/event/ticket/TicketTest.java | 8 ++-- .../domain/partner/PartnerTest.java | 4 +- .../fullcycle}/domain/person/CnpjTest.java | 4 +- .../com/fullcycle}/domain/person/CpfTest.java | 4 +- .../fullcycle}/domain/person/EmailTest.java | 4 +- infrastructure/.gitignore | 42 +++++++++++++++++++ infrastructure/build.gradle.kts | 19 +++++++++ .../src/main/java/br/com/fullcycle/Main.java | 7 ++++ settings.gradle.kts | 3 ++ .../domain/event/ticket/TicketStatus.java | 5 --- .../repositories/CustomerRepository.java | 23 ---------- .../repositories/PartnerRepository.java | 23 ---------- .../repositories/TicketRepository.java | 17 -------- .../CreateCustomerUseCaseIT.java | 2 +- .../{event => }/CreateEventUseCaseIT.java | 5 +-- .../rest/PartnerControllerTest.java | 1 - 58 files changed, 334 insertions(+), 242 deletions(-) create mode 100644 application/build.gradle.kts rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/NullaryUseCase.java (82%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/UnitUseCase.java (82%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/UseCase.java (82%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/customer/CreateCustomerUseCase.java (70%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/customer/GetCustomerByIdUseCase.java (76%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/event/CreateEventUseCase.java (72%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/event/SubscribeCustomerToEventUseCase.java (71%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/partner/CreatePartnerUseCase.java (71%) rename {src/main/java/br/com/fullcycle/hexagonal/application/usecases => application/src/main/java/br/com/fullcycle/application}/partner/GetPartnerByIdUseCase.java (77%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/customer/CreateCustomerUseCaseTest.java (91%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/customer/GetCustomerByIdUseCaseTest.java (85%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/event/CreateEventUseCaseTest.java (82%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/event/SubscribeCustomerToEventUseCaseTest.java (90%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/partner/CreatePartnerUseCaseTest.java (88%) rename {src/test/java/br/com/fullcycle/hexagonal/application/usecases => application/src/test/java/br/com/fullcycle/application}/partner/GetPartnerByIdUseCaseTest.java (85%) rename {src/test/java/br/com/fullcycle/hexagonal => application/src/test/java/br/com/fullcycle}/application/repository/InMemoryCustomerRepository.java (81%) rename {src/test/java/br/com/fullcycle/hexagonal => application/src/test/java/br/com/fullcycle}/application/repository/InMemoryEventRepository.java (75%) rename {src/test/java/br/com/fullcycle/hexagonal => application/src/test/java/br/com/fullcycle}/application/repository/InMemoryPartnerRepository.java (81%) rename {src/test/java/br/com/fullcycle/hexagonal => application/src/test/java/br/com/fullcycle}/application/repository/InMemoryTicketRepository.java (74%) create mode 100644 domain/build.gradle.kts rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/customer/Customer.java (81%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/customer/CustomerId.java (80%) create mode 100644 domain/src/main/java/br/com/fullcycle/domain/customer/CustomerRepository.java rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/event/Event.java (89%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/event/EventId.java (80%) rename {src/main/java/br/com/fullcycle/hexagonal/application/repositories => domain/src/main/java/br/com/fullcycle/domain/event}/EventRepository.java (50%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/event/EventTicket.java (81%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/event/ticket/Ticket.java (90%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/event/ticket/TicketId.java (80%) create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle/domain}/exceptions/ValidationException.java (83%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/partner/Partner.java (81%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/partner/PartnerId.java (80%) create mode 100644 domain/src/main/java/br/com/fullcycle/domain/partner/PartnerRepository.java rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/person/Cnpj.java (62%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/person/Cpf.java (61%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/person/Email.java (64%) rename {src/main/java/br/com/fullcycle/hexagonal/application => domain/src/main/java/br/com/fullcycle}/domain/person/Name.java (55%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/customer/CustomerTest.java (91%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/event/EventTest.java (95%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/event/ticket/TicketTest.java (83%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/partner/PartnerTest.java (94%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/person/CnpjTest.java (90%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/person/CpfTest.java (90%) rename {src/test/java/br/com/fullcycle/hexagonal/application => domain/src/test/java/br/com/fullcycle}/domain/person/EmailTest.java (90%) create mode 100644 infrastructure/.gitignore create mode 100644 infrastructure/build.gradle.kts create mode 100644 infrastructure/src/main/java/br/com/fullcycle/Main.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java delete mode 100644 src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java rename src/test/java/br/com/fullcycle/hexagonal/application/{usecases/customer => }/CreateCustomerUseCaseIT.java (98%) rename src/test/java/br/com/fullcycle/hexagonal/application/usecases/{event => }/CreateEventUseCaseIT.java (90%) diff --git a/application/build.gradle.kts b/application/build.gradle.kts new file mode 100644 index 00000000..5dbffff5 --- /dev/null +++ b/application/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + id("java") +} + +group = "br.com.fullcycle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + implementation(project(":domain")) + + testImplementation(platform("org.junit:junit-bom:5.9.1")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java b/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java rename to application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java index cb2cc894..2261aa1f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/NullaryUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.application; public abstract class NullaryUseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java b/application/src/main/java/br/com/fullcycle/application/UnitUseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java rename to application/src/main/java/br/com/fullcycle/application/UnitUseCase.java index c0d178c5..cd14f22c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UnitUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/UnitUseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.application; public abstract class UnitUseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java b/application/src/main/java/br/com/fullcycle/application/UseCase.java similarity index 82% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java rename to application/src/main/java/br/com/fullcycle/application/UseCase.java index a33e82f8..584f9649 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/UseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/UseCase.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.application; public abstract class UseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java b/application/src/main/java/br/com/fullcycle/application/customer/CreateCustomerUseCase.java similarity index 70% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java rename to application/src/main/java/br/com/fullcycle/application/customer/CreateCustomerUseCase.java index d58d3ff0..5afc486b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/customer/CreateCustomerUseCase.java @@ -1,11 +1,11 @@ -package br.com.fullcycle.hexagonal.application.usecases.customer; - -import br.com.fullcycle.hexagonal.application.domain.person.Cpf; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +package br.com.fullcycle.application.customer; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.person.Cpf; +import br.com.fullcycle.domain.person.Email; public class CreateCustomerUseCase extends UseCase { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java b/application/src/main/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCase.java similarity index 76% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java rename to application/src/main/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCase.java index bbb48a51..88788dc1 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCase.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases.customer; +package br.com.fullcycle.application.customer; -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.customer.CustomerRepository; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java similarity index 72% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java rename to application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java index 37bd9fea..cef3d8e0 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java @@ -1,11 +1,11 @@ -package br.com.fullcycle.hexagonal.application.usecases.event; - -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.partner.PartnerRepository; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java similarity index 71% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java rename to application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java index 550a4c01..25b0e7d7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java @@ -1,13 +1,13 @@ -package br.com.fullcycle.hexagonal.application.usecases.event; - -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.time.Instant; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java b/application/src/main/java/br/com/fullcycle/application/partner/CreatePartnerUseCase.java similarity index 71% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java rename to application/src/main/java/br/com/fullcycle/application/partner/CreatePartnerUseCase.java index f7abce2f..74fd70a7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/partner/CreatePartnerUseCase.java @@ -1,11 +1,11 @@ -package br.com.fullcycle.hexagonal.application.usecases.partner; - -import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +package br.com.fullcycle.application.partner; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.domain.person.Cnpj; +import br.com.fullcycle.domain.person.Email; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java b/application/src/main/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCase.java similarity index 77% rename from src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java rename to application/src/main/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCase.java index 519ccc7c..0dd286c7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCase.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases.partner; +package br.com.fullcycle.application.partner; -import br.com.fullcycle.hexagonal.application.usecases.UseCase; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.partner.PartnerRepository; import java.util.Objects; import java.util.Optional; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/customer/CreateCustomerUseCaseTest.java similarity index 91% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/customer/CreateCustomerUseCaseTest.java index b370c915..a4c0ff69 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/customer/CreateCustomerUseCaseTest.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases.customer; +package br.com.fullcycle.application.customer; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.repository.InMemoryCustomerRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCaseTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCaseTest.java index 4d3dbadf..e2dbf40d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/GetCustomerByIdUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/customer/GetCustomerByIdUseCaseTest.java @@ -1,8 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases.customer; +package br.com.fullcycle.application.customer; -import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.domain.customer.Customer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/CreateEventUseCaseTest.java similarity index 82% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/event/CreateEventUseCaseTest.java index 053ed237..c5fb76b4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/event/CreateEventUseCaseTest.java @@ -1,11 +1,10 @@ -package br.com.fullcycle.hexagonal.application.usecases.event; +package br.com.fullcycle.application.event; -import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; -import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; +import br.com.fullcycle.application.repository.InMemoryEventRepository; +import br.com.fullcycle.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java index a5c8c6dc..05ee8144 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/SubscribeCustomerToEventUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java @@ -1,15 +1,15 @@ -package br.com.fullcycle.hexagonal.application.usecases.event; - -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repository.InMemoryCustomerRepository; -import br.com.fullcycle.hexagonal.application.repository.InMemoryEventRepository; -import br.com.fullcycle.hexagonal.application.repository.InMemoryTicketRepository; +package br.com.fullcycle.application.event; + +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.ticket.TicketStatus; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.application.repository.InMemoryEventRepository; +import br.com.fullcycle.application.repository.InMemoryTicketRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/partner/CreatePartnerUseCaseTest.java similarity index 88% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/partner/CreatePartnerUseCaseTest.java index 20b23fe4..39e15e0d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/CreatePartnerUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/partner/CreatePartnerUseCaseTest.java @@ -1,9 +1,8 @@ -package br.com.fullcycle.hexagonal.application.usecases.partner; +package br.com.fullcycle.application.partner; -import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCaseTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java rename to application/src/test/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCaseTest.java index 475be382..462f297f 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/partner/GetPartnerByIdUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/partner/GetPartnerByIdUseCaseTest.java @@ -1,8 +1,7 @@ -package br.com.fullcycle.hexagonal.application.usecases.partner; +package br.com.fullcycle.application.partner; -import br.com.fullcycle.hexagonal.application.repository.InMemoryPartnerRepository; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.application.repository.InMemoryPartnerRepository; +import br.com.fullcycle.domain.partner.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryCustomerRepository.java similarity index 81% rename from src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java rename to application/src/test/java/br/com/fullcycle/application/repository/InMemoryCustomerRepository.java index b69999b8..a59490e6 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryCustomerRepository.java +++ b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryCustomerRepository.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.application.repository; +package br.com.fullcycle.application.repository; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cpf; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.person.Cpf; +import br.com.fullcycle.domain.person.Email; import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryEventRepository.java similarity index 75% rename from src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java rename to application/src/test/java/br/com/fullcycle/application/repository/InMemoryEventRepository.java index 34a80af7..87a370ed 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryEventRepository.java +++ b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryEventRepository.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.repository; +package br.com.fullcycle.application.repository; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryPartnerRepository.java similarity index 81% rename from src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java rename to application/src/test/java/br/com/fullcycle/application/repository/InMemoryPartnerRepository.java index 37e44d8c..dcc49d86 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryPartnerRepository.java +++ b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryPartnerRepository.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.application.repository; +package br.com.fullcycle.application.repository; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.domain.person.Cnpj; +import br.com.fullcycle.domain.person.Email; import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java similarity index 74% rename from src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java rename to application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java index 73d2baa8..ddf3864c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/repository/InMemoryTicketRepository.java +++ b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.repository; +package br.com.fullcycle.application.repository; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; -import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketId; +import br.com.fullcycle.domain.event.ticket.TicketRepository; import java.util.HashMap; import java.util.Map; diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts new file mode 100644 index 00000000..342f0b3b --- /dev/null +++ b/domain/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("java") +} + +group = "br.com.fullcycle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(platform("org.junit:junit-bom:5.9.1")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java b/domain/src/main/java/br/com/fullcycle/domain/customer/Customer.java similarity index 81% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java rename to domain/src/main/java/br/com/fullcycle/domain/customer/Customer.java index 3ebaaa42..e7807acc 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/Customer.java +++ b/domain/src/main/java/br/com/fullcycle/domain/customer/Customer.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.application.domain.customer; +package br.com.fullcycle.domain.customer; -import br.com.fullcycle.hexagonal.application.domain.person.Cpf; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.domain.person.Name; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.person.Cpf; +import br.com.fullcycle.domain.person.Email; +import br.com.fullcycle.domain.person.Name; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java b/domain/src/main/java/br/com/fullcycle/domain/customer/CustomerId.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java rename to domain/src/main/java/br/com/fullcycle/domain/customer/CustomerId.java index 00a37293..71e8e17b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerId.java +++ b/domain/src/main/java/br/com/fullcycle/domain/customer/CustomerId.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.customer; +package br.com.fullcycle.domain.customer; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.util.UUID; diff --git a/domain/src/main/java/br/com/fullcycle/domain/customer/CustomerRepository.java b/domain/src/main/java/br/com/fullcycle/domain/customer/CustomerRepository.java new file mode 100644 index 00000000..41a5265a --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/customer/CustomerRepository.java @@ -0,0 +1,21 @@ +package br.com.fullcycle.domain.customer; + +import br.com.fullcycle.domain.person.Cpf; +import br.com.fullcycle.domain.person.Email; + +import java.util.Optional; + +public interface CustomerRepository { + + Optional customerOfId(CustomerId anId); + + Optional customerOfCPF(Cpf cpf); + + Optional customerOfEmail(Email email); + + Customer create(Customer customer); + + Customer update(Customer customer); + + void deleteAll(); +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java similarity index 89% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java rename to domain/src/main/java/br/com/fullcycle/domain/event/Event.java index 0d99a5e2..09b4779b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/Event.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java @@ -1,11 +1,11 @@ -package br.com.fullcycle.hexagonal.application.domain.event; - -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.domain.person.Name; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +package br.com.fullcycle.domain.event; + +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.person.Name; import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventId.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java rename to domain/src/main/java/br/com/fullcycle/domain/event/EventId.java index bf7501d2..a7905518 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventId.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventId.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.event; +package br.com.fullcycle.domain.event; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.util.UUID; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventRepository.java similarity index 50% rename from src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java rename to domain/src/main/java/br/com/fullcycle/domain/event/EventRepository.java index cc441cf5..24c4c20c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/EventRepository.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventRepository.java @@ -1,7 +1,4 @@ -package br.com.fullcycle.hexagonal.application.repositories; - -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; +package br.com.fullcycle.domain.event; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java similarity index 81% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java rename to domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java index 269c375c..13889013 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/EventTicket.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.domain.event; +package br.com.fullcycle.domain.event; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.ticket.TicketId; +import br.com.fullcycle.domain.exceptions.ValidationException; public class EventTicket { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java similarity index 90% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java rename to domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java index 86ccb13f..e37022a4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/Ticket.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.domain.event.ticket; +package br.com.fullcycle.domain.event.ticket; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.time.Instant; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketId.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java rename to domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketId.java index 1adf4dfd..aa702225 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketId.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketId.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.event.ticket; +package br.com.fullcycle.domain.event.ticket; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.util.UUID; diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java new file mode 100644 index 00000000..c30de970 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java @@ -0,0 +1,14 @@ +package br.com.fullcycle.domain.event.ticket; + +import java.util.Optional; + +public interface TicketRepository { + + Optional ticketOfId(TicketId anId); + + Ticket create(Ticket ticket); + + Ticket update(Ticket ticket); + + void deleteAll(); +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java new file mode 100644 index 00000000..9b27c4e5 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.domain.event.ticket; + +public enum TicketStatus { + PENDING, PROCESSING, PAID; +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java b/domain/src/main/java/br/com/fullcycle/domain/exceptions/ValidationException.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java rename to domain/src/main/java/br/com/fullcycle/domain/exceptions/ValidationException.java index a4dcb35a..66fbf9ec 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/exceptions/ValidationException.java +++ b/domain/src/main/java/br/com/fullcycle/domain/exceptions/ValidationException.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.exceptions; +package br.com.fullcycle.domain.exceptions; public class ValidationException extends RuntimeException { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java b/domain/src/main/java/br/com/fullcycle/domain/partner/Partner.java similarity index 81% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java rename to domain/src/main/java/br/com/fullcycle/domain/partner/Partner.java index c005cca8..b617356c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/Partner.java +++ b/domain/src/main/java/br/com/fullcycle/domain/partner/Partner.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.application.domain.partner; +package br.com.fullcycle.domain.partner; -import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.domain.person.Name; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.person.Cnpj; +import br.com.fullcycle.domain.person.Email; +import br.com.fullcycle.domain.person.Name; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java b/domain/src/main/java/br/com/fullcycle/domain/partner/PartnerId.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java rename to domain/src/main/java/br/com/fullcycle/domain/partner/PartnerId.java index af3d4399..e7505389 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerId.java +++ b/domain/src/main/java/br/com/fullcycle/domain/partner/PartnerId.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.partner; +package br.com.fullcycle.domain.partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import java.util.UUID; diff --git a/domain/src/main/java/br/com/fullcycle/domain/partner/PartnerRepository.java b/domain/src/main/java/br/com/fullcycle/domain/partner/PartnerRepository.java new file mode 100644 index 00000000..c16fe0fd --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/partner/PartnerRepository.java @@ -0,0 +1,21 @@ +package br.com.fullcycle.domain.partner; + +import br.com.fullcycle.domain.person.Cnpj; +import br.com.fullcycle.domain.person.Email; + +import java.util.Optional; + +public interface PartnerRepository { + + Optional partnerOfId(PartnerId anId); + + Optional partnerOfCNPJ(Cnpj cnpj); + + Optional partnerOfEmail(Email email); + + Partner create(Partner partner); + + Partner update(Partner partner); + + void deleteAll(); +} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java b/domain/src/main/java/br/com/fullcycle/domain/person/Cnpj.java similarity index 62% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java rename to domain/src/main/java/br/com/fullcycle/domain/person/Cnpj.java index 6ea42c77..443338fd 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cnpj.java +++ b/domain/src/main/java/br/com/fullcycle/domain/person/Cnpj.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; public record Cnpj(String value) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java b/domain/src/main/java/br/com/fullcycle/domain/person/Cpf.java similarity index 61% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java rename to domain/src/main/java/br/com/fullcycle/domain/person/Cpf.java index 9582ebcf..01c264c6 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Cpf.java +++ b/domain/src/main/java/br/com/fullcycle/domain/person/Cpf.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; public record Cpf(String value) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java b/domain/src/main/java/br/com/fullcycle/domain/person/Email.java similarity index 64% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java rename to domain/src/main/java/br/com/fullcycle/domain/person/Email.java index c8b852f9..bac5f1e7 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Email.java +++ b/domain/src/main/java/br/com/fullcycle/domain/person/Email.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; public record Email(String value) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java b/domain/src/main/java/br/com/fullcycle/domain/person/Name.java similarity index 55% rename from src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java rename to domain/src/main/java/br/com/fullcycle/domain/person/Name.java index 88362edf..ee523211 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/person/Name.java +++ b/domain/src/main/java/br/com/fullcycle/domain/person/Name.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; public record Name(String value) { diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java b/domain/src/test/java/br/com/fullcycle/domain/customer/CustomerTest.java similarity index 91% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java rename to domain/src/test/java/br/com/fullcycle/domain/customer/CustomerTest.java index 1d9f3e1f..fd466cf8 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/customer/CustomerTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/customer/CustomerTest.java @@ -1,7 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.customer; +package br.com.fullcycle.domain.customer; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java similarity index 95% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java rename to domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java index a79bab58..21e76628 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/EventTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.application.domain.event; +package br.com.fullcycle.domain.event; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.event.ticket.TicketStatus; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java b/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java similarity index 83% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java rename to domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java index c26a1b79..96cb9f1d 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.application.domain.event.ticket; +package br.com.fullcycle.domain.event.ticket; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.partner.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java b/domain/src/test/java/br/com/fullcycle/domain/partner/PartnerTest.java similarity index 94% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java rename to domain/src/test/java/br/com/fullcycle/domain/partner/PartnerTest.java index 3ef2299b..79025cc4 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/partner/PartnerTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/partner/PartnerTest.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.partner; +package br.com.fullcycle.domain.partner; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java b/domain/src/test/java/br/com/fullcycle/domain/person/CnpjTest.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java rename to domain/src/test/java/br/com/fullcycle/domain/person/CnpjTest.java index 1cfd5a62..d5a3d166 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CnpjTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/person/CnpjTest.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java b/domain/src/test/java/br/com/fullcycle/domain/person/CpfTest.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java rename to domain/src/test/java/br/com/fullcycle/domain/person/CpfTest.java index fc44e758..1743417a 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/CpfTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/person/CpfTest.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java b/domain/src/test/java/br/com/fullcycle/domain/person/EmailTest.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java rename to domain/src/test/java/br/com/fullcycle/domain/person/EmailTest.java index 6354c179..f50c339e 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/domain/person/EmailTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/person/EmailTest.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.application.domain.person; +package br.com.fullcycle.domain.person; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; +import br.com.fullcycle.domain.exceptions.ValidationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/infrastructure/.gitignore b/infrastructure/.gitignore new file mode 100644 index 00000000..b63da455 --- /dev/null +++ b/infrastructure/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/infrastructure/build.gradle.kts b/infrastructure/build.gradle.kts new file mode 100644 index 00000000..342f0b3b --- /dev/null +++ b/infrastructure/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("java") +} + +group = "br.com.fullcycle" +version = "0.0.1-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(platform("org.junit:junit-bom:5.9.1")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/infrastructure/src/main/java/br/com/fullcycle/Main.java b/infrastructure/src/main/java/br/com/fullcycle/Main.java new file mode 100644 index 00000000..888157f6 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/Main.java @@ -0,0 +1,7 @@ +package br.com.fullcycle; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 1194c105..54c9cb4f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,4 @@ rootProject.name = "mba-hexagonal-arch" +include("domain") +include("application") +include("infrastructure") diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java b/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java deleted file mode 100644 index f9016aa3..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/application/domain/event/ticket/TicketStatus.java +++ /dev/null @@ -1,5 +0,0 @@ -package br.com.fullcycle.hexagonal.application.domain.event.ticket; - -public enum TicketStatus { - PENDING, PROCESSING, PAID; -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java deleted file mode 100644 index d15f3010..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/CustomerRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package br.com.fullcycle.hexagonal.application.repositories; - -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cpf; -import br.com.fullcycle.hexagonal.application.domain.person.Email; - -import java.util.Optional; - -public interface CustomerRepository { - - Optional customerOfId(CustomerId anId); - - Optional customerOfCPF(Cpf cpf); - - Optional customerOfEmail(Email email); - - Customer create(Customer customer); - - Customer update(Customer customer); - - void deleteAll(); -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java deleted file mode 100644 index c26c9642..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/PartnerRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package br.com.fullcycle.hexagonal.application.repositories; - -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; -import br.com.fullcycle.hexagonal.application.domain.person.Email; - -import java.util.Optional; - -public interface PartnerRepository { - - Optional partnerOfId(PartnerId anId); - - Optional partnerOfCNPJ(Cnpj cnpj); - - Optional partnerOfEmail(Email email); - - Partner create(Partner partner); - - Partner update(Partner partner); - - void deleteAll(); -} diff --git a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java b/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java deleted file mode 100644 index dad8fad8..00000000 --- a/src/main/java/br/com/fullcycle/hexagonal/application/repositories/TicketRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package br.com.fullcycle.hexagonal.application.repositories; - -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; - -import java.util.Optional; - -public interface TicketRepository { - - Optional ticketOfId(TicketId anId); - - Ticket create(Ticket ticket); - - Ticket update(Ticket ticket); - - void deleteAll(); -} diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java similarity index 98% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java rename to src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java index 17551a71..bd283c9c 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/customer/CreateCustomerUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.usecases.customer; +package br.com.fullcycle.hexagonal.application; import br.com.fullcycle.hexagonal.IntegrationTest; import br.com.fullcycle.hexagonal.application.domain.customer.Customer; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java rename to src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java index 96168ddf..2310d6d3 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/event/CreateEventUseCaseIT.java +++ b/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.application.usecases.event; +package br.com.fullcycle.hexagonal.application.usecases; import br.com.fullcycle.hexagonal.IntegrationTest; import br.com.fullcycle.hexagonal.application.domain.partner.Partner; @@ -6,9 +6,6 @@ import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; import br.com.fullcycle.hexagonal.application.repositories.EventRepository; import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java index ac59fcda..a90a6cef 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java +++ b/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java @@ -4,7 +4,6 @@ import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; From 9f77293eb19e3508f75c65417c40539db3e09499 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 3 Sep 2023 21:36:11 -0300 Subject: [PATCH 17/22] 02-segregando-a-camada-de-infrastructure --- application/build.gradle.kts | 17 ++----- build.gradle.kts | 37 --------------- buildSrc/build.gradle.kts | 14 ++++++ .../main/kotlin/java-conventions.gradle.kts | 26 ++++++++++ domain/build.gradle.kts | 19 ++------ infrastructure/.gitignore | 42 ----------------- infrastructure/build.gradle.kts | 47 +++++++++++++++---- .../src/main/java/br/com/fullcycle/Main.java | 7 --- .../com/fullcycle}/infrastructure/Main.java | 2 +- .../configurations/UseCaseConfig.java | 22 ++++----- .../infrastructure/dtos/NewCustomerDTO.java | 2 +- .../infrastructure/dtos/NewEventDTO.java | 2 +- .../infrastructure/dtos/NewPartnerDTO.java | 2 +- .../infrastructure/dtos/SubscribeDTO.java | 2 +- .../graphql/CustomerResolver.java | 8 ++-- .../infrastructure/graphql/EventResolver.java | 10 ++-- .../graphql/PartnerResolver.java | 8 ++-- .../jpa/entities/CustomerEntity.java | 6 +-- .../jpa/entities/EventEntity.java | 6 +-- .../jpa/entities/EventTicketEntity.java | 10 ++-- .../jpa/entities/PartnerEntity.java | 6 +-- .../jpa/entities/TicketEntity.java | 12 ++--- .../repositories/CustomerJpaRepository.java | 4 +- .../jpa/repositories/EventJpaRepository.java | 4 +- .../repositories/PartnerJpaRepository.java | 4 +- .../jpa/repositories/TicketJpaRepository.java | 4 +- .../CustomerDatabaseRepository.java | 16 +++---- .../repositories/EventDatabaseRepository.java | 12 ++--- .../PartnerDatabaseRepository.java | 16 +++---- .../TicketDatabaseRepository.java | 12 ++--- .../rest/CustomerController.java | 10 ++-- .../infrastructure/rest/EventController.java | 17 +++---- .../rest/PartnerController.java | 10 ++-- .../resources/application-test.properties | 0 .../main/resources/application.properties | 0 .../src}/main/resources/graphql/schema.gqls | 0 .../br/com/fullcycle}/IntegrationTest.java | 4 +- .../application/CreateCustomerUseCaseIT.java | 11 +++-- .../usecases/CreateEventUseCaseIT.java | 15 +++--- .../fullcycle}/infrastructure/MainTests.java | 2 +- .../rest/CustomerControllerTest.java | 10 ++-- .../rest/EventControllerTest.java | 22 ++++----- .../rest/PartnerControllerTest.java | 10 ++-- 43 files changed, 226 insertions(+), 264 deletions(-) delete mode 100644 build.gradle.kts create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/java-conventions.gradle.kts delete mode 100644 infrastructure/.gitignore delete mode 100644 infrastructure/src/main/java/br/com/fullcycle/Main.java rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/Main.java (83%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/configurations/UseCaseConfig.java (67%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/dtos/NewCustomerDTO.java (56%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/dtos/NewEventDTO.java (69%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/dtos/NewPartnerDTO.java (56%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/dtos/SubscribeDTO.java (54%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/graphql/CustomerResolver.java (80%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/graphql/EventResolver.java (78%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/graphql/PartnerResolver.java (80%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/entities/CustomerEntity.java (89%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/entities/EventEntity.java (93%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/entities/EventTicketEntity.java (87%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/entities/PartnerEntity.java (87%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/entities/TicketEntity.java (86%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/repositories/CustomerJpaRepository.java (67%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/repositories/EventJpaRepository.java (54%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/repositories/PartnerJpaRepository.java (67%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/jpa/repositories/TicketJpaRepository.java (54%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/repositories/CustomerDatabaseRepository.java (75%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/repositories/EventDatabaseRepository.java (74%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/repositories/PartnerDatabaseRepository.java (75%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/repositories/TicketDatabaseRepository.java (73%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/rest/CustomerController.java (79%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/rest/EventController.java (79%) rename {src/main/java/br/com/fullcycle/hexagonal => infrastructure/src/main/java/br/com/fullcycle}/infrastructure/rest/PartnerController.java (79%) rename {src => infrastructure/src}/main/resources/application-test.properties (100%) rename {src => infrastructure/src}/main/resources/application.properties (100%) rename {src => infrastructure/src}/main/resources/graphql/schema.gqls (100%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/IntegrationTest.java (71%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/application/CreateCustomerUseCaseIT.java (90%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/application/usecases/CreateEventUseCaseIT.java (84%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/infrastructure/MainTests.java (83%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/infrastructure/rest/CustomerControllerTest.java (94%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/infrastructure/rest/EventControllerTest.java (85%) rename {src/test/java/br/com/fullcycle/hexagonal => infrastructure/src/test/java/br/com/fullcycle}/infrastructure/rest/PartnerControllerTest.java (94%) diff --git a/application/build.gradle.kts b/application/build.gradle.kts index 5dbffff5..c6e07c4e 100644 --- a/application/build.gradle.kts +++ b/application/build.gradle.kts @@ -1,21 +1,10 @@ plugins { - id("java") + `java-conventions` + `java-library` } -group = "br.com.fullcycle" -version = "0.0.1-SNAPSHOT" - -repositories { - mavenCentral() -} +group = "br.com.fullcycle.application" dependencies { implementation(project(":domain")) - - testImplementation(platform("org.junit:junit-bom:5.9.1")) - testImplementation("org.junit.jupiter:junit-jupiter") -} - -tasks.test { - useJUnitPlatform() } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts deleted file mode 100644 index 67eb6d1d..00000000 --- a/build.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ -plugins { - java - id("org.springframework.boot") version "3.1.2" - id("io.spring.dependency-management") version "1.1.2" -} - -group = "br.com.fullcycle" -version = "0.0.1-SNAPSHOT" - -java { - sourceCompatibility = JavaVersion.VERSION_17 -} - -repositories { - mavenCentral() -} - -dependencies { - implementation("io.hypersistence:hypersistence-tsid:2.1.0") - implementation("org.springframework.boot:spring-boot-starter-data-jpa") - implementation("org.springframework.boot:spring-boot-starter-graphql") - implementation("org.springframework.boot:spring-boot-starter-web") - - implementation("jakarta.inject:jakarta.inject-api:2.0.1") - - runtimeOnly("com.mysql:mysql-connector-j") - - testImplementation("org.springframework.boot:spring-boot-starter-test") - testImplementation("org.springframework:spring-webflux") - testImplementation("org.springframework.graphql:spring-graphql-test") - - testRuntimeOnly("com.h2database:h2") -} - -tasks.withType { - useJUnitPlatform() -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..4e91d6ff --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + `kotlin-dsl` +} + +version = "0.0.1-SNAPSHOT" + +java { + targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_17 +} + +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/java-conventions.gradle.kts b/buildSrc/src/main/kotlin/java-conventions.gradle.kts new file mode 100644 index 00000000..32b0a5e2 --- /dev/null +++ b/buildSrc/src/main/kotlin/java-conventions.gradle.kts @@ -0,0 +1,26 @@ +plugins { + java + jacoco +} + +java { + targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_17 +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(platform("org.junit:junit-bom:5.9.1")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +jacoco { + toolVersion = "0.8.9" +} + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 342f0b3b..55e94042 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -1,19 +1,6 @@ plugins { - id("java") + `java-conventions` + `java-library` } -group = "br.com.fullcycle" -version = "0.0.1-SNAPSHOT" - -repositories { - mavenCentral() -} - -dependencies { - testImplementation(platform("org.junit:junit-bom:5.9.1")) - testImplementation("org.junit.jupiter:junit-jupiter") -} - -tasks.test { - useJUnitPlatform() -} \ No newline at end of file +group = "br.com.fullcycle.domain" diff --git a/infrastructure/.gitignore b/infrastructure/.gitignore deleted file mode 100644 index b63da455..00000000 --- a/infrastructure/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store \ No newline at end of file diff --git a/infrastructure/build.gradle.kts b/infrastructure/build.gradle.kts index 342f0b3b..f56aea44 100644 --- a/infrastructure/build.gradle.kts +++ b/infrastructure/build.gradle.kts @@ -1,19 +1,48 @@ plugins { - id("java") + java + `java-conventions` + `jacoco-report-aggregation` + id("org.springframework.boot") version "3.1.2" + id("io.spring.dependency-management") version "1.1.2" } -group = "br.com.fullcycle" -version = "0.0.1-SNAPSHOT" +group = "br.com.fullcycle.infrastructure" -repositories { - mavenCentral() +tasks.bootJar { + archiveBaseName.set("application") + destinationDirectory.set(file("${rootProject.buildDir}/libs")) } dependencies { - testImplementation(platform("org.junit:junit-bom:5.9.1")) - testImplementation("org.junit.jupiter:junit-jupiter") + implementation(project(":domain")) + implementation(project(":application")) + + implementation("io.hypersistence:hypersistence-tsid:2.1.0") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-graphql") + implementation("org.springframework.boot:spring-boot-starter-web") + + implementation("jakarta.inject:jakarta.inject-api:2.0.1") + + runtimeOnly("com.mysql:mysql-connector-j") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework:spring-webflux") + testImplementation("org.springframework.graphql:spring-graphql-test") + + testRuntimeOnly("com.h2database:h2") +} + +tasks.testCodeCoverageReport { + reports { + xml.required.set(true) + xml.outputLocation.set(file("$rootDir/build/reports/jacoco/test/jacocoTestReport.xml")) + + html.required.set(true) + html.outputLocation.set(file("$rootDir/build/reports/jacoco/test/")) + } } -tasks.test { - useJUnitPlatform() +tasks.named("jacocoTestReport") { + dependsOn(tasks.named("testCodeCoverageReport")) } \ No newline at end of file diff --git a/infrastructure/src/main/java/br/com/fullcycle/Main.java b/infrastructure/src/main/java/br/com/fullcycle/Main.java deleted file mode 100644 index 888157f6..00000000 --- a/infrastructure/src/main/java/br/com/fullcycle/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package br.com.fullcycle; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java similarity index 83% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java index 3ca266b8..a60ac304 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/Main.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure; +package br.com.fullcycle.infrastructure; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java similarity index 67% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java index d754fc2b..5b6e83ad 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/configurations/UseCaseConfig.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java @@ -1,15 +1,15 @@ -package br.com.fullcycle.hexagonal.infrastructure.configurations; +package br.com.fullcycle.infrastructure.configurations; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; -import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.application.customer.CreateCustomerUseCase; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewCustomerDTO.java similarity index 56% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewCustomerDTO.java index 9631943d..8397b5fb 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewCustomerDTO.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewCustomerDTO.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; +package br.com.fullcycle.infrastructure.dtos; public record NewCustomerDTO(String cpf, String email, String name) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewEventDTO.java similarity index 69% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewEventDTO.java index aee49d71..0ad47aaf 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewEventDTO.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewEventDTO.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; +package br.com.fullcycle.infrastructure.dtos; public record NewEventDTO( String name, diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewPartnerDTO.java similarity index 56% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewPartnerDTO.java index d3987e8c..dbe3e78b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/NewPartnerDTO.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/NewPartnerDTO.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; +package br.com.fullcycle.infrastructure.dtos; public record NewPartnerDTO(String cnpj, String email, String name) { diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/SubscribeDTO.java similarity index 54% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/SubscribeDTO.java index 7018cc1e..cb0abc36 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/dtos/SubscribeDTO.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/dtos/SubscribeDTO.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure.dtos; +package br.com.fullcycle.infrastructure.dtos; public record SubscribeDTO(String customerId, String eventId) { } diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/CustomerResolver.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/CustomerResolver.java index 0fadf904..083242de 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/CustomerResolver.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/CustomerResolver.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.infrastructure.graphql; +package br.com.fullcycle.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; +import br.com.fullcycle.application.customer.CreateCustomerUseCase; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewCustomerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java similarity index 78% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java index 401b4559..5a7ae0f2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/EventResolver.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.graphql; +package br.com.fullcycle.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; -import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.infrastructure.dtos.NewEventDTO; +import br.com.fullcycle.infrastructure.dtos.SubscribeDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.stereotype.Controller; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/PartnerResolver.java similarity index 80% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/PartnerResolver.java index c5c72c82..173d7ed5 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/graphql/PartnerResolver.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/PartnerResolver.java @@ -1,8 +1,8 @@ -package br.com.fullcycle.hexagonal.infrastructure.graphql; +package br.com.fullcycle.infrastructure.graphql; -import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewPartnerDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.graphql.data.method.annotation.QueryMapping; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/CustomerEntity.java similarity index 89% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/CustomerEntity.java index d9477a72..ceee744e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/CustomerEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/CustomerEntity.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +package br.com.fullcycle.infrastructure.jpa.entities; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerId; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java similarity index 93% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java index 2b7ee3da..c504ffbd 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +package br.com.fullcycle.infrastructure.jpa.entities; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.event.EventTicket; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventTicket; import jakarta.persistence.*; import java.time.LocalDate; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java index 000443a2..a953062f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/EventTicketEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +package br.com.fullcycle.infrastructure.jpa.entities; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.domain.event.EventTicket; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventTicket; +import br.com.fullcycle.domain.event.ticket.TicketId; import jakarta.persistence.*; import java.util.Objects; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/PartnerEntity.java similarity index 87% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/PartnerEntity.java index 1255ee22..4df8d2c4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/PartnerEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/PartnerEntity.java @@ -1,7 +1,7 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +package br.com.fullcycle.infrastructure.jpa.entities; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/TicketEntity.java similarity index 86% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/TicketEntity.java index a9ee8724..1a779195 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/entities/TicketEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/TicketEntity.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.entities; +package br.com.fullcycle.infrastructure.jpa.entities; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketStatus; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketId; +import br.com.fullcycle.domain.event.ticket.TicketStatus; import jakarta.persistence.*; import java.time.Instant; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/CustomerJpaRepository.java similarity index 67% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/CustomerJpaRepository.java index 810190e4..d0acb9be 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/CustomerJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/CustomerJpaRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; +package br.com.fullcycle.infrastructure.jpa.repositories; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; +import br.com.fullcycle.infrastructure.jpa.entities.CustomerEntity; import org.springframework.data.repository.CrudRepository; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/EventJpaRepository.java similarity index 54% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/EventJpaRepository.java index 8ade8c17..7d70fe10 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/EventJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/EventJpaRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; +package br.com.fullcycle.infrastructure.jpa.repositories; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.EventEntity; +import br.com.fullcycle.infrastructure.jpa.entities.EventEntity; import org.springframework.data.repository.CrudRepository; import java.util.UUID; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/PartnerJpaRepository.java similarity index 67% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/PartnerJpaRepository.java index 96d02396..e626bd5c 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/PartnerJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/PartnerJpaRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; +package br.com.fullcycle.infrastructure.jpa.repositories; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; +import br.com.fullcycle.infrastructure.jpa.entities.PartnerEntity; import org.springframework.data.repository.CrudRepository; import java.util.Optional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java similarity index 54% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java index 6e0a2956..97458ef1 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/jpa/repositories/TicketJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal.infrastructure.jpa.repositories; +package br.com.fullcycle.infrastructure.jpa.repositories; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.TicketEntity; +import br.com.fullcycle.infrastructure.jpa.entities.TicketEntity; import org.springframework.data.repository.CrudRepository; import java.util.UUID; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/CustomerDatabaseRepository.java similarity index 75% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/CustomerDatabaseRepository.java index 7c45c44a..918db5d4 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/CustomerDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/CustomerDatabaseRepository.java @@ -1,12 +1,12 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; +package br.com.fullcycle.infrastructure.repositories; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.customer.CustomerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cpf; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.CustomerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.person.Cpf; +import br.com.fullcycle.domain.person.Email; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.infrastructure.jpa.entities.CustomerEntity; +import br.com.fullcycle.infrastructure.jpa.repositories.CustomerJpaRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java similarity index 74% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java index ac81385c..06fc162b 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/EventDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; +package br.com.fullcycle.infrastructure.repositories; -import br.com.fullcycle.hexagonal.application.domain.event.Event; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.EventEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.EventJpaRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.infrastructure.jpa.entities.EventEntity; +import br.com.fullcycle.infrastructure.jpa.repositories.EventJpaRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/PartnerDatabaseRepository.java similarity index 75% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/PartnerDatabaseRepository.java index 54979b2c..46d0335f 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/PartnerDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/PartnerDatabaseRepository.java @@ -1,12 +1,12 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; +package br.com.fullcycle.infrastructure.repositories; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.domain.person.Cnpj; -import br.com.fullcycle.hexagonal.application.domain.person.Email; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.PartnerEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.PartnerJpaRepository; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.person.Cnpj; +import br.com.fullcycle.domain.person.Email; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.infrastructure.jpa.entities.PartnerEntity; +import br.com.fullcycle.infrastructure.jpa.repositories.PartnerJpaRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java similarity index 73% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java index bf3c0499..0b16ddd2 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/repositories/TicketDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java @@ -1,10 +1,10 @@ -package br.com.fullcycle.hexagonal.infrastructure.repositories; +package br.com.fullcycle.infrastructure.repositories; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.Ticket; -import br.com.fullcycle.hexagonal.application.domain.event.ticket.TicketId; -import br.com.fullcycle.hexagonal.application.repositories.TicketRepository; -import br.com.fullcycle.hexagonal.infrastructure.jpa.entities.TicketEntity; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.TicketJpaRepository; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketId; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.infrastructure.jpa.entities.TicketEntity; +import br.com.fullcycle.infrastructure.jpa.repositories.TicketJpaRepository; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java similarity index 79% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java index 78eca03d..e69d369d 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; +package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.customer.CreateCustomerUseCase; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewCustomerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java similarity index 79% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java index b0d11b05..cf6a8761 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java @@ -1,10 +1,11 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; - -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; -import br.com.fullcycle.hexagonal.application.usecases.event.SubscribeCustomerToEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; -import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +package br.com.fullcycle.infrastructure.rest; + +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.infrastructure.dtos.NewEventDTO; +import br.com.fullcycle.infrastructure.dtos.SubscribeDTO; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -31,7 +32,7 @@ public EventController( } @PostMapping - @ResponseStatus(CREATED) + @ResponseStatus(HttpStatus.CREATED) public ResponseEntity create(@RequestBody NewEventDTO dto) { try { final var output = diff --git a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java similarity index 79% rename from src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java rename to infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java index 21236e0c..8698255e 100644 --- a/src/main/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; +package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewPartnerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/resources/application-test.properties b/infrastructure/src/main/resources/application-test.properties similarity index 100% rename from src/main/resources/application-test.properties rename to infrastructure/src/main/resources/application-test.properties diff --git a/src/main/resources/application.properties b/infrastructure/src/main/resources/application.properties similarity index 100% rename from src/main/resources/application.properties rename to infrastructure/src/main/resources/application.properties diff --git a/src/main/resources/graphql/schema.gqls b/infrastructure/src/main/resources/graphql/schema.gqls similarity index 100% rename from src/main/resources/graphql/schema.gqls rename to infrastructure/src/main/resources/graphql/schema.gqls diff --git a/src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java b/infrastructure/src/test/java/br/com/fullcycle/IntegrationTest.java similarity index 71% rename from src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java rename to infrastructure/src/test/java/br/com/fullcycle/IntegrationTest.java index 39a62207..0e5f9aa2 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/IntegrationTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/IntegrationTest.java @@ -1,6 +1,6 @@ -package br.com.fullcycle.hexagonal; +package br.com.fullcycle; -import br.com.fullcycle.hexagonal.infrastructure.Main; +import br.com.fullcycle.infrastructure.Main; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java b/infrastructure/src/test/java/br/com/fullcycle/application/CreateCustomerUseCaseIT.java similarity index 90% rename from src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java rename to infrastructure/src/test/java/br/com/fullcycle/application/CreateCustomerUseCaseIT.java index bd283c9c..991df4f6 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/CreateCustomerUseCaseIT.java +++ b/infrastructure/src/test/java/br/com/fullcycle/application/CreateCustomerUseCaseIT.java @@ -1,9 +1,10 @@ -package br.com.fullcycle.hexagonal.application; +package br.com.fullcycle.application; -import br.com.fullcycle.hexagonal.IntegrationTest; -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; +import br.com.fullcycle.IntegrationTest; +import br.com.fullcycle.application.customer.CreateCustomerUseCase; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.customer.CustomerRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java b/infrastructure/src/test/java/br/com/fullcycle/application/usecases/CreateEventUseCaseIT.java similarity index 84% rename from src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java rename to infrastructure/src/test/java/br/com/fullcycle/application/usecases/CreateEventUseCaseIT.java index 2310d6d3..5c92f960 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/application/usecases/CreateEventUseCaseIT.java +++ b/infrastructure/src/test/java/br/com/fullcycle/application/usecases/CreateEventUseCaseIT.java @@ -1,11 +1,12 @@ -package br.com.fullcycle.hexagonal.application.usecases; +package br.com.fullcycle.application.usecases; -import br.com.fullcycle.hexagonal.IntegrationTest; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.domain.partner.PartnerId; -import br.com.fullcycle.hexagonal.application.exceptions.ValidationException; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; +import br.com.fullcycle.IntegrationTest; +import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerId; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.partner.PartnerRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/MainTests.java similarity index 83% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java rename to infrastructure/src/test/java/br/com/fullcycle/infrastructure/MainTests.java index 1febd88c..dba72f63 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/MainTests.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/MainTests.java @@ -1,4 +1,4 @@ -package br.com.fullcycle.hexagonal.infrastructure; +package br.com.fullcycle.infrastructure; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java similarity index 94% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java rename to infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java index 5df0534a..fdb82774 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/CustomerControllerTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; +package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.usecases.customer.CreateCustomerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.customer.GetCustomerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewCustomerDTO; -import br.com.fullcycle.hexagonal.infrastructure.jpa.repositories.CustomerJpaRepository; +import br.com.fullcycle.application.customer.CreateCustomerUseCase; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewCustomerDTO; +import br.com.fullcycle.infrastructure.jpa.repositories.CustomerJpaRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java similarity index 85% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java rename to infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java index 02e4d02d..2e0f8ea2 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/EventControllerTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java @@ -1,14 +1,14 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; - -import br.com.fullcycle.hexagonal.application.domain.customer.Customer; -import br.com.fullcycle.hexagonal.application.domain.event.EventId; -import br.com.fullcycle.hexagonal.application.domain.partner.Partner; -import br.com.fullcycle.hexagonal.application.repositories.CustomerRepository; -import br.com.fullcycle.hexagonal.application.repositories.EventRepository; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.application.usecases.event.CreateEventUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewEventDTO; -import br.com.fullcycle.hexagonal.infrastructure.dtos.SubscribeDTO; +package br.com.fullcycle.infrastructure.rest; + +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.infrastructure.dtos.NewEventDTO; +import br.com.fullcycle.infrastructure.dtos.SubscribeDTO; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/PartnerControllerTest.java similarity index 94% rename from src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java rename to infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/PartnerControllerTest.java index a90a6cef..87b0f784 100644 --- a/src/test/java/br/com/fullcycle/hexagonal/infrastructure/rest/PartnerControllerTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/PartnerControllerTest.java @@ -1,9 +1,9 @@ -package br.com.fullcycle.hexagonal.infrastructure.rest; +package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.hexagonal.application.repositories.PartnerRepository; -import br.com.fullcycle.hexagonal.application.usecases.partner.CreatePartnerUseCase; -import br.com.fullcycle.hexagonal.application.usecases.partner.GetPartnerByIdUseCase; -import br.com.fullcycle.hexagonal.infrastructure.dtos.NewPartnerDTO; +import br.com.fullcycle.domain.partner.PartnerRepository; +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.infrastructure.dtos.NewPartnerDTO; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; From c3e4ea56736aa6a9c1fe89a3292232a572a075b8 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 3 Sep 2023 22:16:10 -0300 Subject: [PATCH 18/22] 03-adicionado-suporte-ao-padrao-presenters --- .../fullcycle/application/NullaryUseCase.java | 8 ++++++ .../com/fullcycle/application/Presenter.java | 8 ++++++ .../br/com/fullcycle/application/UseCase.java | 8 ++++++ .../rest/CustomerController.java | 24 ++++++++++++---- .../GetCustomerByIdResponseEntity.java | 28 +++++++++++++++++++ .../PublicGetCustomerByIdString.java | 27 ++++++++++++++++++ .../rest/CustomerControllerTest.java | 25 +++++++++++++++++ 7 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 application/src/main/java/br/com/fullcycle/application/Presenter.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetCustomerByIdResponseEntity.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetCustomerByIdString.java diff --git a/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java b/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java index 2261aa1f..719299b3 100644 --- a/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/NullaryUseCase.java @@ -6,4 +6,12 @@ public abstract class NullaryUseCase { // 2. O caso de uso implementa o padrão Command public abstract OUTPUT execute(); + + public T execute(Presenter presenter) { + try { + return presenter.present(execute()); + } catch (Throwable t) { + return presenter.present(t); + } + } } diff --git a/application/src/main/java/br/com/fullcycle/application/Presenter.java b/application/src/main/java/br/com/fullcycle/application/Presenter.java new file mode 100644 index 00000000..f4066959 --- /dev/null +++ b/application/src/main/java/br/com/fullcycle/application/Presenter.java @@ -0,0 +1,8 @@ +package br.com.fullcycle.application; + +public interface Presenter { + + OUT present(IN input); + + OUT present(Throwable error); +} diff --git a/application/src/main/java/br/com/fullcycle/application/UseCase.java b/application/src/main/java/br/com/fullcycle/application/UseCase.java index 584f9649..bbb6eeda 100644 --- a/application/src/main/java/br/com/fullcycle/application/UseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/UseCase.java @@ -6,4 +6,12 @@ public abstract class UseCase { // 2. O caso de uso implementa o padrão Command public abstract OUTPUT execute(INPUT input); + + public T execute(INPUT input, Presenter presenter) { + try { + return presenter.present(execute(input)); + } catch (Throwable t) { + return presenter.present(t); + } + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java index e69d369d..2e6dac6e 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/CustomerController.java @@ -1,14 +1,16 @@ package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.application.Presenter; import br.com.fullcycle.application.customer.CreateCustomerUseCase; import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.infrastructure.dtos.NewCustomerDTO; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; import java.util.Objects; +import java.util.Optional; // Adapter @RestController @@ -17,11 +19,17 @@ public class CustomerController { private final CreateCustomerUseCase createCustomerUseCase; private final GetCustomerByIdUseCase getCustomerByIdUseCase; + private final Presenter, Object> publicGetCustomerPresenter; + private final Presenter, Object> privateGetCustomerPresenter; public CustomerController( final CreateCustomerUseCase createCustomerUseCase, - final GetCustomerByIdUseCase getCustomerByIdUseCase + final GetCustomerByIdUseCase getCustomerByIdUseCase, + final Presenter, Object> privateGetCustomer, + final Presenter, Object> publicGetCustomer ) { + this.publicGetCustomerPresenter = publicGetCustomer; + this.privateGetCustomerPresenter = privateGetCustomer; this.createCustomerUseCase = Objects.requireNonNull(createCustomerUseCase); this.getCustomerByIdUseCase = Objects.requireNonNull(getCustomerByIdUseCase); } @@ -39,9 +47,13 @@ public ResponseEntity create(@RequestBody NewCustomerDTO dto) { } @GetMapping("/{id}") - public ResponseEntity get(@PathVariable String id) { - return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id)) - .map(ResponseEntity::ok) - .orElseGet(ResponseEntity.notFound()::build); + public Object get(@PathVariable String id, @RequestHeader(name = "X-Public", required = false) String xPublic) { + Presenter, Object> presenter = privateGetCustomerPresenter; + + if (xPublic != null) { + presenter = publicGetCustomerPresenter; + } + + return getCustomerByIdUseCase.execute(new GetCustomerByIdUseCase.Input(id), presenter); } } \ No newline at end of file diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetCustomerByIdResponseEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetCustomerByIdResponseEntity.java new file mode 100644 index 00000000..4a14ee7f --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetCustomerByIdResponseEntity.java @@ -0,0 +1,28 @@ +package br.com.fullcycle.infrastructure.rest.presenters; + +import br.com.fullcycle.application.Presenter; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component("privateGetCustomer") +public class GetCustomerByIdResponseEntity implements Presenter, Object> { + + private static final Logger LOG = LoggerFactory.getLogger(GetCustomerByIdResponseEntity.class); + + @Override + public ResponseEntity present(final Optional output) { + return output.map(ResponseEntity::ok) + .orElseGet(ResponseEntity.notFound()::build); + } + + @Override + public ResponseEntity present(Throwable error) { + LOG.error("An error was observer at GetCustomerByIdUseCase", error); + return ResponseEntity.notFound().build(); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetCustomerByIdString.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetCustomerByIdString.java new file mode 100644 index 00000000..5429b7b5 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetCustomerByIdString.java @@ -0,0 +1,27 @@ +package br.com.fullcycle.infrastructure.rest.presenters; + +import br.com.fullcycle.application.Presenter; +import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component("publicGetCustomer") +public class PublicGetCustomerByIdString implements Presenter, Object> { + + private static final Logger LOG = LoggerFactory.getLogger(PublicGetCustomerByIdString.class); + + @Override + public String present(final Optional output) { + return output.map(o -> o.id()) + .orElseGet(() -> "not found"); + } + + @Override + public String present(Throwable error) { + LOG.error("An error was observer at GetCustomerByIdUseCase", error); + return "not found"; + } +} diff --git a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java index fdb82774..020d915d 100644 --- a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/CustomerControllerTest.java @@ -144,4 +144,29 @@ public void testGet() throws Exception { Assertions.assertEquals(customer.cpf(), actualResponse.cpf()); Assertions.assertEquals(customer.email(), actualResponse.email()); } + + @Test + @DisplayName("Deve obter um cliente por id com X-Public") + public void testGetPublic() throws Exception { + + var customer = new NewCustomerDTO("123.456.789-01", "john.doe@gmail.com", "John Doe"); + + final var createResult = this.mvc.perform( + MockMvcRequestBuilders.post("/customers") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(customer)) + ) + .andReturn().getResponse().getContentAsByteArray(); + + var customerId = mapper.readValue(createResult, CreateCustomerUseCase.Output.class).id(); + + final var actualResponse = this.mvc.perform( + MockMvcRequestBuilders.get("/customers/{id}", customerId) + .header("X-Public", "true") + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andReturn().getResponse().getContentAsByteArray(); + + Assertions.assertEquals(customerId, new String(actualResponse)); + } } From 9705a3ae8399eb48c9d2527d999e0921421476a9 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Mon, 4 Sep 2023 09:53:53 -0300 Subject: [PATCH 19/22] 04-separando-frameworks-and-drivers-de-interface-adapters --- .../configurations/ControllerConfig.java | 19 +++++ .../configurations/RouterConfig.java | 21 ++++++ .../infrastructure/http/HttpRouter.java | 69 ++++++++++++++++++ .../infrastructure/http/SpringHttpRouter.java | 73 +++++++++++++++++++ .../rest/PartnerController.java | 4 +- .../rest/PartnerFnController.java | 53 ++++++++++++++ 6 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/ControllerConfig.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/RouterConfig.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/HttpRouter.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/SpringHttpRouter.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerFnController.java diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/ControllerConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/ControllerConfig.java new file mode 100644 index 00000000..330dcb2f --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/ControllerConfig.java @@ -0,0 +1,19 @@ +package br.com.fullcycle.infrastructure.configurations; + +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.infrastructure.rest.PartnerFnController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ControllerConfig { + + @Bean + public PartnerFnController partnerFnController( + final CreatePartnerUseCase createPartnerUseCase, + final GetPartnerByIdUseCase getPartnerByIdUseCase + ) { + return new PartnerFnController(createPartnerUseCase, getPartnerByIdUseCase); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/RouterConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/RouterConfig.java new file mode 100644 index 00000000..6c0740de --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/RouterConfig.java @@ -0,0 +1,21 @@ +package br.com.fullcycle.infrastructure.configurations; + +import br.com.fullcycle.infrastructure.http.SpringHttpRouter; +import br.com.fullcycle.infrastructure.rest.PartnerFnController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.function.RouterFunction; + +// Frameworks and Drivers +@Configuration +public class RouterConfig { + + @Bean + public RouterFunction routes( + final PartnerFnController partnerFnController + ) { + final var router = new SpringHttpRouter(); + partnerFnController.bind(router); + return router.router().build(); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/HttpRouter.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/HttpRouter.java new file mode 100644 index 00000000..e27950ef --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/HttpRouter.java @@ -0,0 +1,69 @@ +package br.com.fullcycle.infrastructure.http; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public interface HttpRouter { + + HttpRouter POST(String pattern, HttpHandler handler); + + HttpRouter GET(String pattern, HttpHandler handler); + + interface HttpHandler { + HttpResponse handle(HttpRequest req); + } + + interface HttpRequest { + + T body(Class tClass); + + String pathParam(String name); + + Optional queryParam(String name); + } + + record HttpResponse(int statusCode, Map headers, T body) { + + public static HttpResponse.Builder created(final URI uri) { + return new Builder(201).location(uri); + } + + public static HttpResponse.Builder notFound() { + return new Builder(404); + } + + public static HttpResponse.Builder unprocessableEntity() { + return new Builder(422); + } + + public static HttpResponse ok(final T body) { + return new HttpResponse<>(200, Map.of(), body); + } + + public static class Builder { + + private final int statusCode; + private final Map headers; + + public Builder(int statusCode) { + this.statusCode = statusCode; + this.headers = new HashMap<>(2); + } + + public HttpResponse build() { + return new HttpResponse<>(statusCode, headers, null); + } + + public HttpResponse body(T body) { + return new HttpResponse<>(statusCode, headers, body); + } + + public Builder location(URI uri) { + this.headers.put("Location", uri.toASCIIString()); + return this; + } + } + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/SpringHttpRouter.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/SpringHttpRouter.java new file mode 100644 index 00000000..2918bf8e --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/http/SpringHttpRouter.java @@ -0,0 +1,73 @@ +package br.com.fullcycle.infrastructure.http; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.RouterFunctions; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +import java.util.Optional; + +public class SpringHttpRouter implements HttpRouter { + + private static final Logger LOG = LoggerFactory.getLogger(SpringHttpRouter.class); + + private final RouterFunctions.Builder router; + + public SpringHttpRouter() { + this.router = RouterFunctions.route(); + } + + public RouterFunctions.Builder router() { + return router; + } + + @Override + public HttpRouter POST(String pattern, HttpHandler handler) { + this.router.POST(pattern, wrapHandler(pattern, handler)); + return this; + } + + @Override + public HttpRouter GET(String pattern, HttpHandler handler) { + this.router.GET(pattern, wrapHandler(pattern, handler)); + return this; + } + + private static HandlerFunction wrapHandler(String pattern, HttpHandler handler) { + return req -> { + try { + var res = handler.handle(new SpringHttpRequest(req)); + return ServerResponse.status(res.statusCode()) + .headers(headers -> res.headers().forEach(headers::add)) + .body(res.body()); + } catch (final Throwable t) { + LOG.error("Unexpected error was observed at %s".formatted(pattern), t); + return ServerResponse.status(500).body("Unexpected error was observed."); + } + }; + } + + public record SpringHttpRequest(ServerRequest request) implements HttpRequest { + + @Override + public T body(final Class tClass) { + try { + return request.body(tClass); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Override + public String pathParam(String name) { + return request.pathVariable(name); + } + + @Override + public Optional queryParam(String name) { + return request.param(name); + } + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java index 8698255e..5224b5ee 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerController.java @@ -11,8 +11,8 @@ import java.util.Objects; // Adapter -@RestController -@RequestMapping(value = "partners") +//@RestController +//@RequestMapping(value = "partners") public class PartnerController { private final CreatePartnerUseCase createPartnerUseCase; diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerFnController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerFnController.java new file mode 100644 index 00000000..6d63d81d --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/PartnerFnController.java @@ -0,0 +1,53 @@ +package br.com.fullcycle.infrastructure.rest; + +import br.com.fullcycle.application.partner.CreatePartnerUseCase; +import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.infrastructure.dtos.NewPartnerDTO; +import br.com.fullcycle.infrastructure.http.HttpRouter; +import br.com.fullcycle.infrastructure.http.HttpRouter.HttpRequest; +import br.com.fullcycle.infrastructure.http.HttpRouter.HttpResponse; + +import java.net.URI; +import java.util.Objects; + +// Adapter +public class PartnerFnController { + + private final CreatePartnerUseCase createPartnerUseCase; + private final GetPartnerByIdUseCase getPartnerByIdUseCase; + + public PartnerFnController( + final CreatePartnerUseCase createPartnerUseCase, + final GetPartnerByIdUseCase getPartnerByIdUseCase + ) { + this.createPartnerUseCase = Objects.requireNonNull(createPartnerUseCase); + this.getPartnerByIdUseCase = Objects.requireNonNull(getPartnerByIdUseCase); + } + + public HttpRouter bind(final HttpRouter router) { + router.GET("/partners/{id}", this::get); + router.POST("/partners", this::create); + return router; + } + + private HttpResponse create(final HttpRequest req) { + try { + final var dto = req.body(NewPartnerDTO.class); + + final var output = + createPartnerUseCase.execute(new CreatePartnerUseCase.Input(dto.cnpj(), dto.email(), dto.name())); + + return HttpResponse.created(URI.create("/partners/" + output.id())).body(output); + } catch (ValidationException ex) { + return HttpResponse.unprocessableEntity().body(ex.getMessage()); + } + } + + private HttpResponse get(final HttpRequest req) { + final String id = req.pathParam("id"); + return getPartnerByIdUseCase.execute(new GetPartnerByIdUseCase.Input(id)) + .map(HttpResponse::ok) + .orElseGet(HttpResponse.notFound()::build); + } +} \ No newline at end of file From 547f81d47e2334d54123c74f715822a56639a074 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Mon, 4 Sep 2023 10:26:44 -0300 Subject: [PATCH 20/22] 05-aplicando-eventos-de-dominio-para-desacoplar-agregados --- .../SubscribeCustomerToEventUseCase.java | 14 ++-- .../SubscribeCustomerToEventUseCaseTest.java | 31 +++----- .../br/com/fullcycle/domain/DomainEvent.java | 12 +++ .../br/com/fullcycle/domain/event/Event.java | 22 ++++-- .../fullcycle/domain/event/EventTicket.java | 25 ++++-- .../fullcycle/domain/event/EventTicketId.java | 26 +++++++ .../domain/event/EventTicketReserved.java | 21 +++++ .../com/fullcycle/domain/event/EventTest.java | 12 +-- .../configurations/UseCaseConfig.java | 10 +-- .../jpa/entities/EventTicketEntity.java | 25 ++++-- .../jpa/entities/OutboxEntity.java | 78 +++++++++++++++++++ .../jpa/repositories/OutboxJpaRepository.java | 12 +++ .../repositories/EventDatabaseRepository.java | 44 +++++++++-- .../infrastructure/rest/EventController.java | 6 +- 14 files changed, 269 insertions(+), 69 deletions(-) create mode 100644 domain/src/main/java/br/com/fullcycle/domain/DomainEvent.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/EventTicketId.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/EventTicketReserved.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java diff --git a/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java index 25b0e7d7..9abbcbcd 100644 --- a/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCase.java @@ -5,7 +5,7 @@ import br.com.fullcycle.domain.customer.CustomerRepository; import br.com.fullcycle.domain.event.EventId; import br.com.fullcycle.domain.event.EventRepository; -import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.EventTicket; import br.com.fullcycle.domain.event.ticket.TicketRepository; import br.com.fullcycle.domain.exceptions.ValidationException; @@ -16,16 +16,13 @@ public class SubscribeCustomerToEventUseCase extends UseCase new ValidationException("Event not found")); - final Ticket ticket = anEvent.reserveTicket(aCustomer.customerId()); + final EventTicket ticket = anEvent.reserveTicket(aCustomer.customerId()); - ticketRepository.create(ticket); eventRepository.update(anEvent); - return new Output(anEvent.eventId().value(), ticket.ticketId().value(), ticket.status().name(), ticket.reservedAt()); + return new Output(anEvent.eventId().value(), ticket.eventTicketId().value(), Instant.now()); } public record Input(String customerId, String eventId) { } - public record Output(String eventId, String ticketId, String ticketStatus, Instant reservationDate) { + public record Output(String eventId, String eventTicketId, Instant reservationDate) { } } diff --git a/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java index 05ee8144..2d2afc56 100644 --- a/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java @@ -1,15 +1,14 @@ package br.com.fullcycle.application.event; +import br.com.fullcycle.application.repository.InMemoryCustomerRepository; +import br.com.fullcycle.application.repository.InMemoryEventRepository; +import br.com.fullcycle.application.repository.InMemoryTicketRepository; import br.com.fullcycle.domain.customer.Customer; import br.com.fullcycle.domain.customer.CustomerId; import br.com.fullcycle.domain.event.Event; import br.com.fullcycle.domain.event.EventId; -import br.com.fullcycle.domain.event.ticket.TicketStatus; -import br.com.fullcycle.domain.partner.Partner; import br.com.fullcycle.domain.exceptions.ValidationException; -import br.com.fullcycle.application.repository.InMemoryCustomerRepository; -import br.com.fullcycle.application.repository.InMemoryEventRepository; -import br.com.fullcycle.application.repository.InMemoryTicketRepository; +import br.com.fullcycle.domain.partner.Partner; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -34,20 +33,17 @@ public void testReserveTicket() throws Exception { final var customerRepository = new InMemoryCustomerRepository(); final var eventRepository = new InMemoryEventRepository(); - final var ticketRepository = new InMemoryTicketRepository(); customerRepository.create(aCustomer); eventRepository.create(anEvent); // when - final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); final var output = useCase.execute(subscribeInput); // then Assertions.assertEquals(eventID, output.eventId()); - Assertions.assertNotNull(output.ticketId()); Assertions.assertNotNull(output.reservationDate()); - Assertions.assertEquals(TicketStatus.PENDING.name(), output.ticketStatus()); final var actualEvent = eventRepository.eventOfId(anEvent.eventId()); Assertions.assertEquals(expectedTicketsSize, actualEvent.get().allTickets().size()); @@ -70,12 +66,11 @@ public void testReserveTicketWithoutCustomer() throws Exception { final var customerRepository = new InMemoryCustomerRepository(); final var eventRepository = new InMemoryEventRepository(); - final var ticketRepository = new InMemoryTicketRepository(); eventRepository.create(anEvent); // when - final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -98,12 +93,11 @@ public void testReserveTicketWithoutEvent() throws Exception { final var customerRepository = new InMemoryCustomerRepository(); final var eventRepository = new InMemoryEventRepository(); - final var ticketRepository = new InMemoryTicketRepository(); customerRepository.create(aCustomer); // when - final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -128,16 +122,14 @@ public void testReserveTicketMoreThanOnce() throws Exception { final var customerRepository = new InMemoryCustomerRepository(); final var eventRepository = new InMemoryEventRepository(); - final var ticketRepository = new InMemoryTicketRepository(); - final var ticket = anEvent.reserveTicket(aCustomer.customerId()); + anEvent.reserveTicket(aCustomer.customerId()); customerRepository.create(aCustomer); eventRepository.create(anEvent); - ticketRepository.create(ticket); // when - final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then @@ -165,15 +157,14 @@ public void testReserveTicketWithoutSlots() throws Exception { final var eventRepository = new InMemoryEventRepository(); final var ticketRepository = new InMemoryTicketRepository(); - final var ticket = anEvent.reserveTicket(aCustomer2.customerId()); + anEvent.reserveTicket(aCustomer2.customerId()); customerRepository.create(aCustomer); customerRepository.create(aCustomer2); eventRepository.create(anEvent); - ticketRepository.create(ticket); // when - final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); // then diff --git a/domain/src/main/java/br/com/fullcycle/domain/DomainEvent.java b/domain/src/main/java/br/com/fullcycle/domain/DomainEvent.java new file mode 100644 index 00000000..7a664b73 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/DomainEvent.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.domain; + +import java.time.Instant; + +public interface DomainEvent { + + String domainEventId(); + + String type(); + + Instant occurredOn(); +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/Event.java b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java index 09b4779b..7abf3639 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/Event.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java @@ -1,7 +1,7 @@ package br.com.fullcycle.domain.event; +import br.com.fullcycle.domain.DomainEvent; import br.com.fullcycle.domain.customer.CustomerId; -import br.com.fullcycle.domain.event.ticket.Ticket; import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.domain.partner.Partner; import br.com.fullcycle.domain.partner.PartnerId; @@ -19,11 +19,13 @@ public class Event { private static final int ONE = 1; private final EventId eventId; + private final Set tickets; + private final Set domainEvents; + private Name name; private LocalDate date; private int totalSpots; private PartnerId partnerId; - private Set tickets; public Event( final EventId eventId, @@ -47,6 +49,7 @@ private Event(final EventId eventId, final Set tickets) { this.eventId = eventId; this.tickets = tickets != null ? tickets : new HashSet<>(0); + this.domainEvents = new HashSet<>(2); } public static Event newEvent(final String name, final String date, final Integer totalSpots, final Partner partner) { @@ -64,7 +67,7 @@ public static Event restore( return new Event(EventId.with(id), name, date, totalSpots, PartnerId.with(partnerId), tickets); } - public Ticket reserveTicket(final CustomerId aCustomerId) { + public EventTicket reserveTicket(final CustomerId aCustomerId) { this.allTickets().stream() .filter(it -> Objects.equals(it.customerId(), aCustomerId)) .findFirst() @@ -76,12 +79,13 @@ public Ticket reserveTicket(final CustomerId aCustomerId) { throw new ValidationException("Event sold out"); } - final var newTicket = - Ticket.newTicket(aCustomerId, eventId()); + final var aTicket = + EventTicket.newTicket(eventId(), aCustomerId, allTickets().size() + 1); - this.tickets.add(new EventTicket(newTicket.ticketId(), eventId(), aCustomerId, allTickets().size() + 1)); + this.tickets.add(aTicket); + this.domainEvents.add(new EventTicketReserved(aTicket.eventTicketId(), eventId(), aCustomerId)); - return newTicket; + return aTicket; } public EventId eventId() { @@ -108,6 +112,10 @@ public Set allTickets() { return Collections.unmodifiableSet(tickets); } + public Set allDomainEvents() { + return Collections.unmodifiableSet(domainEvents); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java index 13889013..24847c90 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicket.java @@ -6,14 +6,15 @@ public class EventTicket { - private final TicketId ticketId; + private final EventTicketId eventTicketId; private final EventId eventId; private final CustomerId customerId; + private TicketId ticketId; private int ordering; - public EventTicket(final TicketId ticketId, final EventId eventId, final CustomerId customerId, final Integer ordering) { - if (ticketId == null) { - throw new ValidationException("Invalid ticketId for EventTicket"); + public EventTicket(final EventTicketId eventTicketId, final EventId eventId, final CustomerId customerId, final TicketId ticketId, final Integer ordering) { + if (eventTicketId == null) { + throw new ValidationException("Invalid eventTicketId for EventTicket"); } if (eventId == null) { @@ -24,12 +25,26 @@ public EventTicket(final TicketId ticketId, final EventId eventId, final Custome throw new ValidationException("Invalid customerId for EventTicket"); } - this.ticketId = ticketId; + this.eventTicketId = eventTicketId; this.eventId = eventId; this.customerId = customerId; + this.ticketId = ticketId; this.setOrdering(ordering); } + public static EventTicket newTicket(final EventId eventId, final CustomerId customerId, final int ordering) { + return new EventTicket(EventTicketId.unique(), eventId, customerId, null, ordering); + } + + public EventTicket associateTicket(final TicketId aTicket) { + this.ticketId = aTicket; + return this; + } + + public EventTicketId eventTicketId() { + return eventTicketId; + } + public TicketId ticketId() { return ticketId; } diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketId.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketId.java new file mode 100644 index 00000000..8c769413 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketId.java @@ -0,0 +1,26 @@ +package br.com.fullcycle.domain.event; + +import br.com.fullcycle.domain.exceptions.ValidationException; + +import java.util.UUID; + +public record EventTicketId(String value) { + + public EventTicketId { + if (value == null) { + throw new ValidationException("Invalid value for EventTicketId"); + } + } + + public static EventTicketId unique() { + return new EventTicketId(UUID.randomUUID().toString()); + } + + public static EventTicketId with(final String value) { + try { + return new EventTicketId(UUID.fromString(value).toString()); + } catch (IllegalArgumentException ex) { + throw new ValidationException("Invalid value for EventTicketId"); + } + } +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketReserved.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketReserved.java new file mode 100644 index 00000000..77d66aa4 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventTicketReserved.java @@ -0,0 +1,21 @@ +package br.com.fullcycle.domain.event; + +import br.com.fullcycle.domain.DomainEvent; +import br.com.fullcycle.domain.customer.CustomerId; + +import java.time.Instant; +import java.util.UUID; + +public record EventTicketReserved( + String domainEventId, + String type, + String eventTicketId, + String eventId, + String customerId, + Instant occurredOn +) implements DomainEvent { + + public EventTicketReserved(EventTicketId eventTicketId, EventId eventId, CustomerId customerId) { + this(UUID.randomUUID().toString(), "event-ticket.reserved", eventTicketId.value(), eventId.value(), customerId.value(), Instant.now()); + } +} diff --git a/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java index 21e76628..cf5d23f4 100644 --- a/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java @@ -1,7 +1,6 @@ package br.com.fullcycle.domain.event; import br.com.fullcycle.domain.customer.Customer; -import br.com.fullcycle.domain.event.ticket.TicketStatus; import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.domain.partner.Partner; import org.junit.jupiter.api.Assertions; @@ -92,7 +91,7 @@ public void testReserveTicket() throws Exception { final var expectedPartnerId = aPartner.partnerId().value(); final var expectedTickets = 1; final var expectedTicketOrder = 1; - final var expectedTicketStatus = TicketStatus.PENDING; + final var expectedDomainEvent = "event-ticket.reserved"; final var actualEvent = Event.newEvent(expectedName, expectedDate, expectedTotalSpots, aPartner); @@ -102,12 +101,10 @@ public void testReserveTicket() throws Exception { final var actualTicket = actualEvent.reserveTicket(aCustomer.customerId()); // then - Assertions.assertNotNull(actualTicket.ticketId()); - Assertions.assertNotNull(actualTicket.reservedAt()); - Assertions.assertNull(actualTicket.paidAt()); + Assertions.assertNotNull(actualTicket.eventTicketId()); + Assertions.assertNull(actualTicket.ticketId()); Assertions.assertEquals(expectedEventId, actualTicket.eventId()); Assertions.assertEquals(expectedCustomerId, actualTicket.customerId()); - Assertions.assertEquals(expectedTicketStatus, actualTicket.status()); Assertions.assertEquals(expectedDate, actualEvent.date().format(DateTimeFormatter.ISO_LOCAL_DATE)); Assertions.assertEquals(expectedName, actualEvent.name().value()); @@ -120,6 +117,9 @@ public void testReserveTicket() throws Exception { Assertions.assertEquals(expectedEventId, actualEventTicket.eventId()); Assertions.assertEquals(expectedCustomerId, actualEventTicket.customerId()); Assertions.assertEquals(actualTicket.ticketId(), actualEventTicket.ticketId()); + + final var actualDomainEvents = actualEvent.allDomainEvents().iterator().next(); + Assertions.assertEquals(expectedDomainEvent, actualDomainEvents.type()); } @Test diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java index 5b6e83ad..9bf2540d 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java @@ -1,15 +1,15 @@ package br.com.fullcycle.infrastructure.configurations; -import br.com.fullcycle.domain.customer.CustomerRepository; -import br.com.fullcycle.domain.event.EventRepository; -import br.com.fullcycle.domain.partner.PartnerRepository; -import br.com.fullcycle.domain.event.ticket.TicketRepository; import br.com.fullcycle.application.customer.CreateCustomerUseCase; import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; import br.com.fullcycle.application.event.CreateEventUseCase; import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.application.partner.CreatePartnerUseCase; import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.domain.partner.PartnerRepository; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -62,6 +62,6 @@ public GetPartnerByIdUseCase getPartnerByIdUseCase() { @Bean public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { - return new SubscribeCustomerToEventUseCase(customerRepository, eventRepository, ticketRepository); + return new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java index a953062f..22028f4c 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventTicketEntity.java @@ -3,6 +3,7 @@ import br.com.fullcycle.domain.customer.CustomerId; import br.com.fullcycle.domain.event.EventId; import br.com.fullcycle.domain.event.EventTicket; +import br.com.fullcycle.domain.event.EventTicketId; import br.com.fullcycle.domain.event.ticket.TicketId; import jakarta.persistence.*; @@ -14,6 +15,8 @@ public class EventTicketEntity { @Id + private UUID eventTicketId; + private UUID ticketId; private UUID customerId; @@ -27,11 +30,13 @@ public EventTicketEntity() { } public EventTicketEntity( - final UUID ticketId, + final UUID eventTicketId, final UUID customerId, final int ordering, + final UUID ticketId, final EventEntity event ) { + this.eventTicketId = eventTicketId; this.ticketId = ticketId; this.customerId = customerId; this.event = event; @@ -40,22 +45,32 @@ public EventTicketEntity( public static EventTicketEntity of(final EventEntity event, final EventTicket ev) { return new EventTicketEntity( - UUID.fromString(ev.ticketId().value()), + UUID.fromString(ev.eventTicketId().value()), UUID.fromString(ev.customerId().value()), ev.ordering(), + ev.ticketId() != null ? UUID.fromString(ev.ticketId().value()) : null, event ); } public EventTicket toEventTicket() { return new EventTicket( - TicketId.with(this.ticketId.toString()), + EventTicketId.with(eventTicketId.toString()), EventId.with(this.event.id().toString()), CustomerId.with(this.customerId.toString()), + this.ticketId != null ? TicketId.with(this.ticketId.toString()) : null, this.ordering ); } + public UUID eventTicketId() { + return eventTicketId; + } + + public void setEventTicketId(UUID eventTicketId) { + this.eventTicketId = eventTicketId; + } + public UUID ticketId() { return ticketId; } @@ -93,11 +108,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EventTicketEntity that = (EventTicketEntity) o; - return ordering == that.ordering && Objects.equals(ticketId, that.ticketId) && Objects.equals(customerId, that.customerId) && Objects.equals(event, that.event); + return Objects.equals(eventTicketId, that.eventTicketId); } @Override public int hashCode() { - return Objects.hash(ticketId, customerId, ordering, event); + return Objects.hash(eventTicketId); } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java new file mode 100644 index 00000000..a9786a66 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java @@ -0,0 +1,78 @@ +package br.com.fullcycle.infrastructure.jpa.entities; + +import br.com.fullcycle.domain.DomainEvent; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerId; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import java.util.Objects; +import java.util.UUID; +import java.util.function.Function; + +@Entity(name = "Outbox") +@Table(name = "outbox") +public class OutboxEntity { + + @Id + private UUID id; + + private String content; + + private boolean published; + + public OutboxEntity() { + } + + public OutboxEntity(UUID id, String content, boolean published) { + this.id = id; + this.content = content; + this.published = published; + } + + public static OutboxEntity of(final DomainEvent domainEvent, final Function toJson) { + return new OutboxEntity( + UUID.fromString(domainEvent.domainEventId()), + toJson.apply(domainEvent), + false + ); + } + + public UUID id() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String content() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public boolean published() { + return published; + } + + public void setPublished(boolean published) { + this.published = published; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OutboxEntity that = (OutboxEntity) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java new file mode 100644 index 00000000..18eeb217 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java @@ -0,0 +1,12 @@ +package br.com.fullcycle.infrastructure.jpa.repositories; + +import br.com.fullcycle.infrastructure.jpa.entities.OutboxEntity; +import org.springframework.data.repository.CrudRepository; + +import java.util.List; +import java.util.UUID; + +public interface OutboxJpaRepository extends CrudRepository { + + List findAllByPublishedFalse(); +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java index 06fc162b..8cc8d477 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/EventDatabaseRepository.java @@ -1,10 +1,15 @@ package br.com.fullcycle.infrastructure.repositories; +import br.com.fullcycle.domain.DomainEvent; import br.com.fullcycle.domain.event.Event; import br.com.fullcycle.domain.event.EventId; import br.com.fullcycle.domain.event.EventRepository; import br.com.fullcycle.infrastructure.jpa.entities.EventEntity; +import br.com.fullcycle.infrastructure.jpa.entities.OutboxEntity; import br.com.fullcycle.infrastructure.jpa.repositories.EventJpaRepository; +import br.com.fullcycle.infrastructure.jpa.repositories.OutboxJpaRepository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -17,9 +22,17 @@ public class EventDatabaseRepository implements EventRepository { private final EventJpaRepository eventJpaRepository; + private final OutboxJpaRepository outboxJpaRepository; + private final ObjectMapper mapper; - public EventDatabaseRepository(final EventJpaRepository EventJpaRepository) { + public EventDatabaseRepository( + final EventJpaRepository EventJpaRepository, + final OutboxJpaRepository outboxJpaRepository, + final ObjectMapper mapper + ) { this.eventJpaRepository = Objects.requireNonNull(EventJpaRepository); + this.outboxJpaRepository = outboxJpaRepository; + this.mapper = mapper; } @Override @@ -31,20 +44,37 @@ public Optional eventOfId(final EventId anId) { @Override @Transactional - public Event create(final Event Event) { - return this.eventJpaRepository.save(EventEntity.of(Event)) - .toEvent(); + public Event create(final Event event) { + return save(event); } @Override @Transactional - public Event update(Event Event) { - return this.eventJpaRepository.save(EventEntity.of(Event)) - .toEvent(); + public Event update(Event event) { + return save(event); } @Override public void deleteAll() { this.eventJpaRepository.deleteAll(); } + + private Event save(Event event) { + this.outboxJpaRepository.saveAll( + event.allDomainEvents().stream() + .map(it -> OutboxEntity.of(it, this::toJson)) + .toList() + ); + + return this.eventJpaRepository.save(EventEntity.of(event)) + .toEvent(); + } + + private String toJson(DomainEvent domainEvent) { + try { + return this.mapper.writeValueAsString(domainEvent); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java index cf6a8761..32d3ef2e 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java @@ -1,20 +1,17 @@ package br.com.fullcycle.infrastructure.rest; -import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.application.event.CreateEventUseCase; import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; +import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.infrastructure.dtos.SubscribeDTO; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.net.URI; import java.util.Objects; -import static org.springframework.http.HttpStatus.CREATED; - // Adapter @RestController @RequestMapping(value = "events") @@ -44,7 +41,6 @@ public ResponseEntity create(@RequestBody NewEventDTO dto) { } } - @Transactional @PostMapping(value = "/{id}/subscribe") public ResponseEntity subscribe(@PathVariable String id, @RequestBody SubscribeDTO dto) { try { From 7b317f7312b6ff29e5c6005fc53c06733539b869 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Mon, 4 Sep 2023 12:41:46 -0300 Subject: [PATCH 21/22] 06-event-driven-architecture-para-finalizar-o-fluxo --- .../CreateTicketForCustomerUseCase.java | 35 +++++++++++++++ .../fullcycle/domain/event/ticket/Ticket.java | 18 ++++++++ .../domain/event/ticket/TicketCreated.java | 24 +++++++++++ .../br/com/fullcycle/infrastructure/Main.java | 2 + .../configurations/OutboxConfig.java | 19 ++++++++ .../configurations/UseCaseConfig.java | 6 +++ .../gateways/ConsumerQueueGateway.java | 43 +++++++++++++++++++ .../infrastructure/gateways/QueueGateway.java | 5 +++ .../infrastructure/job/OutboxRelay.java | 29 +++++++++++++ .../jpa/entities/OutboxEntity.java | 9 +++- .../jpa/repositories/OutboxJpaRepository.java | 10 ++++- .../TicketDatabaseRepository.java | 41 +++++++++++++++--- 12 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 application/src/main/java/br/com/fullcycle/application/ticket/CreateTicketForCustomerUseCase.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketCreated.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/OutboxConfig.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/QueueGateway.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/job/OutboxRelay.java diff --git a/application/src/main/java/br/com/fullcycle/application/ticket/CreateTicketForCustomerUseCase.java b/application/src/main/java/br/com/fullcycle/application/ticket/CreateTicketForCustomerUseCase.java new file mode 100644 index 00000000..eab6e52f --- /dev/null +++ b/application/src/main/java/br/com/fullcycle/application/ticket/CreateTicketForCustomerUseCase.java @@ -0,0 +1,35 @@ +package br.com.fullcycle.application.ticket; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventTicketId; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketRepository; + +import java.util.Objects; + +public class CreateTicketForCustomerUseCase + extends UseCase { + + private final TicketRepository ticketRepository; + + public CreateTicketForCustomerUseCase(final TicketRepository ticketRepository) { + this.ticketRepository = Objects.requireNonNull(ticketRepository); + } + + @Override + public Output execute(final Input input) { + + final var aTicket = + Ticket.newTicket(EventTicketId.with(input.eventTicketId), CustomerId.with(input.customerId), EventId.with(input.eventId)); + + this.ticketRepository.create(aTicket); + + return new Output(aTicket.ticketId().value()); + } + + public record Input(String eventTicketId, String eventId, String customerId) {} + + public record Output(String ticketId) {} +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java index e37022a4..2fb18bfb 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java @@ -1,15 +1,22 @@ package br.com.fullcycle.domain.event.ticket; +import br.com.fullcycle.domain.DomainEvent; import br.com.fullcycle.domain.customer.CustomerId; import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventTicketId; import br.com.fullcycle.domain.exceptions.ValidationException; import java.time.Instant; +import java.util.Collections; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; public class Ticket { private final TicketId ticketId; + private final Set domainEvents; + private CustomerId customerId; private EventId eventId; private TicketStatus status; @@ -25,6 +32,7 @@ public Ticket( final Instant reservedAt ) { this.ticketId = ticketId; + this.domainEvents = new HashSet<>(); this.setCustomerId(customerId); this.setEventId(eventId); this.setStatus(status); @@ -36,6 +44,12 @@ public static Ticket newTicket(final CustomerId customerId, final EventId eventI return new Ticket(TicketId.unique(), customerId, eventId, TicketStatus.PENDING, null, Instant.now()); } + public static Ticket newTicket(final EventTicketId eventTicketId, final CustomerId customerId, final EventId eventId) { + final var aTicket = newTicket(customerId, eventId); + aTicket.domainEvents.add(new TicketCreated(aTicket.ticketId, eventTicketId, eventId, customerId)); + return aTicket; + } + public TicketId ticketId() { return ticketId; } @@ -60,6 +74,10 @@ public Instant reservedAt() { return reservedAt; } + public Set allDomainEvents() { + return Collections.unmodifiableSet(domainEvents); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketCreated.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketCreated.java new file mode 100644 index 00000000..f60c07b1 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketCreated.java @@ -0,0 +1,24 @@ +package br.com.fullcycle.domain.event.ticket; + +import br.com.fullcycle.domain.DomainEvent; +import br.com.fullcycle.domain.customer.CustomerId; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventTicketId; + +import java.time.Instant; +import java.util.UUID; + +public record TicketCreated( + String domainEventId, + String type, + String ticketId, + String eventTicketId, + String eventId, + String customerId, + Instant occurredOn +) implements DomainEvent { + + public TicketCreated(TicketId ticketId, EventTicketId eventTicketId, EventId eventId, CustomerId customerId) { + this(UUID.randomUUID().toString(), "ticket.created", ticketId.value(), eventTicketId.value(), eventId.value(), customerId.value(), Instant.now()); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java index a60ac304..36cdd746 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/Main.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; +@EnableScheduling @SpringBootApplication public class Main { diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/OutboxConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/OutboxConfig.java new file mode 100644 index 00000000..a9c0e7fe --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/OutboxConfig.java @@ -0,0 +1,19 @@ +package br.com.fullcycle.infrastructure.configurations; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +public class OutboxConfig { + + @Bean + public TaskExecutor queueExecutor() { + var executor = new ThreadPoolTaskExecutor(); + executor.setQueueCapacity(200); + executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 4); + executor.setCorePoolSize(2); + return executor; + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java index 9bf2540d..50286048 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java @@ -6,6 +6,7 @@ import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.application.partner.CreatePartnerUseCase; import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.application.ticket.CreateTicketForCustomerUseCase; import br.com.fullcycle.domain.customer.CustomerRepository; import br.com.fullcycle.domain.event.EventRepository; import br.com.fullcycle.domain.event.ticket.TicketRepository; @@ -64,4 +65,9 @@ public GetPartnerByIdUseCase getPartnerByIdUseCase() { public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { return new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); } + + @Bean + public CreateTicketForCustomerUseCase createTicketForCustomerUseCase() { + return new CreateTicketForCustomerUseCase(ticketRepository); + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java new file mode 100644 index 00000000..f43d397c --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java @@ -0,0 +1,43 @@ +package br.com.fullcycle.infrastructure.gateways; + +import br.com.fullcycle.application.ticket.CreateTicketForCustomerUseCase; +import br.com.fullcycle.domain.event.EventTicketReserved; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Component +public class ConsumerQueueGateway implements QueueGateway { + + private final CreateTicketForCustomerUseCase createTicketForCustomerUseCase; + private final ObjectMapper mapper; + + public ConsumerQueueGateway(final CreateTicketForCustomerUseCase createTicketForCustomerUseCase, final ObjectMapper mapper) { + this.createTicketForCustomerUseCase = Objects.requireNonNull(createTicketForCustomerUseCase); + this.mapper = Objects.requireNonNull(mapper); + } + + @Async(value = "queueExecutor") + @Override + public void publish(final String content) { + if (content == null) { + return; + } + + if (content.contains("event-ticket.reserved")) { + final var dto = safeRead(content, EventTicketReserved.class); + this.createTicketForCustomerUseCase.execute(new CreateTicketForCustomerUseCase.Input(dto.eventTicketId(), dto.eventId(), dto.customerId())); + } + } + + private T safeRead(final String content, final Class tClass) { + try { + return this.mapper.readValue(content, tClass); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/QueueGateway.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/QueueGateway.java new file mode 100644 index 00000000..f6ba0e88 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/QueueGateway.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.infrastructure.gateways; + +public interface QueueGateway { + void publish(String content); +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/job/OutboxRelay.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/job/OutboxRelay.java new file mode 100644 index 00000000..12ec2ed4 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/job/OutboxRelay.java @@ -0,0 +1,29 @@ +package br.com.fullcycle.infrastructure.job; + +import br.com.fullcycle.infrastructure.gateways.QueueGateway; +import br.com.fullcycle.infrastructure.jpa.repositories.OutboxJpaRepository; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +public class OutboxRelay { + + private final OutboxJpaRepository outboxJpaRepository; + private final QueueGateway queueGateway; + + public OutboxRelay(final OutboxJpaRepository outboxJpaRepository, final QueueGateway queueGateway) { + this.outboxJpaRepository = outboxJpaRepository; + this.queueGateway = queueGateway; + } + + @Scheduled(fixedRate = 2_000) + @Transactional + void execute() { + this.outboxJpaRepository.findTop100ByPublishedFalse() + .forEach(it -> { + this.queueGateway.publish(it.content()); + this.outboxJpaRepository.save(it.notePublished()); + }); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java index a9786a66..a32ffef9 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/OutboxEntity.java @@ -1,8 +1,7 @@ package br.com.fullcycle.infrastructure.jpa.entities; import br.com.fullcycle.domain.DomainEvent; -import br.com.fullcycle.domain.customer.Customer; -import br.com.fullcycle.domain.customer.CustomerId; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -18,6 +17,7 @@ public class OutboxEntity { @Id private UUID id; + @Column(columnDefinition = "JSON", length = 4_000) private String content; private boolean published; @@ -75,4 +75,9 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } + + public OutboxEntity notePublished() { + this.published = true; + return this; + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java index 18eeb217..e8240f34 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/OutboxJpaRepository.java @@ -1,6 +1,10 @@ package br.com.fullcycle.infrastructure.jpa.repositories; import br.com.fullcycle.infrastructure.jpa.entities.OutboxEntity; +import jakarta.persistence.LockModeType; +import jakarta.persistence.QueryHint; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.repository.CrudRepository; import java.util.List; @@ -8,5 +12,9 @@ public interface OutboxJpaRepository extends CrudRepository { - List findAllByPublishedFalse(); + @Lock(LockModeType.PESSIMISTIC_WRITE) + @QueryHints({ + @QueryHint(name = "jakarta.persistence.lock.timeout", value = "2") + }) + List findTop100ByPublishedFalse(); } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java index 0b16ddd2..caa41e41 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java @@ -1,10 +1,15 @@ package br.com.fullcycle.infrastructure.repositories; +import br.com.fullcycle.domain.DomainEvent; import br.com.fullcycle.domain.event.ticket.Ticket; import br.com.fullcycle.domain.event.ticket.TicketId; import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.infrastructure.jpa.entities.OutboxEntity; import br.com.fullcycle.infrastructure.jpa.entities.TicketEntity; +import br.com.fullcycle.infrastructure.jpa.repositories.OutboxJpaRepository; import br.com.fullcycle.infrastructure.jpa.repositories.TicketJpaRepository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -17,9 +22,17 @@ public class TicketDatabaseRepository implements TicketRepository { private final TicketJpaRepository ticketJpaRepository; + private final OutboxJpaRepository outboxJpaRepository; + private final ObjectMapper mapper; - public TicketDatabaseRepository(final TicketJpaRepository ticketJpaRepository) { + public TicketDatabaseRepository( + final TicketJpaRepository ticketJpaRepository, + final OutboxJpaRepository outboxJpaRepository, + final ObjectMapper mapper + ) { this.ticketJpaRepository = Objects.requireNonNull(ticketJpaRepository); + this.outboxJpaRepository = outboxJpaRepository; + this.mapper = mapper; } @Override @@ -32,19 +45,37 @@ public Optional ticketOfId(final TicketId anId) { @Override @Transactional public Ticket create(final Ticket ticket) { - return this.ticketJpaRepository.save(TicketEntity.of(ticket)) - .toTicket(); + return save(ticket); } @Override @Transactional public Ticket update(Ticket ticket) { - return this.ticketJpaRepository.save(TicketEntity.of(ticket)) - .toTicket(); + return save(ticket); } @Override public void deleteAll() { this.ticketJpaRepository.deleteAll(); } + + private Ticket save(Ticket ticket) { + this.outboxJpaRepository.saveAll( + ticket.allDomainEvents().stream() + .map(it -> OutboxEntity.of(it, this::toJson)) + .toList() + ); + + + return this.ticketJpaRepository.save(TicketEntity.of(ticket)) + .toTicket(); + } + + private String toJson(DomainEvent domainEvent) { + try { + return this.mapper.writeValueAsString(domainEvent); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } } From 1e3f84dfd8e38d8535bd20bf0e8fd39cd7836d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Duarte=20Mota?= Date: Mon, 24 Aug 2026 20:22:31 -0300 Subject: [PATCH 22/22] initial commit --- README.md | 39 ++++++++ .../application/event/CancelEventUseCase.java | 35 +++++++ .../application/event/CreateEventUseCase.java | 5 +- .../event/GetEventByIdUseCase.java | 37 ++++++++ .../ticket/CancelEventTicketsUseCase.java | 39 ++++++++ .../event/CancelEventUseCaseTest.java | 86 +++++++++++++++++ .../event/GetEventByIdUseCaseTest.java | 52 ++++++++++ .../SubscribeCustomerToEventUseCaseTest.java | 32 +++++++ .../repository/InMemoryTicketRepository.java | 9 ++ .../ticket/CancelEventTicketsUseCaseTest.java | 86 +++++++++++++++++ .../br/com/fullcycle/domain/event/Event.java | 25 ++++- .../domain/event/EventCancelled.java | 18 ++++ .../fullcycle/domain/event/EventStatus.java | 5 + .../fullcycle/domain/event/ticket/Ticket.java | 8 ++ .../domain/event/ticket/TicketRepository.java | 5 + .../domain/event/ticket/TicketStatus.java | 2 +- .../com/fullcycle/domain/event/EventTest.java | 70 ++++++++++++++ .../domain/event/ticket/TicketTest.java | 46 +++++++++ .../configurations/UseCaseConfig.java | 18 ++++ .../gateways/ConsumerQueueGateway.java | 15 ++- .../infrastructure/graphql/EventResolver.java | 21 ++++- .../jpa/entities/EventEntity.java | 19 +++- .../jpa/repositories/TicketJpaRepository.java | 2 + .../TicketDatabaseRepository.java | 10 ++ .../infrastructure/rest/EventController.java | 40 +++++++- .../GetEventByIdResponseEntity.java | 28 ++++++ .../PublicGetEventByIdResponseEntity.java | 31 ++++++ .../src/main/resources/graphql/schema.gqls | 8 ++ .../usecases/CancelEventUseCaseIT.java | 67 +++++++++++++ .../ConsumerQueueGatewayCancelEventIT.java | 84 +++++++++++++++++ .../TicketDatabaseRepositoryIT.java | 73 ++++++++++++++ .../rest/EventControllerTest.java | 94 +++++++++++++++++++ 32 files changed, 1099 insertions(+), 10 deletions(-) create mode 100644 README.md create mode 100644 application/src/main/java/br/com/fullcycle/application/event/CancelEventUseCase.java create mode 100644 application/src/main/java/br/com/fullcycle/application/event/GetEventByIdUseCase.java create mode 100644 application/src/main/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCase.java create mode 100644 application/src/test/java/br/com/fullcycle/application/event/CancelEventUseCaseTest.java create mode 100644 application/src/test/java/br/com/fullcycle/application/event/GetEventByIdUseCaseTest.java create mode 100644 application/src/test/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCaseTest.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/EventCancelled.java create mode 100644 domain/src/main/java/br/com/fullcycle/domain/event/EventStatus.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetEventByIdResponseEntity.java create mode 100644 infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetEventByIdResponseEntity.java create mode 100644 infrastructure/src/test/java/br/com/fullcycle/application/usecases/CancelEventUseCaseIT.java create mode 100644 infrastructure/src/test/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGatewayCancelEventIT.java create mode 100644 infrastructure/src/test/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepositoryIT.java diff --git a/README.md b/README.md new file mode 100644 index 00000000..acf5d402 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# MBA Hexagonal Architecture — Plataforma de Ingressos + +Projeto do curso de Arquitetura Hexagonal & Clean Architecture (Full Cycle), estendido com a feature de **cancelamento de evento**. + +## Como subir o projeto + +Pré-requisitos: Java 17 e Docker (para o MySQL). + +1. Suba o banco de dados: + ```bash + docker-compose up -d + ``` +2. Rode a aplicação: + ```bash + ./gradlew :infrastructure:bootRun + ``` + A API sobe em `http://localhost:8080`. O endpoint REST fica na raiz (`/events`, `/customers`, `/partners`) e o GraphQL em `/graphql` (GraphiQL habilitado em `/graphiql`). + +## Como rodar a suíte de testes + +```bash +./gradlew test +``` + +Isso roda os testes de domínio (`domain`), casos de uso com repositórios in-memory (`application`) e os testes de integração/REST (`infrastructure`), estes últimos usando um banco H2 em memória (perfil `test`), sem depender do MySQL do `docker-compose`. + +Para rodar só um módulo: `./gradlew :domain:test`, `./gradlew :application:test` ou `./gradlew :infrastructure:test`. + +## Coleção de requisições `.http` (opcional, uso local) + +Crie localmente uma pasta `requests/` com arquivos `.http` (extensão [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) do VS Code) para testar a API manualmente — um arquivo por entidade (`partners.http`, `customers.http`, `events.http`), com exemplos de criação/cancelamento/consulta de evento. Essa pasta está no `.gitignore` por ser uma conveniência de desenvolvimento, não um entregável do desafio. + +## Onde acontece a cascata de cancelamento + +Quando um parceiro cancela um evento (`CancelEventUseCase`), o agregado `Event` apenas transiciona seu próprio estado para `CANCELLED` e registra o evento de domínio `EventCancelled` (`domain/.../event/EventCancelled.java`) — ele **não** toca o agregado `Ticket` nem chama nenhum caso de uso de ingresso de forma síncrona. + +Esse `EventCancelled` trafega pelo mesmo mecanismo já usado para `EventTicketReserved`: ao persistir o evento (`EventDatabaseRepository`), os eventos de domínio pendentes são gravados na tabela `outbox`; o job `OutboxRelay` publica periodicamente os registros não publicados na fila via `QueueGateway`; e o `ConsumerQueueGateway` roteia a mensagem pelo seu `type` (`event.cancelled`) para o caso de uso `CancelEventTicketsUseCase`, que busca todos os ingressos do evento (`TicketRepository.ticketsByEventId`) e cancela cada um (`Ticket.cancel()`, idempotente). + +Esse fluxo assíncrono ponta a ponta — publicação no `ConsumerQueueGateway` até os tickets ficarem `CANCELLED` — é coberto pelo teste `infrastructure/src/test/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGatewayCancelEventIT.java`. diff --git a/application/src/main/java/br/com/fullcycle/application/event/CancelEventUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/CancelEventUseCase.java new file mode 100644 index 00000000..0f62d431 --- /dev/null +++ b/application/src/main/java/br/com/fullcycle/application/event/CancelEventUseCase.java @@ -0,0 +1,35 @@ +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.exceptions.ValidationException; + +import java.util.Objects; + +public class CancelEventUseCase extends UseCase { + + private final EventRepository eventRepository; + + public CancelEventUseCase(final EventRepository eventRepository) { + this.eventRepository = Objects.requireNonNull(eventRepository); + } + + @Override + public Output execute(final Input input) { + final var anEvent = eventRepository.eventOfId(EventId.with(input.id())) + .orElseThrow(() -> new ValidationException("Event not found")); + + anEvent.cancel(); + + eventRepository.update(anEvent); + + return new Output(anEvent.eventId().value(), anEvent.status().name()); + } + + public record Input(String id) { + } + + public record Output(String id, String status) { + } +} diff --git a/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java index cef3d8e0..f753a394 100644 --- a/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java +++ b/application/src/main/java/br/com/fullcycle/application/event/CreateEventUseCase.java @@ -32,13 +32,14 @@ public Output execute(final Input input) { input.date, anEvent.name().value(), anEvent.totalSpots(), - anEvent.partnerId().value() + anEvent.partnerId().value(), + anEvent.status().name() ); } public record Input(String date, String name, String partnerId, Integer totalSpots) { } - public record Output(String id, String date, String name, int totalSpots, String partnerId) { + public record Output(String id, String date, String name, int totalSpots, String partnerId, String status) { } } diff --git a/application/src/main/java/br/com/fullcycle/application/event/GetEventByIdUseCase.java b/application/src/main/java/br/com/fullcycle/application/event/GetEventByIdUseCase.java new file mode 100644 index 00000000..984a1aa1 --- /dev/null +++ b/application/src/main/java/br/com/fullcycle/application/event/GetEventByIdUseCase.java @@ -0,0 +1,37 @@ +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; + +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.Optional; + +public class GetEventByIdUseCase + extends UseCase> { + + private final EventRepository eventRepository; + + public GetEventByIdUseCase(final EventRepository eventRepository) { + this.eventRepository = Objects.requireNonNull(eventRepository); + } + + @Override + public Optional execute(final Input input) { + return eventRepository.eventOfId(EventId.with(input.id())) + .map(anEvent -> new Output( + anEvent.eventId().value(), + anEvent.name().value(), + anEvent.date().format(DateTimeFormatter.ISO_LOCAL_DATE), + anEvent.totalSpots(), + anEvent.status().name()) + ); + } + + public record Input(String id) { + } + + public record Output(String id, String name, String date, int totalSpots, String status) { + } +} diff --git a/application/src/main/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCase.java b/application/src/main/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCase.java new file mode 100644 index 00000000..5e22eff3 --- /dev/null +++ b/application/src/main/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCase.java @@ -0,0 +1,39 @@ +package br.com.fullcycle.application.ticket; + +import br.com.fullcycle.application.UseCase; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.ticket.TicketRepository; + +import java.util.List; +import java.util.Objects; + +public class CancelEventTicketsUseCase + extends UseCase { + + private final TicketRepository ticketRepository; + + public CancelEventTicketsUseCase(final TicketRepository ticketRepository) { + this.ticketRepository = Objects.requireNonNull(ticketRepository); + } + + @Override + public Output execute(final Input input) { + final var anEventId = EventId.with(input.eventId()); + + final var cancelledTicketIds = ticketRepository.ticketsByEventId(anEventId).stream() + .map(aTicket -> { + aTicket.cancel(); + ticketRepository.update(aTicket); + return aTicket.ticketId().value(); + }) + .toList(); + + return new Output(input.eventId(), cancelledTicketIds); + } + + public record Input(String eventId) { + } + + public record Output(String eventId, List cancelledTicketIds) { + } +} diff --git a/application/src/test/java/br/com/fullcycle/application/event/CancelEventUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/CancelEventUseCaseTest.java new file mode 100644 index 00000000..b81e5446 --- /dev/null +++ b/application/src/test/java/br/com/fullcycle/application/event/CancelEventUseCaseTest.java @@ -0,0 +1,86 @@ +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.repository.InMemoryEventRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.Partner; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CancelEventUseCaseTest { + + @Test + @DisplayName("Deve cancelar um evento ativo") + public void testCancelEvent() throws Exception { + // given + final var expectedStatus = "CANCELLED"; + + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var eventID = anEvent.eventId().value(); + + final var cancelInput = new CancelEventUseCase.Input(eventID); + + final var eventRepository = new InMemoryEventRepository(); + eventRepository.create(anEvent); + + // when + final var useCase = new CancelEventUseCase(eventRepository); + final var output = useCase.execute(cancelInput); + + // then + Assertions.assertEquals(eventID, output.id()); + Assertions.assertEquals(expectedStatus, output.status()); + + final var actualEvent = eventRepository.eventOfId(anEvent.eventId()).get(); + Assertions.assertEquals(expectedStatus, actualEvent.status().name()); + } + + @Test + @DisplayName("Não deve cancelar um evento que não existe") + public void testCancelEventThatDoesNotExist() throws Exception { + // given + final var expectedError = "Event not found"; + + final var eventID = EventId.unique().value(); + + final var cancelInput = new CancelEventUseCase.Input(eventID); + + final var eventRepository = new InMemoryEventRepository(); + + // when + final var useCase = new CancelEventUseCase(eventRepository); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(cancelInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } + + @Test + @DisplayName("Não deve cancelar um evento já cancelado") + public void testCancelEventAlreadyCancelled() throws Exception { + // given + final var expectedError = "Event already cancelled"; + + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + anEvent.cancel(); + + final var eventID = anEvent.eventId().value(); + + final var cancelInput = new CancelEventUseCase.Input(eventID); + + final var eventRepository = new InMemoryEventRepository(); + eventRepository.create(anEvent); + + // when + final var useCase = new CancelEventUseCase(eventRepository); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(cancelInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} diff --git a/application/src/test/java/br/com/fullcycle/application/event/GetEventByIdUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/GetEventByIdUseCaseTest.java new file mode 100644 index 00000000..12537b1b --- /dev/null +++ b/application/src/test/java/br/com/fullcycle/application/event/GetEventByIdUseCaseTest.java @@ -0,0 +1,52 @@ +package br.com.fullcycle.application.event; + +import br.com.fullcycle.application.repository.InMemoryEventRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.partner.Partner; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GetEventByIdUseCaseTest { + + @Test + @DisplayName("Deve obter um evento pelo id") + public void testGetEventById() throws Exception { + // given + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var eventRepository = new InMemoryEventRepository(); + eventRepository.create(anEvent); + + final var getInput = new GetEventByIdUseCase.Input(anEvent.eventId().value()); + + // when + final var useCase = new GetEventByIdUseCase(eventRepository); + final var output = useCase.execute(getInput); + + // then + Assertions.assertTrue(output.isPresent()); + Assertions.assertEquals(anEvent.eventId().value(), output.get().id()); + Assertions.assertEquals("Disney on Ice", output.get().name()); + Assertions.assertEquals("2021-01-01", output.get().date()); + Assertions.assertEquals(10, output.get().totalSpots()); + Assertions.assertEquals("ACTIVE", output.get().status()); + } + + @Test + @DisplayName("Não deve obter um evento que não existe") + public void testGetEventByIdThatDoesNotExist() throws Exception { + // given + final var eventRepository = new InMemoryEventRepository(); + final var getInput = new GetEventByIdUseCase.Input(EventId.unique().value()); + + // when + final var useCase = new GetEventByIdUseCase(eventRepository); + final var output = useCase.execute(getInput); + + // then + Assertions.assertTrue(output.isEmpty()); + } +} diff --git a/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java index 2d2afc56..355dce17 100644 --- a/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java +++ b/application/src/test/java/br/com/fullcycle/application/event/SubscribeCustomerToEventUseCaseTest.java @@ -170,4 +170,36 @@ public void testReserveTicketWithoutSlots() throws Exception { // then Assertions.assertEquals(expectedError, actualException.getMessage()); } + + @Test + @DisplayName("Não deve comprar um ticket de um evento cancelado") + public void testReserveTicketOnCancelledEvent() throws Exception { + // given + final var expectedError = "Event is cancelled"; + + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + anEvent.cancel(); + + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); + + final var customerID = aCustomer.customerId().value(); + final var eventID = anEvent.eventId().value(); + + final var subscribeInput = + new SubscribeCustomerToEventUseCase.Input(customerID, eventID); + + final var customerRepository = new InMemoryCustomerRepository(); + final var eventRepository = new InMemoryEventRepository(); + + customerRepository.create(aCustomer); + eventRepository.create(anEvent); + + // when + final var useCase = new SubscribeCustomerToEventUseCase(customerRepository, eventRepository); + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(subscribeInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } } \ No newline at end of file diff --git a/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java index ddf3864c..5b955c68 100644 --- a/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java +++ b/application/src/test/java/br/com/fullcycle/application/repository/InMemoryTicketRepository.java @@ -1,10 +1,12 @@ package br.com.fullcycle.application.repository; +import br.com.fullcycle.domain.event.EventId; import br.com.fullcycle.domain.event.ticket.Ticket; import br.com.fullcycle.domain.event.ticket.TicketId; import br.com.fullcycle.domain.event.ticket.TicketRepository; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -38,4 +40,11 @@ public Ticket update(Ticket ticket) { public void deleteAll() { this.tickets.clear(); } + + @Override + public List ticketsByEventId(EventId anEventId) { + return this.tickets.values().stream() + .filter(it -> Objects.equals(it.eventId(), anEventId)) + .toList(); + } } diff --git a/application/src/test/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCaseTest.java b/application/src/test/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCaseTest.java new file mode 100644 index 00000000..a23fbe0a --- /dev/null +++ b/application/src/test/java/br/com/fullcycle/application/ticket/CancelEventTicketsUseCaseTest.java @@ -0,0 +1,86 @@ +package br.com.fullcycle.application.ticket; + +import br.com.fullcycle.application.repository.InMemoryTicketRepository; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketStatus; +import br.com.fullcycle.domain.partner.Partner; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CancelEventTicketsUseCaseTest { + + @Test + @DisplayName("Deve cancelar todos os tickets de um evento") + public void testCancelEventTickets() throws Exception { + // given + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); + final var aCustomer2 = Customer.newCustomer("Pedro Doe", "123.111.789-01", "pedro.doe@gmail.com"); + + final var aTicket = Ticket.newTicket(aCustomer.customerId(), anEvent.eventId()); + final var aTicket2 = Ticket.newTicket(aCustomer2.customerId(), anEvent.eventId()); + + final var ticketRepository = new InMemoryTicketRepository(); + ticketRepository.create(aTicket); + ticketRepository.create(aTicket2); + + final var cancelInput = new CancelEventTicketsUseCase.Input(anEvent.eventId().value()); + + // when + final var useCase = new CancelEventTicketsUseCase(ticketRepository); + final var output = useCase.execute(cancelInput); + + // then + Assertions.assertEquals(2, output.cancelledTicketIds().size()); + + final var tickets = ticketRepository.ticketsByEventId(anEvent.eventId()); + Assertions.assertTrue(tickets.stream().allMatch(it -> it.status() == TicketStatus.CANCELLED)); + } + + @Test + @DisplayName("Deve ser idempotente ao reprocessar o cancelamento dos tickets de um evento") + public void testCancelEventTicketsIsIdempotent() throws Exception { + // given + final var aPartner = Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + final var anEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + final var aCustomer = Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com"); + + final var aTicket = Ticket.newTicket(aCustomer.customerId(), anEvent.eventId()); + + final var ticketRepository = new InMemoryTicketRepository(); + ticketRepository.create(aTicket); + + final var cancelInput = new CancelEventTicketsUseCase.Input(anEvent.eventId().value()); + final var useCase = new CancelEventTicketsUseCase(ticketRepository); + + useCase.execute(cancelInput); + + // when + useCase.execute(cancelInput); + + // then + final var tickets = ticketRepository.ticketsByEventId(anEvent.eventId()); + Assertions.assertEquals(1, tickets.size()); + Assertions.assertEquals(TicketStatus.CANCELLED, tickets.get(0).status()); + } + + @Test + @DisplayName("Não deve falhar ao cancelar os tickets de um evento sem tickets") + public void testCancelEventTicketsWithoutTickets() throws Exception { + // given + final var ticketRepository = new InMemoryTicketRepository(); + final var cancelInput = new CancelEventTicketsUseCase.Input(EventId.unique().value()); + + // when + final var useCase = new CancelEventTicketsUseCase(ticketRepository); + final var output = useCase.execute(cancelInput); + + // then + Assertions.assertTrue(output.cancelledTicketIds().isEmpty()); + } +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/Event.java b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java index 7abf3639..3ac1d53a 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/Event.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/Event.java @@ -26,6 +26,7 @@ public class Event { private LocalDate date; private int totalSpots; private PartnerId partnerId; + private EventStatus status; public Event( final EventId eventId, @@ -33,6 +34,7 @@ public Event( final String date, final Integer totalSpots, final PartnerId partnerId, + final EventStatus status, final Set tickets ) { this(eventId, tickets); @@ -40,6 +42,7 @@ public Event( this.setDate(date); this.setTotalSpots(totalSpots); this.setPartnerId(partnerId); + this.status = status != null ? status : EventStatus.ACTIVE; } private Event(final EventId eventId, final Set tickets) { @@ -53,7 +56,7 @@ private Event(final EventId eventId, final Set tickets) { } public static Event newEvent(final String name, final String date, final Integer totalSpots, final Partner partner) { - return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId(), null); + return new Event(EventId.unique(), name, date, totalSpots, partner.partnerId(), EventStatus.ACTIVE, null); } public static Event restore( @@ -62,12 +65,26 @@ public static Event restore( final String date, final int totalSpots, final String partnerId, + final String status, final Set tickets ) { - return new Event(EventId.with(id), name, date, totalSpots, PartnerId.with(partnerId), tickets); + return new Event(EventId.with(id), name, date, totalSpots, PartnerId.with(partnerId), EventStatus.valueOf(status), tickets); + } + + public void cancel() { + if (this.status == EventStatus.CANCELLED) { + throw new ValidationException("Event already cancelled"); + } + + this.status = EventStatus.CANCELLED; + this.domainEvents.add(new EventCancelled(eventId())); } public EventTicket reserveTicket(final CustomerId aCustomerId) { + if (this.status == EventStatus.CANCELLED) { + throw new ValidationException("Event is cancelled"); + } + this.allTickets().stream() .filter(it -> Objects.equals(it.customerId(), aCustomerId)) .findFirst() @@ -108,6 +125,10 @@ public PartnerId partnerId() { return partnerId; } + public EventStatus status() { + return status; + } + public Set allTickets() { return Collections.unmodifiableSet(tickets); } diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/EventCancelled.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventCancelled.java new file mode 100644 index 00000000..7591ee5b --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventCancelled.java @@ -0,0 +1,18 @@ +package br.com.fullcycle.domain.event; + +import br.com.fullcycle.domain.DomainEvent; + +import java.time.Instant; +import java.util.UUID; + +public record EventCancelled( + String domainEventId, + String type, + String eventId, + Instant occurredOn +) implements DomainEvent { + + public EventCancelled(EventId eventId) { + this(UUID.randomUUID().toString(), "event.cancelled", eventId.value(), Instant.now()); + } +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/EventStatus.java b/domain/src/main/java/br/com/fullcycle/domain/event/EventStatus.java new file mode 100644 index 00000000..0b41c528 --- /dev/null +++ b/domain/src/main/java/br/com/fullcycle/domain/event/EventStatus.java @@ -0,0 +1,5 @@ +package br.com.fullcycle.domain.event; + +public enum EventStatus { + ACTIVE, CANCELLED; +} diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java index 2fb18bfb..a56984d6 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/Ticket.java @@ -78,6 +78,14 @@ public Set allDomainEvents() { return Collections.unmodifiableSet(domainEvents); } + public void cancel() { + if (this.status == TicketStatus.CANCELLED) { + return; + } + + this.status = TicketStatus.CANCELLED; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java index c30de970..9150508b 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketRepository.java @@ -1,5 +1,8 @@ package br.com.fullcycle.domain.event.ticket; +import br.com.fullcycle.domain.event.EventId; + +import java.util.List; import java.util.Optional; public interface TicketRepository { @@ -11,4 +14,6 @@ public interface TicketRepository { Ticket update(Ticket ticket); void deleteAll(); + + List ticketsByEventId(EventId anEventId); } diff --git a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java index 9b27c4e5..642ed8d0 100644 --- a/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java +++ b/domain/src/main/java/br/com/fullcycle/domain/event/ticket/TicketStatus.java @@ -1,5 +1,5 @@ package br.com.fullcycle.domain.event.ticket; public enum TicketStatus { - PENDING, PROCESSING, PAID; + PENDING, PROCESSING, PAID, CANCELLED; } diff --git a/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java index cf5d23f4..aa3f3bfa 100644 --- a/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/event/EventTest.java @@ -179,4 +179,74 @@ public void testReserveTwoTicketsForTheSameClient() throws Exception { // then Assertions.assertEquals(expectedError, actualError.getMessage()); } + + @Test + @DisplayName("Deve cancelar um evento ativo") + public void testCancelEvent() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var expectedDomainEvent = "event.cancelled"; + + final var actualEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + // when + actualEvent.cancel(); + + // then + Assertions.assertEquals(EventStatus.CANCELLED, actualEvent.status()); + + final var actualDomainEvents = actualEvent.allDomainEvents().iterator().next(); + Assertions.assertEquals(expectedDomainEvent, actualDomainEvents.type()); + } + + @Test + @DisplayName("Não deve cancelar um evento já cancelado") + public void testCancelEventTwice() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var expectedError = "Event already cancelled"; + + final var actualEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + actualEvent.cancel(); + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + actualEvent::cancel + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } + + @Test + @DisplayName("Não deve reservar um ticket em um evento cancelado") + public void testReserveTicketOnCancelledEvent() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var expectedError = "Event is cancelled"; + + final var actualEvent = Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + actualEvent.cancel(); + + // when + final var actualError = Assertions.assertThrows( + ValidationException.class, + () -> actualEvent.reserveTicket(aCustomer.customerId()) + ); + + // then + Assertions.assertEquals(expectedError, actualError.getMessage()); + } } diff --git a/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java b/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java index 96cb9f1d..2f51364f 100644 --- a/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java +++ b/domain/src/test/java/br/com/fullcycle/domain/event/ticket/TicketTest.java @@ -39,4 +39,50 @@ public void testReserveTicket() throws Exception { Assertions.assertEquals(expectedCustomerId, actualTicket.customerId()); Assertions.assertEquals(expectedTicketStatus, actualTicket.status()); } + + @Test + @DisplayName("Deve cancelar um ticket") + public void testCancelTicket() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var anEvent = + Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var actualTicket = Ticket.newTicket(aCustomer.customerId(), anEvent.eventId()); + + // when + actualTicket.cancel(); + + // then + Assertions.assertEquals(TicketStatus.CANCELLED, actualTicket.status()); + } + + @Test + @DisplayName("Deve ser idempotente ao cancelar um ticket já cancelado") + public void testCancelTicketTwice() throws Exception { + // given + final var aPartner = + Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com"); + + final var aCustomer = + Customer.newCustomer("John Doe", "123.456.789-01", "john.doe@gmail.com"); + + final var anEvent = + Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner); + + final var actualTicket = Ticket.newTicket(aCustomer.customerId(), anEvent.eventId()); + + actualTicket.cancel(); + + // when + actualTicket.cancel(); + + // then + Assertions.assertEquals(TicketStatus.CANCELLED, actualTicket.status()); + } } \ No newline at end of file diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java index 50286048..5707cd33 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/configurations/UseCaseConfig.java @@ -2,10 +2,13 @@ import br.com.fullcycle.application.customer.CreateCustomerUseCase; import br.com.fullcycle.application.customer.GetCustomerByIdUseCase; +import br.com.fullcycle.application.event.CancelEventUseCase; import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.GetEventByIdUseCase; import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.application.partner.CreatePartnerUseCase; import br.com.fullcycle.application.partner.GetPartnerByIdUseCase; +import br.com.fullcycle.application.ticket.CancelEventTicketsUseCase; import br.com.fullcycle.application.ticket.CreateTicketForCustomerUseCase; import br.com.fullcycle.domain.customer.CustomerRepository; import br.com.fullcycle.domain.event.EventRepository; @@ -70,4 +73,19 @@ public SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase() { public CreateTicketForCustomerUseCase createTicketForCustomerUseCase() { return new CreateTicketForCustomerUseCase(ticketRepository); } + + @Bean + public CancelEventUseCase cancelEventUseCase() { + return new CancelEventUseCase(eventRepository); + } + + @Bean + public CancelEventTicketsUseCase cancelEventTicketsUseCase() { + return new CancelEventTicketsUseCase(ticketRepository); + } + + @Bean + public GetEventByIdUseCase getEventByIdUseCase() { + return new GetEventByIdUseCase(eventRepository); + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java index f43d397c..6a7a9bcb 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGateway.java @@ -1,6 +1,8 @@ package br.com.fullcycle.infrastructure.gateways; +import br.com.fullcycle.application.ticket.CancelEventTicketsUseCase; import br.com.fullcycle.application.ticket.CreateTicketForCustomerUseCase; +import br.com.fullcycle.domain.event.EventCancelled; import br.com.fullcycle.domain.event.EventTicketReserved; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,10 +15,16 @@ public class ConsumerQueueGateway implements QueueGateway { private final CreateTicketForCustomerUseCase createTicketForCustomerUseCase; + private final CancelEventTicketsUseCase cancelEventTicketsUseCase; private final ObjectMapper mapper; - public ConsumerQueueGateway(final CreateTicketForCustomerUseCase createTicketForCustomerUseCase, final ObjectMapper mapper) { + public ConsumerQueueGateway( + final CreateTicketForCustomerUseCase createTicketForCustomerUseCase, + final CancelEventTicketsUseCase cancelEventTicketsUseCase, + final ObjectMapper mapper + ) { this.createTicketForCustomerUseCase = Objects.requireNonNull(createTicketForCustomerUseCase); + this.cancelEventTicketsUseCase = Objects.requireNonNull(cancelEventTicketsUseCase); this.mapper = Objects.requireNonNull(mapper); } @@ -31,6 +39,11 @@ public void publish(final String content) { final var dto = safeRead(content, EventTicketReserved.class); this.createTicketForCustomerUseCase.execute(new CreateTicketForCustomerUseCase.Input(dto.eventTicketId(), dto.eventId(), dto.customerId())); } + + if (content.contains("event.cancelled")) { + final var dto = safeRead(content, EventCancelled.class); + this.cancelEventTicketsUseCase.execute(new CancelEventTicketsUseCase.Input(dto.eventId())); + } } private T safeRead(final String content, final Class tClass) { diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java index 5a7ae0f2..92d2a33c 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/graphql/EventResolver.java @@ -1,11 +1,14 @@ package br.com.fullcycle.infrastructure.graphql; +import br.com.fullcycle.application.event.CancelEventUseCase; import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.GetEventByIdUseCase; import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.infrastructure.dtos.NewEventDTO; import br.com.fullcycle.infrastructure.dtos.SubscribeDTO; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.MutationMapping; +import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; @@ -16,13 +19,19 @@ public class EventResolver { private final CreateEventUseCase createEventUseCase; private final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase; + private final CancelEventUseCase cancelEventUseCase; + private final GetEventByIdUseCase getEventByIdUseCase; public EventResolver( final CreateEventUseCase createEventUseCase, - final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase + final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase, + final CancelEventUseCase cancelEventUseCase, + final GetEventByIdUseCase getEventByIdUseCase ) { this.createEventUseCase = Objects.requireNonNull(createEventUseCase); this.subscribeCustomerToEventUseCase = Objects.requireNonNull(subscribeCustomerToEventUseCase); + this.cancelEventUseCase = Objects.requireNonNull(cancelEventUseCase); + this.getEventByIdUseCase = Objects.requireNonNull(getEventByIdUseCase); } @MutationMapping @@ -35,4 +44,14 @@ public CreateEventUseCase.Output createEvent(@Argument NewEventDTO input) { public SubscribeCustomerToEventUseCase.Output subscribeCustomerToEvent(@Argument SubscribeDTO input) { return subscribeCustomerToEventUseCase.execute(new SubscribeCustomerToEventUseCase.Input(input.customerId(), input.eventId())); } + + @MutationMapping + public CancelEventUseCase.Output cancelEvent(@Argument String id) { + return cancelEventUseCase.execute(new CancelEventUseCase.Input(id)); + } + + @QueryMapping + public GetEventByIdUseCase.Output eventOfId(@Argument String id) { + return getEventByIdUseCase.execute(new GetEventByIdUseCase.Input(id)).orElse(null); + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java index c504ffbd..cd105ecc 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/entities/EventEntity.java @@ -1,6 +1,7 @@ package br.com.fullcycle.infrastructure.jpa.entities; import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventStatus; import br.com.fullcycle.domain.event.EventTicket; import jakarta.persistence.*; @@ -27,6 +28,9 @@ public class EventEntity { private UUID partnerId; + @Enumerated(EnumType.STRING) + private EventStatus status; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "event") private Set tickets; @@ -34,13 +38,14 @@ public EventEntity() { this.tickets = new HashSet<>(); } - public EventEntity(UUID id, String name, LocalDate date, int totalSpots, UUID partnerId) { + public EventEntity(UUID id, String name, LocalDate date, int totalSpots, UUID partnerId, EventStatus status) { this(); this.id = id; this.name = name; this.date = date; this.totalSpots = totalSpots; this.partnerId = partnerId; + this.status = status; } public static EventEntity of(final Event event) { @@ -49,7 +54,8 @@ public static EventEntity of(final Event event) { event.name().value(), event.date(), event.totalSpots(), - UUID.fromString(event.partnerId().value()) + UUID.fromString(event.partnerId().value()), + event.status() ); event.allTickets().forEach(entity::addTicket); @@ -64,6 +70,7 @@ public Event toEvent() { this.date().format(DateTimeFormatter.ISO_LOCAL_DATE), this.totalSpots(), this.partnerId().toString(), + this.status().name(), this.tickets().stream() .map(EventTicketEntity::toEventTicket) .collect(Collectors.toSet()) @@ -114,6 +121,14 @@ public void setPartnerId(UUID partnerId) { this.partnerId = partnerId; } + public EventStatus status() { + return status; + } + + public void setStatus(EventStatus status) { + this.status = status; + } + public Set tickets() { return tickets; } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java index 97458ef1..f53c7246 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/jpa/repositories/TicketJpaRepository.java @@ -3,8 +3,10 @@ import br.com.fullcycle.infrastructure.jpa.entities.TicketEntity; import org.springframework.data.repository.CrudRepository; +import java.util.List; import java.util.UUID; public interface TicketJpaRepository extends CrudRepository { + List findAllByEventId(UUID eventId); } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java index caa41e41..a714e229 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepository.java @@ -1,6 +1,7 @@ package br.com.fullcycle.infrastructure.repositories; import br.com.fullcycle.domain.DomainEvent; +import br.com.fullcycle.domain.event.EventId; import br.com.fullcycle.domain.event.ticket.Ticket; import br.com.fullcycle.domain.event.ticket.TicketId; import br.com.fullcycle.domain.event.ticket.TicketRepository; @@ -13,6 +14,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -59,6 +61,14 @@ public void deleteAll() { this.ticketJpaRepository.deleteAll(); } + @Override + public List ticketsByEventId(final EventId anEventId) { + Objects.requireNonNull(anEventId, "id cannot be null"); + return this.ticketJpaRepository.findAllByEventId(UUID.fromString(anEventId.value())).stream() + .map(TicketEntity::toTicket) + .toList(); + } + private Ticket save(Ticket ticket) { this.outboxJpaRepository.saveAll( ticket.allDomainEvents().stream() diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java index 32d3ef2e..16f09215 100644 --- a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/EventController.java @@ -1,6 +1,9 @@ package br.com.fullcycle.infrastructure.rest; +import br.com.fullcycle.application.Presenter; +import br.com.fullcycle.application.event.CancelEventUseCase; import br.com.fullcycle.application.event.CreateEventUseCase; +import br.com.fullcycle.application.event.GetEventByIdUseCase; import br.com.fullcycle.application.event.SubscribeCustomerToEventUseCase; import br.com.fullcycle.domain.exceptions.ValidationException; import br.com.fullcycle.infrastructure.dtos.NewEventDTO; @@ -11,6 +14,7 @@ import java.net.URI; import java.util.Objects; +import java.util.Optional; // Adapter @RestController @@ -19,13 +23,25 @@ public class EventController { private final CreateEventUseCase createEventUseCase; private final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase; + private final CancelEventUseCase cancelEventUseCase; + private final GetEventByIdUseCase getEventByIdUseCase; + private final Presenter, Object> privateGetEventPresenter; + private final Presenter, Object> publicGetEventPresenter; public EventController( final CreateEventUseCase createEventUseCase, - final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase + final SubscribeCustomerToEventUseCase subscribeCustomerToEventUseCase, + final CancelEventUseCase cancelEventUseCase, + final GetEventByIdUseCase getEventByIdUseCase, + final Presenter, Object> privateGetEvent, + final Presenter, Object> publicGetEvent ) { this.createEventUseCase = Objects.requireNonNull(createEventUseCase); this.subscribeCustomerToEventUseCase = Objects.requireNonNull(subscribeCustomerToEventUseCase); + this.cancelEventUseCase = Objects.requireNonNull(cancelEventUseCase); + this.getEventByIdUseCase = Objects.requireNonNull(getEventByIdUseCase); + this.privateGetEventPresenter = Objects.requireNonNull(privateGetEvent); + this.publicGetEventPresenter = Objects.requireNonNull(publicGetEvent); } @PostMapping @@ -52,4 +68,26 @@ public ResponseEntity subscribe(@PathVariable String id, @RequestBody Subscri return ResponseEntity.unprocessableEntity().body(ex.getMessage()); } } + + @PostMapping(value = "/{id}/cancel") + public ResponseEntity cancel(@PathVariable String id) { + try { + final var output = cancelEventUseCase.execute(new CancelEventUseCase.Input(id)); + + return ResponseEntity.ok(output); + } catch (ValidationException ex) { + return ResponseEntity.unprocessableEntity().body(ex.getMessage()); + } + } + + @GetMapping("/{id}") + public Object get(@PathVariable String id, @RequestHeader(name = "X-Public", required = false) String xPublic) { + Presenter, Object> presenter = privateGetEventPresenter; + + if (xPublic != null) { + presenter = publicGetEventPresenter; + } + + return getEventByIdUseCase.execute(new GetEventByIdUseCase.Input(id), presenter); + } } diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetEventByIdResponseEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetEventByIdResponseEntity.java new file mode 100644 index 00000000..17477203 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/GetEventByIdResponseEntity.java @@ -0,0 +1,28 @@ +package br.com.fullcycle.infrastructure.rest.presenters; + +import br.com.fullcycle.application.Presenter; +import br.com.fullcycle.application.event.GetEventByIdUseCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component("privateGetEvent") +public class GetEventByIdResponseEntity implements Presenter, Object> { + + private static final Logger LOG = LoggerFactory.getLogger(GetEventByIdResponseEntity.class); + + @Override + public ResponseEntity present(final Optional output) { + return output.map(ResponseEntity::ok) + .orElseGet(ResponseEntity.notFound()::build); + } + + @Override + public ResponseEntity present(Throwable error) { + LOG.error("An error was observer at GetEventByIdUseCase", error); + return ResponseEntity.notFound().build(); + } +} diff --git a/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetEventByIdResponseEntity.java b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetEventByIdResponseEntity.java new file mode 100644 index 00000000..0cd5e514 --- /dev/null +++ b/infrastructure/src/main/java/br/com/fullcycle/infrastructure/rest/presenters/PublicGetEventByIdResponseEntity.java @@ -0,0 +1,31 @@ +package br.com.fullcycle.infrastructure.rest.presenters; + +import br.com.fullcycle.application.Presenter; +import br.com.fullcycle.application.event.GetEventByIdUseCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component("publicGetEvent") +public class PublicGetEventByIdResponseEntity implements Presenter, Object> { + + private static final Logger LOG = LoggerFactory.getLogger(PublicGetEventByIdResponseEntity.class); + + @Override + public ResponseEntity present(final Optional output) { + return output.map(o -> ResponseEntity.ok((Object) new PublicEvent(o.id(), o.status()))) + .orElseGet(ResponseEntity.notFound()::build); + } + + @Override + public ResponseEntity present(Throwable error) { + LOG.error("An error was observer at GetEventByIdUseCase", error); + return ResponseEntity.notFound().build(); + } + + public record PublicEvent(String id, String status) { + } +} diff --git a/infrastructure/src/main/resources/graphql/schema.gqls b/infrastructure/src/main/resources/graphql/schema.gqls index dd4cf22a..268310d6 100644 --- a/infrastructure/src/main/resources/graphql/schema.gqls +++ b/infrastructure/src/main/resources/graphql/schema.gqls @@ -1,6 +1,7 @@ type Query { customerOfId(id: ID!): Customer partnerOfId(id: ID!): Partner + eventOfId(id: ID!): Event } type Mutation { @@ -8,6 +9,7 @@ type Mutation { createEvent(input: EventInput): Event! createPartner(input: PartnerInput): Partner! subscribeCustomerToEvent(input: SubscribeInput): Subscribe! + cancelEvent(id: ID!): CancelEventResult! } type Customer { @@ -28,6 +30,7 @@ type Event { date: String! totalSpots: Int! name: String! + status: String } input EventInput { @@ -37,6 +40,11 @@ input EventInput { partnerId: ID } +type CancelEventResult { + id: ID! + status: String! +} + type Partner { id: ID! name: String diff --git a/infrastructure/src/test/java/br/com/fullcycle/application/usecases/CancelEventUseCaseIT.java b/infrastructure/src/test/java/br/com/fullcycle/application/usecases/CancelEventUseCaseIT.java new file mode 100644 index 00000000..8e7edab4 --- /dev/null +++ b/infrastructure/src/test/java/br/com/fullcycle/application/usecases/CancelEventUseCaseIT.java @@ -0,0 +1,67 @@ +package br.com.fullcycle.application.usecases; + +import br.com.fullcycle.IntegrationTest; +import br.com.fullcycle.application.event.CancelEventUseCase; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.event.EventStatus; +import br.com.fullcycle.domain.exceptions.ValidationException; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerRepository; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class CancelEventUseCaseIT extends IntegrationTest { + + @Autowired + private CancelEventUseCase useCase; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private PartnerRepository partnerRepository; + + @BeforeEach + void setUp() { + eventRepository.deleteAll(); + partnerRepository.deleteAll(); + } + + @Test + @DisplayName("Deve cancelar um evento persistido") + public void testCancelEvent() throws Exception { + // given + final var aPartner = partnerRepository.create(Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com")); + final var anEvent = eventRepository.create(Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner)); + + final var cancelInput = new CancelEventUseCase.Input(anEvent.eventId().value()); + + // when + final var output = useCase.execute(cancelInput); + + // then + Assertions.assertEquals("CANCELLED", output.status()); + + final var actualEvent = eventRepository.eventOfId(EventId.with(anEvent.eventId().value())).get(); + Assertions.assertEquals(EventStatus.CANCELLED, actualEvent.status()); + } + + @Test + @DisplayName("Não deve cancelar um evento que não existe") + public void testCancelEventThatDoesNotExist() throws Exception { + // given + final var expectedError = "Event not found"; + final var cancelInput = new CancelEventUseCase.Input(EventId.unique().value()); + + // when + final var actualException = Assertions.assertThrows(ValidationException.class, () -> useCase.execute(cancelInput)); + + // then + Assertions.assertEquals(expectedError, actualException.getMessage()); + } +} diff --git a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGatewayCancelEventIT.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGatewayCancelEventIT.java new file mode 100644 index 00000000..cb83d4fb --- /dev/null +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/gateways/ConsumerQueueGatewayCancelEventIT.java @@ -0,0 +1,84 @@ +package br.com.fullcycle.infrastructure.gateways; + +import br.com.fullcycle.IntegrationTest; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventCancelled; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.domain.event.ticket.TicketStatus; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerRepository; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; + +class ConsumerQueueGatewayCancelEventIT extends IntegrationTest { + + @Autowired + private ConsumerQueueGateway consumerQueueGateway; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private TicketRepository ticketRepository; + + @Autowired + private CustomerRepository customerRepository; + + @Autowired + private PartnerRepository partnerRepository; + + @BeforeEach + void setUp() { + ticketRepository.deleteAll(); + eventRepository.deleteAll(); + customerRepository.deleteAll(); + partnerRepository.deleteAll(); + } + + @Test + @DisplayName("Deve cancelar todos os tickets do evento ao processar um EventCancelled recebido pela fila") + public void testCascadeCancelsTicketsWhenEventCancelledIsConsumedFromQueue() throws Exception { + // given + final var aPartner = partnerRepository.create(Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com")); + final var anEvent = eventRepository.create(Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner)); + + final var aCustomer = customerRepository.create(Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com")); + final var aCustomer2 = customerRepository.create(Customer.newCustomer("Pedro Doe", "123.111.789-01", "pedro.doe@gmail.com")); + + ticketRepository.create(Ticket.newTicket(aCustomer.customerId(), anEvent.eventId())); + ticketRepository.create(Ticket.newTicket(aCustomer2.customerId(), anEvent.eventId())); + + final var eventCancelled = new EventCancelled(anEvent.eventId()); + final var json = mapper.writeValueAsString(eventCancelled); + + // when: dispara o EventCancelled pelo caminho real do gateway, o mesmo usado pelo OutboxRelay + consumerQueueGateway.publish(json); + + // then: publish é assíncrono, então aguarda o processamento com timeout + final var deadline = Instant.now().plus(Duration.ofSeconds(5)); + List ticketsOfEvent; + do { + Thread.sleep(100); + ticketsOfEvent = ticketRepository.ticketsByEventId(anEvent.eventId()); + } while (Instant.now().isBefore(deadline) + && ticketsOfEvent.stream().anyMatch(it -> it.status() != TicketStatus.CANCELLED)); + + Assertions.assertEquals(2, ticketsOfEvent.size()); + Assertions.assertTrue(ticketsOfEvent.stream().allMatch(it -> it.status() == TicketStatus.CANCELLED)); + } +} diff --git a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepositoryIT.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepositoryIT.java new file mode 100644 index 00000000..80095dff --- /dev/null +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/repositories/TicketDatabaseRepositoryIT.java @@ -0,0 +1,73 @@ +package br.com.fullcycle.infrastructure.repositories; + +import br.com.fullcycle.IntegrationTest; +import br.com.fullcycle.domain.customer.Customer; +import br.com.fullcycle.domain.customer.CustomerRepository; +import br.com.fullcycle.domain.event.Event; +import br.com.fullcycle.domain.event.EventId; +import br.com.fullcycle.domain.event.EventRepository; +import br.com.fullcycle.domain.event.ticket.Ticket; +import br.com.fullcycle.domain.event.ticket.TicketRepository; +import br.com.fullcycle.domain.partner.Partner; +import br.com.fullcycle.domain.partner.PartnerRepository; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class TicketDatabaseRepositoryIT extends IntegrationTest { + + @Autowired + private TicketRepository ticketRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private CustomerRepository customerRepository; + + @Autowired + private PartnerRepository partnerRepository; + + @BeforeEach + void setUp() { + ticketRepository.deleteAll(); + eventRepository.deleteAll(); + customerRepository.deleteAll(); + partnerRepository.deleteAll(); + } + + @Test + @DisplayName("Deve buscar os tickets de um evento") + public void testTicketsByEventId() throws Exception { + // given + final var aPartner = partnerRepository.create(Partner.newPartner("John Doe", "41.536.538/0001-00", "john.doe@gmail.com")); + final var anEvent = eventRepository.create(Event.newEvent("Disney on Ice", "2021-01-01", 10, aPartner)); + final var anotherEvent = eventRepository.create(Event.newEvent("Rock in Rio", "2021-02-01", 10, aPartner)); + + final var aCustomer = customerRepository.create(Customer.newCustomer("Gabriel Doe", "123.456.789-01", "gabriel.doe@gmail.com")); + final var aCustomer2 = customerRepository.create(Customer.newCustomer("Pedro Doe", "123.111.789-01", "pedro.doe@gmail.com")); + + ticketRepository.create(Ticket.newTicket(aCustomer.customerId(), anEvent.eventId())); + ticketRepository.create(Ticket.newTicket(aCustomer2.customerId(), anEvent.eventId())); + ticketRepository.create(Ticket.newTicket(aCustomer.customerId(), anotherEvent.eventId())); + + // when + final var actualTickets = ticketRepository.ticketsByEventId(anEvent.eventId()); + + // then + Assertions.assertEquals(2, actualTickets.size()); + Assertions.assertTrue(actualTickets.stream().allMatch(it -> it.eventId().equals(anEvent.eventId()))); + } + + @Test + @DisplayName("Deve retornar lista vazia para um evento sem tickets") + public void testTicketsByEventIdWithoutTickets() throws Exception { + // when + final var actualTickets = ticketRepository.ticketsByEventId(EventId.unique()); + + // then + Assertions.assertTrue(actualTickets.isEmpty()); + } +} diff --git a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java index 2e0f8ea2..b111653f 100644 --- a/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java +++ b/infrastructure/src/test/java/br/com/fullcycle/infrastructure/rest/EventControllerTest.java @@ -109,4 +109,98 @@ public void testReserveTicket() throws Exception { var actualEvent = eventRepository.eventOfId(EventId.with(eventId)).get(); Assertions.assertEquals(1, actualEvent.allTickets().size()); } + + @Test + @DisplayName("Deve cancelar um evento") + public void testCancel() throws Exception { + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); + + final var createResult = this.mvc.perform( + MockMvcRequestBuilders.post("/events") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(event)) + ) + .andReturn().getResponse().getContentAsByteArray(); + + var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); + + this.mvc.perform(MockMvcRequestBuilders.post("/events/{id}/cancel", eventId)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(eventId)) + .andExpect(MockMvcResultMatchers.jsonPath("$.status").value("CANCELLED")); + } + + @Test + @DisplayName("Não deve cancelar um evento já cancelado") + public void testCancelAlreadyCancelledShouldFail() throws Exception { + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); + + final var createResult = this.mvc.perform( + MockMvcRequestBuilders.post("/events") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(event)) + ) + .andReturn().getResponse().getContentAsByteArray(); + + var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); + + this.mvc.perform(MockMvcRequestBuilders.post("/events/{id}/cancel", eventId)) + .andExpect(MockMvcResultMatchers.status().isOk()); + + this.mvc.perform(MockMvcRequestBuilders.post("/events/{id}/cancel", eventId)) + .andExpect(MockMvcResultMatchers.status().isUnprocessableEntity()) + .andExpect(MockMvcResultMatchers.content().string("Event already cancelled")); + } + + @Test + @DisplayName("Deve obter um evento por id") + public void testGet() throws Exception { + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); + + final var createResult = this.mvc.perform( + MockMvcRequestBuilders.post("/events") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(event)) + ) + .andReturn().getResponse().getContentAsByteArray(); + + var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); + + this.mvc.perform(MockMvcRequestBuilders.get("/events/{id}", eventId)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(eventId)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Disney on Ice")) + .andExpect(MockMvcResultMatchers.jsonPath("$.status").value("ACTIVE")); + } + + @Test + @DisplayName("Deve obter um evento por id com X-Public") + public void testGetPublic() throws Exception { + var event = new NewEventDTO("Disney on Ice", "2021-01-01", 100, disney.partnerId().value()); + + final var createResult = this.mvc.perform( + MockMvcRequestBuilders.post("/events") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(event)) + ) + .andReturn().getResponse().getContentAsByteArray(); + + var eventId = mapper.readValue(createResult, CreateEventUseCase.Output.class).id(); + + this.mvc.perform( + MockMvcRequestBuilders.get("/events/{id}", eventId) + .header("X-Public", "true") + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(eventId)) + .andExpect(MockMvcResultMatchers.jsonPath("$.status").value("ACTIVE")) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").doesNotExist()); + } + + @Test + @DisplayName("Deve retornar 404 ao consultar um evento que não existe") + public void testGetNotFound() throws Exception { + this.mvc.perform(MockMvcRequestBuilders.get("/events/{id}", EventId.unique().value())) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } } \ No newline at end of file