parent
a1b83f76f2
commit
28cdc0ddc0
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.boot.composite.key;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
@SpringBootApplication
|
||||
@PropertySource("classpath:boot.composite.key/app.properties")
|
||||
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.composite.key" })
|
||||
public class SpringBootCompositeKeyApplication {
|
||||
public static void main(String... args) {
|
||||
SpringApplication.run(SpringBootCompositeKeyApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.boot.composite.key.dao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.composite.key.data.Customer;
|
||||
|
||||
public interface CustomerRepository extends MongoRepository<Customer, String> {
|
||||
|
||||
Optional<Customer> findByStoreIdAndNumber(Long storeId, Long number);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.boot.composite.key.dao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.composite.key.data.Sale;
|
||||
import com.baeldung.boot.composite.key.data.TicketId;
|
||||
|
||||
public interface SaleRepository extends MongoRepository<Sale, String> {
|
||||
Optional<Sale> findByTicketId(TicketId ticketId);
|
||||
}
|
|
@ -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<Ticket, TicketId> {
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.boot.composite.key.data;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
@CompoundIndex(name = "customer_idx", def = "{ 'storeId': 1, 'number': 1 }", unique = true)
|
||||
public class Customer {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private Long storeId;
|
||||
private Long number;
|
||||
|
||||
private String name;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getStoreId() {
|
||||
return storeId;
|
||||
}
|
||||
|
||||
public void setStoreId(Long storeId) {
|
||||
this.storeId = storeId;
|
||||
}
|
||||
|
||||
public Long getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(Long number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung.boot.composite.key.data;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
@CompoundIndex(name = "sale_idx", def = "{ 'ticketId': 1 }", unique = true)
|
||||
public class Sale {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private TicketId ticketId;
|
||||
private Double value;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public TicketId getTicketId() {
|
||||
return ticketId;
|
||||
}
|
||||
|
||||
public void setTicketId(TicketId ticketId) {
|
||||
this.ticketId = ticketId;
|
||||
}
|
||||
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Double value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
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.CustomerRepository;
|
||||
import com.baeldung.boot.composite.key.dao.SaleRepository;
|
||||
import com.baeldung.boot.composite.key.dao.TicketRepository;
|
||||
import com.baeldung.boot.composite.key.data.Customer;
|
||||
import com.baeldung.boot.composite.key.data.Sale;
|
||||
import com.baeldung.boot.composite.key.data.Ticket;
|
||||
import com.baeldung.boot.composite.key.data.TicketId;
|
||||
|
||||
@Service
|
||||
public class CustomerService {
|
||||
@Autowired
|
||||
private CustomerRepository customerRepository;
|
||||
|
||||
@Autowired
|
||||
private TicketRepository ticketRepository;
|
||||
|
||||
@Autowired
|
||||
private SaleRepository saleRepository;
|
||||
|
||||
public Optional<Ticket> 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);
|
||||
}
|
||||
|
||||
public Optional<Customer> findCustomerById(String id) {
|
||||
return customerRepository.findById(id);
|
||||
}
|
||||
|
||||
public Optional<Customer> findCustomerByIndex(Long storeId, Long number) {
|
||||
return customerRepository.findByStoreIdAndNumber(storeId, number);
|
||||
}
|
||||
|
||||
public Customer insert(Customer customer) {
|
||||
return customerRepository.insert(customer);
|
||||
}
|
||||
|
||||
public Customer save(Customer customer) {
|
||||
return customerRepository.save(customer);
|
||||
}
|
||||
|
||||
public Sale insert(Sale sale) {
|
||||
return saleRepository.insert(sale);
|
||||
}
|
||||
|
||||
public Optional<Sale> findSaleByTicketId(TicketId ticketId) {
|
||||
return saleRepository.findByTicketId(ticketId);
|
||||
}
|
||||
|
||||
public Optional<Sale> findSaleById(String id) {
|
||||
return saleRepository.findById(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
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.PathVariable;
|
||||
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.Customer;
|
||||
import com.baeldung.boot.composite.key.data.Sale;
|
||||
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;
|
||||
|
||||
// @Autowired
|
||||
// private TicketRepository ticketRepository;
|
||||
//
|
||||
// @GetMapping("/ticket")
|
||||
// public Optional<Ticket> getTicket(TicketId id) {
|
||||
// return ticketRepository.findById(id);
|
||||
// }
|
||||
//
|
||||
// @PostMapping("/ticket")
|
||||
// public Ticket postTicket(@RequestBody Ticket ticket) {
|
||||
// return ticketRepository.insert(ticket);
|
||||
// }
|
||||
|
||||
@GetMapping("/ticket")
|
||||
public Optional<Ticket> 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);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Optional<Customer> getCustomer(@PathVariable String id) {
|
||||
return customerService.findCustomerById(id);
|
||||
}
|
||||
|
||||
@GetMapping("/{storeId}/{number}")
|
||||
public Optional<Customer> getCustomerByIndex(@PathVariable Long storeId, @PathVariable Long number) {
|
||||
return customerService.findCustomerByIndex(storeId, number);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Customer postCustomer(@RequestBody Customer customer) {
|
||||
return customerService.insert(customer);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public Customer putCustomer(@RequestBody Customer customer) {
|
||||
return customerService.save(customer);
|
||||
}
|
||||
|
||||
@PostMapping("/sale")
|
||||
public Sale postSale(@RequestBody Sale sale) {
|
||||
return customerService.insert(sale);
|
||||
}
|
||||
|
||||
@GetMapping("/sale/{id}")
|
||||
public Optional<Sale> getSale(@PathVariable String id) {
|
||||
return customerService.findSaleById(id);
|
||||
}
|
||||
|
||||
@GetMapping("/sale")
|
||||
public Optional<Sale> getSale(TicketId ticketId) {
|
||||
return customerService.findSaleByTicketId(ticketId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
spring.data.mongodb.auto-index-creation=true
|
|
@ -0,0 +1,140 @@
|
|||
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.BeforeClass;
|
||||
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.Customer;
|
||||
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;
|
||||
|
||||
private static Ticket ticket;
|
||||
private static TicketId ticketId;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
ticket = new Ticket();
|
||||
ticket.setEvent("Event A");
|
||||
|
||||
ticketId = new TicketId();
|
||||
ticketId.setDate("2020-01-01");
|
||||
ticketId.setVenue("Venue A");
|
||||
ticket.setId(ticketId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompositeId_whenObjectSaved_thenIdMatches() {
|
||||
Ticket savedTicket = service.insert(ticket);
|
||||
assertEquals(savedTicket.getId(), ticket.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompositeId_whenSearchingByIdObject_thenFound() {
|
||||
Optional<Ticket> optionalTicket = service.find(ticketId);
|
||||
|
||||
assertThat(optionalTicket.isPresent());
|
||||
Ticket savedTicket = optionalTicket.get();
|
||||
|
||||
assertEquals(savedTicket.getId(), ticketId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompoundUniqueIndex_whenSearchingByGeneratedId_thenFound() {
|
||||
Customer customer = new Customer();
|
||||
customer.setName("Name");
|
||||
customer.setNumber(0l);
|
||||
customer.setStoreId(0l);
|
||||
|
||||
Customer savedCustomer = service.insert(customer);
|
||||
|
||||
Optional<Customer> optional = service.findCustomerById(savedCustomer.getId());
|
||||
|
||||
assertThat(optional.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompositeId_whenDupeInsert_thenExceptionIsThrown() {
|
||||
Ticket ticket = new Ticket();
|
||||
ticket.setEvent("C");
|
||||
|
||||
TicketId ticketId = new TicketId();
|
||||
ticketId.setDate("2020-01-01");
|
||||
ticketId.setVenue("V");
|
||||
ticket.setId(ticketId);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
service.insert(ticket);
|
||||
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();
|
||||
ticketA.setEvent("A");
|
||||
ticketA.setId(ticketId);
|
||||
|
||||
service.save(ticketA);
|
||||
|
||||
Ticket ticketB = new Ticket();
|
||||
ticketB.setEvent("B");
|
||||
ticketB.setId(ticketId);
|
||||
|
||||
Ticket savedTicket = service.save(ticketB);
|
||||
assertEquals(savedTicket.getEvent(), ticketB.getEvent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompoundUniqueIndex_whenDupeInsert_thenExceptionIsThrown() {
|
||||
Customer customer = new Customer();
|
||||
customer.setName("Name");
|
||||
customer.setNumber(1l);
|
||||
customer.setStoreId(2l);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
service.insert(customer);
|
||||
service.insert(customer);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompoundUniqueIndex_whenDupeSave_thenExceptionIsThrown() {
|
||||
Customer customerA = new Customer();
|
||||
customerA.setName("Name A");
|
||||
customerA.setNumber(1l);
|
||||
customerA.setStoreId(2l);
|
||||
|
||||
Customer customerB = new Customer();
|
||||
customerB.setName("Name B");
|
||||
customerB.setNumber(1l);
|
||||
customerB.setStoreId(2l);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
service.save(customerA);
|
||||
service.save(customerB);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue