BAEL-5394 - Unique Field in MongoDB Document in Spring Data (#12384)
* 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 * first draft * removing Customer2
This commit is contained in:
parent
413ee370c2
commit
e798355a92
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.boot.unique.field;
|
||||
|
||||
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.unique.field/app.properties")
|
||||
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.unique.field" })
|
||||
public class SpringBootUniqueFieldApplication {
|
||||
public static void main(String... args) {
|
||||
SpringApplication.run(SpringBootUniqueFieldApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.boot.unique.field.dao;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.unique.field.data.Asset;
|
||||
|
||||
public interface AssetRepository extends MongoRepository<Asset, String> {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.boot.unique.field.dao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.unique.field.data.Company;
|
||||
|
||||
public interface CompanyRepository extends MongoRepository<Company, String> {
|
||||
Optional<Company> findByEmail(String email);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.boot.unique.field.dao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.unique.field.data.Customer;
|
||||
|
||||
public interface CustomerRepository extends MongoRepository<Customer, String> {
|
||||
Optional<Customer> findByStoreIdAndNumber(Long storeId, Long number);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.boot.unique.field.dao;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.boot.unique.field.data.Sale;
|
||||
import com.baeldung.boot.unique.field.data.SaleId;
|
||||
|
||||
public interface SaleRepository extends MongoRepository<Sale, String> {
|
||||
Optional<Sale> findBySaleId(SaleId id);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.boot.unique.field.data;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
public class Asset {
|
||||
@Indexed(unique = true)
|
||||
private String name;
|
||||
|
||||
@Indexed(unique = true)
|
||||
private Integer number;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(Integer number) {
|
||||
this.number = number;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.baeldung.boot.unique.field.data;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
public class Company {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Indexed(unique = true)
|
||||
private String email;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.boot.unique.field.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 Customer() {
|
||||
}
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = 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,36 @@
|
|||
package com.baeldung.boot.unique.field.data;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document
|
||||
public class Sale {
|
||||
@Indexed(unique = true)
|
||||
private SaleId saleId;
|
||||
|
||||
private Double value;
|
||||
|
||||
public Sale() {
|
||||
}
|
||||
|
||||
public Sale(SaleId saleId) {
|
||||
super();
|
||||
this.saleId = saleId;
|
||||
}
|
||||
|
||||
public SaleId getSaleId() {
|
||||
return saleId;
|
||||
}
|
||||
|
||||
public void setSaleId(SaleId saleId) {
|
||||
this.saleId = saleId;
|
||||
}
|
||||
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Double value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.boot.unique.field.data;
|
||||
|
||||
public class SaleId {
|
||||
private Long item;
|
||||
private String date;
|
||||
|
||||
public Long getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public void setItem(Long item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.baeldung.boot.unique.field.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.unique.field.dao.AssetRepository;
|
||||
import com.baeldung.boot.unique.field.dao.CompanyRepository;
|
||||
import com.baeldung.boot.unique.field.dao.CustomerRepository;
|
||||
import com.baeldung.boot.unique.field.dao.SaleRepository;
|
||||
import com.baeldung.boot.unique.field.data.Asset;
|
||||
import com.baeldung.boot.unique.field.data.Company;
|
||||
import com.baeldung.boot.unique.field.data.Customer;
|
||||
import com.baeldung.boot.unique.field.data.Sale;
|
||||
import com.baeldung.boot.unique.field.data.SaleId;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/unique-field")
|
||||
public class UniqueFieldController {
|
||||
@Autowired
|
||||
private SaleRepository saleRepo;
|
||||
|
||||
@Autowired
|
||||
private CompanyRepository companyRepo;
|
||||
|
||||
@Autowired
|
||||
private CustomerRepository customerRepo;
|
||||
|
||||
@Autowired
|
||||
private AssetRepository assetRepo;
|
||||
|
||||
@PostMapping("/sale")
|
||||
public Sale post(@RequestBody Sale sale) {
|
||||
return saleRepo.insert(sale);
|
||||
}
|
||||
|
||||
@GetMapping("/sale")
|
||||
public Optional<Sale> getSale(SaleId id) {
|
||||
return saleRepo.findBySaleId(id);
|
||||
}
|
||||
|
||||
@PostMapping("/company")
|
||||
public Company post(@RequestBody Company company) {
|
||||
return companyRepo.insert(company);
|
||||
}
|
||||
|
||||
@PutMapping("/company")
|
||||
public Company put(@RequestBody Company company) {
|
||||
return companyRepo.save(company);
|
||||
}
|
||||
|
||||
@GetMapping("/company/{id}")
|
||||
public Optional<Company> getCompany(@PathVariable String id) {
|
||||
return companyRepo.findById(id);
|
||||
}
|
||||
|
||||
@PostMapping("/customer")
|
||||
public Customer post(@RequestBody Customer customer) {
|
||||
return customerRepo.insert(customer);
|
||||
}
|
||||
|
||||
@GetMapping("/customer/{id}")
|
||||
public Optional<Customer> getCustomer(@PathVariable String id) {
|
||||
return customerRepo.findById(id);
|
||||
}
|
||||
|
||||
@PostMapping("/asset")
|
||||
public Asset post(@RequestBody Asset asset) {
|
||||
return assetRepo.insert(asset);
|
||||
}
|
||||
|
||||
@GetMapping("/asset/{id}")
|
||||
public Optional<Asset> getAsset(@PathVariable String id) {
|
||||
return assetRepo.findById(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
spring.data.mongodb.auto-index-creation=true
|
|
@ -0,0 +1,112 @@
|
|||
package com.baeldung.boot.unique.field;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
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.unique.field.dao.AssetRepository;
|
||||
import com.baeldung.boot.unique.field.dao.CompanyRepository;
|
||||
import com.baeldung.boot.unique.field.dao.CustomerRepository;
|
||||
import com.baeldung.boot.unique.field.dao.SaleRepository;
|
||||
import com.baeldung.boot.unique.field.data.Asset;
|
||||
import com.baeldung.boot.unique.field.data.Company;
|
||||
import com.baeldung.boot.unique.field.data.Customer;
|
||||
import com.baeldung.boot.unique.field.data.Sale;
|
||||
import com.baeldung.boot.unique.field.data.SaleId;
|
||||
|
||||
@SpringBootTest
|
||||
@DirtiesContext
|
||||
@RunWith(SpringRunner.class)
|
||||
public class UniqueFieldIntegrationTest {
|
||||
@Autowired
|
||||
private SaleRepository saleRepo;
|
||||
|
||||
@Autowired
|
||||
private CompanyRepository companyRepo;
|
||||
|
||||
@Autowired
|
||||
private CustomerRepository customerRepo;
|
||||
|
||||
@Autowired
|
||||
private AssetRepository assetRepo;
|
||||
|
||||
@Test
|
||||
public void givenMultipleIndexes_whenAnyFieldDupe_thenExceptionIsThrown() {
|
||||
Asset a = new Asset();
|
||||
a.setName("Name");
|
||||
a.setNumber(1);
|
||||
|
||||
assetRepo.insert(a);
|
||||
|
||||
Asset b = new Asset();
|
||||
b.setName("Name");
|
||||
b.setNumber(2);
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
assetRepo.insert(b);
|
||||
});
|
||||
|
||||
Asset c = new Asset();
|
||||
c.setName("Other");
|
||||
c.setNumber(1);
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
assetRepo.insert(c);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUniqueIndex_whenInsertingDupe_thenExceptionIsThrown() {
|
||||
Company a = new Company();
|
||||
a.setName("Name");
|
||||
a.setEmail("a@mail.com");
|
||||
|
||||
companyRepo.insert(a);
|
||||
|
||||
Company b = new Company();
|
||||
b.setName("Other");
|
||||
b.setEmail("a@mail.com");
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
companyRepo.insert(b);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompoundIndex_whenDupeInsert_thenExceptionIsThrown() {
|
||||
Customer customerA = new Customer("Name A");
|
||||
customerA.setNumber(1l);
|
||||
customerA.setStoreId(2l);
|
||||
|
||||
Customer customerB = new Customer("Name B");
|
||||
customerB.setNumber(1l);
|
||||
customerB.setStoreId(2l);
|
||||
|
||||
customerRepo.insert(customerA);
|
||||
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
customerRepo.insert(customerB);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCustomTypeIndex_whenInsertingDupe_thenExceptionIsThrown() {
|
||||
SaleId id = new SaleId();
|
||||
id.setDate("2022-06-15");
|
||||
id.setItem(1L);
|
||||
|
||||
Sale a = new Sale(id);
|
||||
a.setValue(53.94);
|
||||
|
||||
saleRepo.insert(a);
|
||||
|
||||
Sale b = new Sale(id);
|
||||
b.setValue(100.00);
|
||||
assertThrows(DuplicateKeyException.class, () -> {
|
||||
saleRepo.insert(b);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue