From bb8a76cc97c6238240e59f8ad97325df7c7ae86c Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Sat, 18 Jun 2022 04:49:40 -0300 Subject: [PATCH] BAEL-5370 - MongoDB Composite Key (#12273) * BAEL-5370 - MongoDB Composite Key First Draft. * removing comments * BAEL-5370 Test could fail if ran in a different order: givenCompositeId_whenSearchingByIdObject_thenFound * BAEL-5370 removing compound index related stuff * removing first insert from assertThrows --- .../SpringBootCompositeKeyApplication.java | 13 +++ .../composite/key/dao/TicketRepository.java | 10 +++ .../boot/composite/key/data/Ticket.java | 37 ++++++++ .../boot/composite/key/data/TicketId.java | 56 +++++++++++++ .../key/service/CustomerService.java | 28 +++++++ .../composite/key/web/CustomerController.java | 37 ++++++++ .../key/CustomerServiceIntegrationTest.java | 84 +++++++++++++++++++ 7 files changed, 265 insertions(+) create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java create mode 100644 persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java new file mode 100644 index 0000000000..1322adbf77 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/SpringBootCompositeKeyApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.boot.composite.key; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@SpringBootApplication +@EnableMongoRepositories(basePackages = { "com.baeldung.boot.composite.key" }) +public class SpringBootCompositeKeyApplication { + public static void main(String... args) { + SpringApplication.run(SpringBootCompositeKeyApplication.class, args); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java new file mode 100644 index 0000000000..b02ea461d2 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/dao/TicketRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.boot.composite.key.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; + +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; + +public interface TicketRepository extends MongoRepository { + +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java new file mode 100644 index 0000000000..d77b54c513 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/Ticket.java @@ -0,0 +1,37 @@ +package com.baeldung.boot.composite.key.data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +public class Ticket { + @Id + private TicketId id; + + private String event; + + public Ticket() { + } + + public Ticket(TicketId id, String event) { + super(); + this.id = id; + this.event = event; + } + + public TicketId getId() { + return id; + } + + public void setId(TicketId id) { + this.id = id; + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java new file mode 100644 index 0000000000..76fbf81391 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/data/TicketId.java @@ -0,0 +1,56 @@ +package com.baeldung.boot.composite.key.data; + +public class TicketId { + private String venue; + private String date; + + public TicketId() { + } + + public String getVenue() { + return venue; + } + + public void setVenue(String venue) { + this.venue = venue; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((date == null) ? 0 : date.hashCode()); + result = prime * result + ((venue == null) ? 0 : venue.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TicketId other = (TicketId) obj; + if (date == null) { + if (other.date != null) + return false; + } else if (!date.equals(other.date)) + return false; + if (venue == null) { + if (other.venue != null) + return false; + } else if (!venue.equals(other.venue)) + return false; + return true; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java new file mode 100644 index 0000000000..90ca1b758d --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/service/CustomerService.java @@ -0,0 +1,28 @@ +package com.baeldung.boot.composite.key.service; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.boot.composite.key.dao.TicketRepository; +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; + +@Service +public class CustomerService { + @Autowired + private TicketRepository ticketRepository; + + public Optional find(TicketId id) { + return ticketRepository.findById(id); + } + + public Ticket insert(Ticket ticket) { + return ticketRepository.insert(ticket); + } + + public Ticket save(Ticket ticket) { + return ticketRepository.save(ticket); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java new file mode 100644 index 0000000000..4379a46d05 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/main/java/com/baeldung/boot/composite/key/web/CustomerController.java @@ -0,0 +1,37 @@ +package com.baeldung.boot.composite.key.web; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; +import com.baeldung.boot.composite.key.service.CustomerService; + +@RestController +@RequestMapping("/customer") +public class CustomerController { + @Autowired + private CustomerService customerService; + + @GetMapping("/ticket") + public Optional getTicket(TicketId id) { + return customerService.find(id); + } + + @PostMapping("/ticket") + public Ticket postTicket(@RequestBody Ticket ticket) { + return customerService.insert(ticket); + } + + @PutMapping("/ticket") + public Ticket putTicket(@RequestBody Ticket ticket) { + return customerService.save(ticket); + } +} diff --git a/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java new file mode 100644 index 0000000000..af310ab29e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-mongodb-2/src/test/java/com/baeldung/boot/composite/key/CustomerServiceIntegrationTest.java @@ -0,0 +1,84 @@ +package com.baeldung.boot.composite.key; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import java.util.Optional; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.boot.composite.key.data.Ticket; +import com.baeldung.boot.composite.key.data.TicketId; +import com.baeldung.boot.composite.key.service.CustomerService; + +@SpringBootTest +@DirtiesContext +@RunWith(SpringRunner.class) +public class CustomerServiceIntegrationTest { + @Autowired + private CustomerService service; + + @Test + public void givenCompositeId_whenObjectSaved_thenIdMatches() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue A"); + + Ticket ticket = new Ticket(ticketId, "Event A"); + Ticket savedTicket = service.insert(ticket); + + assertEquals(savedTicket.getId(), ticket.getId()); + } + + @Test + public void givenCompositeId_whenSearchingByIdObject_thenFound() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue B"); + + service.insert(new Ticket(ticketId, "Event B")); + + Optional optionalTicket = service.find(ticketId); + + assertThat(optionalTicket.isPresent()); + Ticket savedTicket = optionalTicket.get(); + + assertEquals(savedTicket.getId(), ticketId); + } + + @Test + public void givenCompositeId_whenDupeInsert_thenExceptionIsThrown() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("V"); + + Ticket ticket = new Ticket(ticketId, "Event C"); + service.insert(ticket); + + assertThrows(DuplicateKeyException.class, () -> { + service.insert(ticket); + }); + } + + @Test + public void givenCompositeId_whenDupeSave_thenObjectUpdated() { + TicketId ticketId = new TicketId(); + ticketId.setDate("2020-01-01"); + ticketId.setVenue("Venue"); + + Ticket ticketA = new Ticket(ticketId, "A"); + service.save(ticketA); + + Ticket ticketB = new Ticket(ticketId, "B"); + Ticket savedTicket = service.save(ticketB); + + assertEquals(savedTicket.getEvent(), ticketB.getEvent()); + } +}