@@ -60,7 +60,7 @@ class ExpressionIntegrationTests {
|
|||||||
employeeRepository.findAllByName("Walter") //
|
employeeRepository.findAllByName("Walter") //
|
||||||
.contextWrite(Context.of(Tenant.class, new Tenant("breaking-bad"))).as(StepVerifier::create) //
|
.contextWrite(Context.of(Tenant.class, new Tenant("breaking-bad"))).as(StepVerifier::create) //
|
||||||
.assertNext(actual -> {
|
.assertNext(actual -> {
|
||||||
assertThat(actual.getTenantId()).isEqualTo("breaking-bad");
|
assertThat(actual.tenantId()).isEqualTo("breaking-bad");
|
||||||
}).verifyComplete();
|
}).verifyComplete();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
import org.jmolecules.ddd.types.AggregateRoot;
|
import org.jmolecules.ddd.types.AggregateRoot;
|
||||||
import org.jmolecules.ddd.types.Association;
|
import org.jmolecules.ddd.types.Association;
|
||||||
import org.jmolecules.ddd.types.Identifier;
|
import org.jmolecules.ddd.types.Identifier;
|
||||||
@@ -46,7 +47,7 @@ public class Order implements AggregateRoot<Order, Order.OrderId> {
|
|||||||
|
|
||||||
public Order(Customer customer) {
|
public Order(Customer customer) {
|
||||||
|
|
||||||
this.id = new OrderId(UUID.randomUUID());
|
this.id = OrderId.of(UUID.randomUUID());
|
||||||
this.customer = Association.forAggregate(customer);
|
this.customer = Association.forAggregate(customer);
|
||||||
this.lineItems = new ArrayList<>();
|
this.lineItems = new ArrayList<>();
|
||||||
}
|
}
|
||||||
@@ -60,10 +61,13 @@ public class Order implements AggregateRoot<Order, Order.OrderId> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record OrderId(UUID orderId) implements Identifier {
|
@Value(staticConstructor = "of")
|
||||||
|
public static class OrderId implements Identifier {
|
||||||
|
|
||||||
|
UUID orderId;
|
||||||
|
|
||||||
public static OrderId create() {
|
public static OrderId create() {
|
||||||
return new OrderId(UUID.randomUUID());
|
return OrderId.of(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,20 +17,12 @@ package example.springdata.mongodb.aggregation;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DTO to represent invoices.
|
* A DTO to represent invoices.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
@Value
|
public record Invoice(String orderId, double taxAmount, double netAmount, double totalAmount, List<LineItem> items) {
|
||||||
public class Invoice {
|
|
||||||
|
|
||||||
private final String orderId;
|
|
||||||
private final double taxAmount;
|
|
||||||
private final double netAmount;
|
|
||||||
private final double totalAmount;
|
|
||||||
private final List<LineItem> items;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.aggregation;
|
package example.springdata.mongodb.aggregation;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.PersistenceConstructor;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,18 +23,15 @@ import org.springframework.data.annotation.PersistenceConstructor;
|
|||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor))
|
|
||||||
public class LineItem {
|
|
||||||
|
|
||||||
private final String caption;
|
public record LineItem(String caption, double price, int quantity) {
|
||||||
private final double price;
|
|
||||||
|
|
||||||
int quantity = 1;
|
@PersistenceConstructor
|
||||||
|
public LineItem {
|
||||||
public LineItem(String caption, double price, int quantity) {
|
|
||||||
|
|
||||||
this(caption, price);
|
|
||||||
this.quantity = quantity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LineItem(String caption, double price) {
|
||||||
|
this(caption, price, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class OrderRepositoryImpl implements OrderRepositoryCustom {
|
|||||||
@Override
|
@Override
|
||||||
public Invoice getInvoiceFor(Order order) {
|
public Invoice getInvoiceFor(Order order) {
|
||||||
|
|
||||||
AggregationResults<Invoice> results = operations.aggregate(newAggregation(Order.class, //
|
var results = operations.aggregate(newAggregation(Order.class, //
|
||||||
match(where("id").is(order.getId())), //
|
match(where("id").is(order.getId())), //
|
||||||
unwind("items"), //
|
unwind("items"), //
|
||||||
project("id", "customerId", "items") //
|
project("id", "customerId", "items") //
|
||||||
|
|||||||
@@ -15,17 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.aggregation;
|
package example.springdata.mongodb.aggregation;
|
||||||
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Value
|
public record OrdersPerCustomer(@Id String customerId, Long total) {
|
||||||
public class OrdersPerCustomer {
|
|
||||||
|
|
||||||
@Id //
|
|
||||||
private String customerId;
|
|
||||||
private Long total;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,33 +54,33 @@ public class OrderRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void createsInvoiceViaProgrammaticAggregation() {
|
public void createsInvoiceViaProgrammaticAggregation() {
|
||||||
|
|
||||||
Order order = new Order("c42", new Date()).//
|
var order = new Order("c42", new Date()).//
|
||||||
addItem(product1).addItem(product2).addItem(product3);
|
addItem(product1).addItem(product2).addItem(product3);
|
||||||
order = repository.save(order);
|
order = repository.save(order);
|
||||||
|
|
||||||
Invoice invoice = repository.getInvoiceFor(order);
|
var invoice = repository.getInvoiceFor(order);
|
||||||
|
|
||||||
assertThat(invoice).isNotNull();
|
assertThat(invoice).isNotNull();
|
||||||
assertThat(invoice.getOrderId()).isEqualTo(order.getId());
|
assertThat(invoice.orderId()).isEqualTo(order.getId());
|
||||||
assertThat(invoice.getNetAmount()).isCloseTo(8.3D, offset(0.00001));
|
assertThat(invoice.netAmount()).isCloseTo(8.3D, offset(0.00001));
|
||||||
assertThat(invoice.getTaxAmount()).isCloseTo(1.577D, offset(0.00001));
|
assertThat(invoice.taxAmount()).isCloseTo(1.577D, offset(0.00001));
|
||||||
assertThat(invoice.getTotalAmount()).isCloseTo(9.877, offset(0.00001));
|
assertThat(invoice.totalAmount()).isCloseTo(9.877, offset(0.00001));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createsInvoiceViaDeclarativeAggregation() {
|
public void createsInvoiceViaDeclarativeAggregation() {
|
||||||
|
|
||||||
Order order = new Order("c42", new Date()).//
|
var order = new Order("c42", new Date()).//
|
||||||
addItem(product1).addItem(product2).addItem(product3);
|
addItem(product1).addItem(product2).addItem(product3);
|
||||||
order = repository.save(order);
|
order = repository.save(order);
|
||||||
|
|
||||||
Invoice invoice = repository.aggregateInvoiceForOrder(order.getId());
|
var invoice = repository.aggregateInvoiceForOrder(order.getId());
|
||||||
|
|
||||||
assertThat(invoice).isNotNull();
|
assertThat(invoice).isNotNull();
|
||||||
assertThat(invoice.getOrderId()).isEqualTo(order.getId());
|
assertThat(invoice.orderId()).isEqualTo(order.getId());
|
||||||
assertThat(invoice.getNetAmount()).isCloseTo(8.3D, offset(0.00001));
|
assertThat(invoice.netAmount()).isCloseTo(8.3D, offset(0.00001));
|
||||||
assertThat(invoice.getTaxAmount()).isCloseTo(1.577D, offset(0.00001));
|
assertThat(invoice.taxAmount()).isCloseTo(1.577D, offset(0.00001));
|
||||||
assertThat(invoice.getTotalAmount()).isCloseTo(9.877, offset(0.00001));
|
assertThat(invoice.totalAmount()).isCloseTo(9.877, offset(0.00001));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ package example.springdata.mongodb.aggregation;
|
|||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -37,8 +33,6 @@ import org.springframework.core.io.ClassPathResource;
|
|||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.domain.Sort.Direction;
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators;
|
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators;
|
||||||
import org.springframework.data.mongodb.core.aggregation.ArrayOperators;
|
import org.springframework.data.mongodb.core.aggregation.ArrayOperators;
|
||||||
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.Granularities;
|
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.Granularities;
|
||||||
@@ -67,10 +61,10 @@ public class SpringBooksIntegrationTests {
|
|||||||
|
|
||||||
if (operations.count(new Query(), "books") == 0) {
|
if (operations.count(new Query(), "books") == 0) {
|
||||||
|
|
||||||
File file = new ClassPathResource("books.json").getFile();
|
var file = new ClassPathResource("books.json").getFile();
|
||||||
String content = Files.contentOf(file, StandardCharsets.UTF_8);
|
var content = Files.contentOf(file, StandardCharsets.UTF_8);
|
||||||
Document wrapper = Document.parse("{wrapper: " + content + "}");
|
var wrapper = Document.parse("{wrapper: " + content + "}");
|
||||||
List<Object> books = wrapper.getList("wrapper", Object.class);
|
var books = wrapper.getList("wrapper", Object.class);
|
||||||
|
|
||||||
operations.insert(books, "books");
|
operations.insert(books, "books");
|
||||||
}
|
}
|
||||||
@@ -82,11 +76,14 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveOrderedBookTitles() {
|
public void shouldRetrieveOrderedBookTitles() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
record BookTitle(String title) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var aggregation = newAggregation( //
|
||||||
sort(Direction.ASC, "volumeInfo.title"), //
|
sort(Direction.ASC, "volumeInfo.title"), //
|
||||||
project().and("volumeInfo.title").as("title"));
|
project().and("volumeInfo.title").as("title"));
|
||||||
|
|
||||||
AggregationResults<BookTitle> result = operations.aggregate(aggregation, "books", BookTitle.class);
|
var result = operations.aggregate(aggregation, "books", BookTitle.class);
|
||||||
|
|
||||||
assertThat(result.getMappedResults())//
|
assertThat(result.getMappedResults())//
|
||||||
.extracting("title")//
|
.extracting("title")//
|
||||||
@@ -99,13 +96,13 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveBooksPerPublisher() {
|
public void shouldRetrieveBooksPerPublisher() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
var aggregation = newAggregation( //
|
||||||
group("volumeInfo.publisher") //
|
group("volumeInfo.publisher") //
|
||||||
.count().as("count"), //
|
.count().as("count"), //
|
||||||
sort(Direction.DESC, "count"), //
|
sort(Direction.DESC, "count"), //
|
||||||
project("count").and("_id").as("publisher"));
|
project("count").and("_id").as("publisher"));
|
||||||
|
|
||||||
AggregationResults<BooksPerPublisher> result = operations.aggregate(aggregation, "books", BooksPerPublisher.class);
|
var result = operations.aggregate(aggregation, "books", BooksPerPublisher.class);
|
||||||
|
|
||||||
assertThat(result).hasSize(27);
|
assertThat(result).hasSize(27);
|
||||||
assertThat(result).extracting("publisher").containsSequence("Apress", "Packt Publishing Ltd");
|
assertThat(result).extracting("publisher").containsSequence("Apress", "Packt Publishing Ltd");
|
||||||
@@ -118,20 +115,20 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveBooksPerPublisherWithTitles() {
|
public void shouldRetrieveBooksPerPublisherWithTitles() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
var aggregation = newAggregation( //
|
||||||
group("volumeInfo.publisher") //
|
group("volumeInfo.publisher") //
|
||||||
.count().as("count") //
|
.count().as("count") //
|
||||||
.addToSet("volumeInfo.title").as("titles"), //
|
.addToSet("volumeInfo.title").as("titles"), //
|
||||||
sort(Direction.DESC, "count"), //
|
sort(Direction.DESC, "count"), //
|
||||||
project("count", "titles").and("_id").as("publisher"));
|
project("count", "titles").and("_id").as("publisher"));
|
||||||
|
|
||||||
AggregationResults<BooksPerPublisher> result = operations.aggregate(aggregation, "books", BooksPerPublisher.class);
|
var result = operations.aggregate(aggregation, "books", BooksPerPublisher.class);
|
||||||
|
|
||||||
BooksPerPublisher booksPerPublisher = result.getMappedResults().get(0);
|
var booksPerPublisher = result.getMappedResults().get(0);
|
||||||
|
|
||||||
assertThat(booksPerPublisher.getPublisher()).isEqualTo("Apress");
|
assertThat(booksPerPublisher.publisher()).isEqualTo("Apress");
|
||||||
assertThat(booksPerPublisher.getCount()).isEqualTo(26);
|
assertThat(booksPerPublisher.count()).isEqualTo(26);
|
||||||
assertThat(booksPerPublisher.getTitles()).contains("Expert Spring MVC and Web Flow", "Pro Spring Boot");
|
assertThat(booksPerPublisher.titles()).contains("Expert Spring MVC and Web Flow", "Pro Spring Boot");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,18 +137,18 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldRetrieveDataRelatedBooks() {
|
public void shouldRetrieveDataRelatedBooks() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
var aggregation = newAggregation( //
|
||||||
match(Criteria.where("volumeInfo.title").regex("data", "i")), //
|
match(Criteria.where("volumeInfo.title").regex("data", "i")), //
|
||||||
replaceRoot("volumeInfo"), //
|
replaceRoot("volumeInfo"), //
|
||||||
project("title", "authors"), //
|
project("title", "authors"), //
|
||||||
sort(Direction.ASC, "title"));
|
sort(Direction.ASC, "title"));
|
||||||
|
|
||||||
AggregationResults<BookAndAuthors> result = operations.aggregate(aggregation, "books", BookAndAuthors.class);
|
var result = operations.aggregate(aggregation, "books", BookAndAuthors.class);
|
||||||
|
|
||||||
BookAndAuthors bookAndAuthors = result.getMappedResults().get(1);
|
var bookAndAuthors = result.getMappedResults().get(1);
|
||||||
|
|
||||||
assertThat(bookAndAuthors.getTitle()).isEqualTo("Spring Data");
|
assertThat(bookAndAuthors.title()).isEqualTo("Spring Data");
|
||||||
assertThat(bookAndAuthors.getAuthors()).contains("Mark Pollack", "Oliver Gierke", "Thomas Risberg", "Jon Brisbin",
|
assertThat(bookAndAuthors.authors()).contains("Mark Pollack", "Oliver Gierke", "Thomas Risberg", "Jon Brisbin",
|
||||||
"Michael Hunger");
|
"Michael Hunger");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +158,10 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldRetrievePagesPerAuthor() {
|
public void shouldRetrievePagesPerAuthor() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
record PagesPerAuthor(@Id String author, int totalPageCount, int approxWritten) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var aggregation = newAggregation( //
|
||||||
match(Criteria.where("volumeInfo.authors").exists(true)), //
|
match(Criteria.where("volumeInfo.authors").exists(true)), //
|
||||||
replaceRoot("volumeInfo"), //
|
replaceRoot("volumeInfo"), //
|
||||||
project("authors", "pageCount") //
|
project("authors", "pageCount") //
|
||||||
@@ -174,13 +174,13 @@ public class SpringBooksIntegrationTests {
|
|||||||
.sum("pagesPerAuthor").as("approxWritten"), //
|
.sum("pagesPerAuthor").as("approxWritten"), //
|
||||||
sort(Direction.DESC, "totalPageCount"));
|
sort(Direction.DESC, "totalPageCount"));
|
||||||
|
|
||||||
AggregationResults<PagesPerAuthor> result = operations.aggregate(aggregation, "books", PagesPerAuthor.class);
|
var result = operations.aggregate(aggregation, "books", PagesPerAuthor.class);
|
||||||
|
|
||||||
PagesPerAuthor pagesPerAuthor = result.getMappedResults().get(0);
|
var pagesPerAuthor = result.getMappedResults().get(0);
|
||||||
|
|
||||||
assertThat(pagesPerAuthor.getAuthor()).isEqualTo("Josh Long");
|
assertThat(pagesPerAuthor.author()).isEqualTo("Josh Long");
|
||||||
assertThat(pagesPerAuthor.getTotalPageCount()).isEqualTo(1892);
|
assertThat(pagesPerAuthor.totalPageCount()).isEqualTo(1892);
|
||||||
assertThat(pagesPerAuthor.getApproxWritten()).isEqualTo(573);
|
assertThat(pagesPerAuthor.approxWritten()).isEqualTo(573);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,7 +189,7 @@ public class SpringBooksIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldCategorizeBooksInBuckets() {
|
public void shouldCategorizeBooksInBuckets() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
var aggregation = newAggregation( //
|
||||||
replaceRoot("volumeInfo"), //
|
replaceRoot("volumeInfo"), //
|
||||||
match(Criteria.where("pageCount").exists(true)),
|
match(Criteria.where("pageCount").exists(true)),
|
||||||
bucketAuto("pageCount", 10) //
|
bucketAuto("pageCount", 10) //
|
||||||
@@ -197,20 +197,20 @@ public class SpringBooksIntegrationTests {
|
|||||||
.andOutput("title").push().as("titles") //
|
.andOutput("title").push().as("titles") //
|
||||||
.andOutput("titles").count().as("count"));
|
.andOutput("titles").count().as("count"));
|
||||||
|
|
||||||
AggregationResults<BookFacetPerPage> result = operations.aggregate(aggregation, "books", BookFacetPerPage.class);
|
var result = operations.aggregate(aggregation, "books", BookFacetPerPage.class);
|
||||||
|
|
||||||
List<BookFacetPerPage> mappedResults = result.getMappedResults();
|
var mappedResults = result.getMappedResults();
|
||||||
|
|
||||||
BookFacetPerPage facet_20_to_100_pages = mappedResults.get(0);
|
var facet_20_to_100_pages = mappedResults.get(0);
|
||||||
assertThat(facet_20_to_100_pages.getId().getMin()).isEqualTo(20);
|
assertThat(facet_20_to_100_pages.id().min()).isEqualTo(20);
|
||||||
assertThat(facet_20_to_100_pages.getId().getMax()).isEqualTo(100);
|
assertThat(facet_20_to_100_pages.id().max()).isEqualTo(100);
|
||||||
assertThat(facet_20_to_100_pages.getCount()).isEqualTo(12);
|
assertThat(facet_20_to_100_pages.count()).isEqualTo(12);
|
||||||
|
|
||||||
BookFacetPerPage facet_100_to_500_pages = mappedResults.get(1);
|
var facet_100_to_500_pages = mappedResults.get(1);
|
||||||
assertThat(facet_100_to_500_pages.getId().getMin()).isEqualTo(100);
|
assertThat(facet_100_to_500_pages.id().min()).isEqualTo(100);
|
||||||
assertThat(facet_100_to_500_pages.getId().getMax()).isEqualTo(500);
|
assertThat(facet_100_to_500_pages.id().max()).isEqualTo(500);
|
||||||
assertThat(facet_100_to_500_pages.getCount()).isEqualTo(63);
|
assertThat(facet_100_to_500_pages.count()).isEqualTo(63);
|
||||||
assertThat(facet_100_to_500_pages.getTitles()).contains("Spring Data");
|
assertThat(facet_100_to_500_pages.titles()).contains("Spring Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -221,7 +221,7 @@ public class SpringBooksIntegrationTests {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void shouldCategorizeInMultipleFacetsByPriceAndAuthor() {
|
public void shouldCategorizeInMultipleFacetsByPriceAndAuthor() {
|
||||||
|
|
||||||
Aggregation aggregation = newAggregation( //
|
var aggregation = newAggregation( //
|
||||||
match(Criteria.where("volumeInfo.authors").exists(true).and("volumeInfo.publisher").exists(true)),
|
match(Criteria.where("volumeInfo.authors").exists(true).and("volumeInfo.publisher").exists(true)),
|
||||||
facet() //
|
facet() //
|
||||||
.and(match(Criteria.where("saleInfo.listPrice").exists(true)), //
|
.and(match(Criteria.where("saleInfo.listPrice").exists(true)), //
|
||||||
@@ -240,55 +240,23 @@ public class SpringBooksIntegrationTests {
|
|||||||
.andOutput("author").push().as("authors") //
|
.andOutput("author").push().as("authors") //
|
||||||
).as("authors"));
|
).as("authors"));
|
||||||
|
|
||||||
AggregationResults<Document> result = operations.aggregate(aggregation, "books", Document.class);
|
var result = operations.aggregate(aggregation, "books", Document.class);
|
||||||
|
|
||||||
Document uniqueMappedResult = result.getUniqueMappedResult();
|
var uniqueMappedResult = result.getUniqueMappedResult();
|
||||||
|
|
||||||
assertThat((List<Object>) uniqueMappedResult.get("prices")).hasSize(3);
|
assertThat((List<Object>) uniqueMappedResult.get("prices")).hasSize(3);
|
||||||
assertThat((List<Object>) uniqueMappedResult.get("authors")).hasSize(8);
|
assertThat((List<Object>) uniqueMappedResult.get("authors")).hasSize(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
record BooksPerPublisher(String publisher, int count, List<String> titles) {
|
||||||
@Getter
|
|
||||||
static class BookTitle {
|
|
||||||
String title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
record BookAndAuthors(String title, List<String> authors) {
|
||||||
@Getter
|
|
||||||
static class BooksPerPublisher {
|
|
||||||
String publisher;
|
|
||||||
int count;
|
|
||||||
List<String> titles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
record BookFacetPerPage(BookFacetPerPageId id, int count, List<String> titles) {
|
||||||
@Getter
|
|
||||||
static class BookAndAuthors {
|
|
||||||
String title;
|
|
||||||
List<String> authors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
record BookFacetPerPageId(int min, int max) {
|
||||||
@Getter
|
|
||||||
static class PagesPerAuthor {
|
|
||||||
@Id String author;
|
|
||||||
int totalPageCount;
|
|
||||||
int approxWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Getter
|
|
||||||
static class BookFacetPerPage {
|
|
||||||
BookFacetPerPageId id;
|
|
||||||
int count;
|
|
||||||
List<String> titles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Value
|
|
||||||
@Getter
|
|
||||||
static class BookFacetPerPageId {
|
|
||||||
int min;
|
|
||||||
int max;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class CollectingMessageListener<S, T> implements MessageListener<S, T> {
|
|||||||
|
|
||||||
void awaitNextMessages(int count) throws InterruptedException {
|
void awaitNextMessages(int count) throws InterruptedException {
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
messages.take();
|
messages.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb;
|
package example.springdata.mongodb;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
import org.springframework.data.mongodb.core.mapping.Field;
|
||||||
|
|
||||||
@@ -29,21 +28,8 @@ import org.springframework.data.mongodb.core.mapping.Field;
|
|||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Data
|
record Person(@Id ObjectId id, @Field("first_name") String firstname, @Field("last_name") String lastname, int age) {
|
||||||
class Person {
|
public Person(String firstname, String lastname, int age) {
|
||||||
|
this(null, firstname, lastname, age);
|
||||||
@Id ObjectId id;
|
|
||||||
|
|
||||||
@Field("first_name") private String firstname;
|
|
||||||
|
|
||||||
@Field("last_name") private String lastname;
|
|
||||||
|
|
||||||
private int age;
|
|
||||||
|
|
||||||
Person(String firstname, String lastname, int age) {
|
|
||||||
|
|
||||||
this.firstname = firstname;
|
|
||||||
this.lastname = lastname;
|
|
||||||
this.age = age;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ import static org.springframework.data.mongodb.core.query.Criteria.*;
|
|||||||
import static org.springframework.data.mongodb.core.query.Query.*;
|
import static org.springframework.data.mongodb.core.query.Query.*;
|
||||||
import static org.springframework.data.mongodb.core.query.Update.*;
|
import static org.springframework.data.mongodb.core.query.Update.*;
|
||||||
|
|
||||||
import com.mongodb.client.MongoClient;
|
|
||||||
import example.springdata.mongodb.util.EmbeddedMongo;
|
import example.springdata.mongodb.util.EmbeddedMongo;
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -32,13 +30,13 @@ import org.bson.Document;
|
|||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
|
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
|
||||||
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
|
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.mongodb.core.ChangeStreamEvent;
|
|
||||||
import org.springframework.data.mongodb.core.ChangeStreamOptions;
|
import org.springframework.data.mongodb.core.ChangeStreamOptions;
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
@@ -48,9 +46,9 @@ import org.springframework.data.mongodb.core.messaging.ChangeStreamRequest;
|
|||||||
import org.springframework.data.mongodb.core.messaging.DefaultMessageListenerContainer;
|
import org.springframework.data.mongodb.core.messaging.DefaultMessageListenerContainer;
|
||||||
import org.springframework.data.mongodb.core.messaging.Message;
|
import org.springframework.data.mongodb.core.messaging.Message;
|
||||||
import org.springframework.data.mongodb.core.messaging.MessageListenerContainer;
|
import org.springframework.data.mongodb.core.messaging.MessageListenerContainer;
|
||||||
import org.springframework.data.mongodb.core.messaging.Subscription;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import com.mongodb.client.MongoClient;
|
||||||
import com.mongodb.client.model.changestream.ChangeStreamDocument;
|
import com.mongodb.client.model.changestream.ChangeStreamDocument;
|
||||||
import com.mongodb.reactivestreams.client.MongoClients;
|
import com.mongodb.reactivestreams.client.MongoClients;
|
||||||
|
|
||||||
@@ -150,14 +148,14 @@ public class ChangeStreamsTests {
|
|||||||
@Test
|
@Test
|
||||||
public void imperativeChangeEvents() throws InterruptedException {
|
public void imperativeChangeEvents() throws InterruptedException {
|
||||||
|
|
||||||
CollectingMessageListener<ChangeStreamDocument<Document>, Person> messageListener = new CollectingMessageListener<>();
|
var messageListener = new CollectingMessageListener<ChangeStreamDocument<Document>, Person>();
|
||||||
|
|
||||||
ChangeStreamRequest<Person> request = ChangeStreamRequest.builder(messageListener) //
|
var request = ChangeStreamRequest.builder(messageListener) //
|
||||||
.collection("person") //
|
.collection("person") //
|
||||||
.filter(newAggregation(match(where("operationType").is("insert")))) // we are only interested in inserts
|
.filter(newAggregation(match(where("operationType").is("insert")))) // we are only interested in inserts
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Subscription subscription = container.register(request, Person.class);
|
var subscription = container.register(request, Person.class);
|
||||||
subscription.await(Duration.ofMillis(200)); // wait till the subscription becomes active
|
subscription.await(Duration.ofMillis(200)); // wait till the subscription becomes active
|
||||||
|
|
||||||
template.save(gabriel);
|
template.save(gabriel);
|
||||||
@@ -168,7 +166,7 @@ public class ChangeStreamsTests {
|
|||||||
assertThat(messageListener.messageCount()).isEqualTo(2); // first two insert events, so far so good
|
assertThat(messageListener.messageCount()).isEqualTo(2); // first two insert events, so far so good
|
||||||
|
|
||||||
template.update(Person.class) //
|
template.update(Person.class) //
|
||||||
.matching(query(where("id").is(ash.getId()))) //
|
.matching(query(where("id").is(ash.id()))) //
|
||||||
.apply(update("age", 40)) //
|
.apply(update("age", 40)) //
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
@@ -189,7 +187,7 @@ public class ChangeStreamsTests {
|
|||||||
@Test
|
@Test
|
||||||
public void reactiveChangeEvents() {
|
public void reactiveChangeEvents() {
|
||||||
|
|
||||||
Flux<ChangeStreamEvent<Person>> changeStream = reactiveTemplate.changeStream("person",
|
var changeStream = reactiveTemplate.changeStream("person",
|
||||||
ChangeStreamOptions.builder().filter(newAggregation(match(where("operationType").is("insert")))).build(),
|
ChangeStreamOptions.builder().filter(newAggregation(match(where("operationType").is("insert")))).build(),
|
||||||
Person.class);
|
Person.class);
|
||||||
|
|
||||||
@@ -207,7 +205,7 @@ public class ChangeStreamsTests {
|
|||||||
.then(() -> {
|
.then(() -> {
|
||||||
|
|
||||||
StepVerifier.create(reactiveTemplate.update(Person.class) //
|
StepVerifier.create(reactiveTemplate.update(Person.class) //
|
||||||
.matching(query(where("id").is(ash.getId()))) //
|
.matching(query(where("id").is(ash.id()))) //
|
||||||
.apply(update("age", 40)) //
|
.apply(update("age", 40)) //
|
||||||
.first()).expectNextCount(1).verifyComplete();
|
.first()).expectNextCount(1).verifyComplete();
|
||||||
}).expectNoEvent(Duration.ofMillis(200)) // updates are skipped
|
}).expectNoEvent(Duration.ofMillis(200)) // updates are skipped
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
|
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test configuration to connect to a MongoDB named "test" using a {@code MongoClient}. <br />
|
* Test configuration to connect to a MongoDB named "test" using a {@code MongoClient}. <br />
|
||||||
* Also enables Spring Data repositories for MongoDB.
|
* Also enables Spring Data repositories for MongoDB.
|
||||||
@@ -44,11 +43,29 @@ class ApplicationConfiguration {
|
|||||||
|
|
||||||
return (immutablePerson, collection) -> {
|
return (immutablePerson, collection) -> {
|
||||||
|
|
||||||
int randomNumber = ThreadLocalRandom.current().nextInt(1, 100);
|
var randomNumber = ThreadLocalRandom.current().nextInt(1, 100);
|
||||||
|
|
||||||
// withRandomNumber is a so called wither method returning a new instance of the entity with a new value assigned
|
// withRandomNumber is a so called wither method returning a new instance of the entity with a new value assigned
|
||||||
return immutablePerson.withRandomNumber(randomNumber);
|
return immutablePerson.withRandomNumber(randomNumber);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the {@link BeforeConvertCallback} used to update an {@link ImmutableRecord} before handing over the newly
|
||||||
|
* created instance to the actual mapping layer performing the conversion into the store native
|
||||||
|
* {@link org.bson.Document} representation.
|
||||||
|
*
|
||||||
|
* @return a {@link BeforeConvertCallback} for {@link ImmutablePerson}.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
BeforeConvertCallback<ImmutableRecord> beforeRecordConvertCallback() {
|
||||||
|
|
||||||
|
return (rec, collection) -> {
|
||||||
|
|
||||||
|
var randomNumber = ThreadLocalRandom.current().nextInt(1, 100);
|
||||||
|
|
||||||
|
return new ImmutableRecord(rec.id(), randomNumber);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package example.springdata.mongodb.immutable;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.experimental.Wither;
|
import lombok.With;
|
||||||
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ import org.bson.types.ObjectId;
|
|||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
@Wither
|
@With
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ImmutablePerson {
|
public class ImmutablePerson {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package example.springdata.mongodb.immutable;
|
||||||
|
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
|
record ImmutableRecord(ObjectId id, int randomNumber) {
|
||||||
|
}
|
||||||
@@ -15,15 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.projections;
|
package example.springdata.mongodb.projections;
|
||||||
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sample DTO only containing the firstname.
|
* A sample DTO only containing the firstname.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
@Value
|
record CustomerDto(String firstname) {
|
||||||
class CustomerDto {
|
|
||||||
|
|
||||||
String firstname;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,40 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.unwrapping;
|
package example.springdata.mongodb.unwrapping;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value object capturing the {@code email} address.
|
* Value object capturing the {@code email} address.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class Email { // might as well be a record type in more recent java versions
|
public record Email(String email) {
|
||||||
|
|
||||||
private final String email;
|
|
||||||
|
|
||||||
public Email(String email) {
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEmail() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
Email email1 = (Email) o;
|
|
||||||
return Objects.equals(email, email1.email);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(email);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class User {
|
|||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
User user = (User) o;
|
var user = (User) o;
|
||||||
return Objects.equals(id, user.id) &&
|
return Objects.equals(id, user.id) &&
|
||||||
Objects.equals(userName, user.userName) &&
|
Objects.equals(userName, user.userName) &&
|
||||||
Objects.equals(email, user.email);
|
Objects.equals(email, user.email);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class UserName { // might as well be a record type in more recent java ve
|
|||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
UserName userName = (UserName) o;
|
var userName = (UserName) o;
|
||||||
return Objects.equals(username, userName.username);
|
return Objects.equals(username, userName.username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,12 +71,12 @@ public class AdvancedIntegrationTests {
|
|||||||
// execute another finder without meta attributes that should not be picked up
|
// execute another finder without meta attributes that should not be picked up
|
||||||
repository.findByLastname(dave.getLastname(), Sort.by("firstname"));
|
repository.findByLastname(dave.getLastname(), Sort.by("firstname"));
|
||||||
|
|
||||||
FindIterable<Document> cursor = operations.getCollection(ApplicationConfiguration.SYSTEM_PROFILE_DB)
|
var cursor = operations.getCollection(ApplicationConfiguration.SYSTEM_PROFILE_DB)
|
||||||
.find(new BasicDBObject("query.$comment", AdvancedRepository.META_COMMENT));
|
.find(new BasicDBObject("query.$comment", AdvancedRepository.META_COMMENT));
|
||||||
|
|
||||||
for (Document document : cursor) {
|
for (var document : cursor) {
|
||||||
|
|
||||||
Document query = (Document) document.get("query");
|
var query = (Document) document.get("query");
|
||||||
assertThat(query).containsKey("foo");
|
assertThat(query).containsKey("foo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class ServersideScriptTests {
|
|||||||
@Ignore
|
@Ignore
|
||||||
public void complexScriptExecutionSimulatingPutIfAbsent() {
|
public void complexScriptExecutionSimulatingPutIfAbsent() {
|
||||||
|
|
||||||
Customer ned = new Customer("Ned", "Stark");
|
var ned = new Customer("Ned", "Stark");
|
||||||
ned.setId("ned-stark");
|
ned.setId("ned-stark");
|
||||||
|
|
||||||
// #1: on first insert null has to be returned
|
// #1: on first insert null has to be returned
|
||||||
@@ -94,14 +94,14 @@ public class ServersideScriptTests {
|
|||||||
|
|
||||||
private ExecutableMongoScript createExecutablePutIfAbsentScript(Customer customer) {
|
private ExecutableMongoScript createExecutablePutIfAbsentScript(Customer customer) {
|
||||||
|
|
||||||
String collectionName = operations.getCollectionName(Customer.class);
|
var collectionName = operations.getCollectionName(Customer.class);
|
||||||
Object id = operations.getConverter().getMappingContext().getRequiredPersistentEntity(Customer.class)
|
var id = operations.getConverter().getMappingContext().getRequiredPersistentEntity(Customer.class)
|
||||||
.getIdentifierAccessor(customer).getIdentifier();
|
.getIdentifierAccessor(customer).getIdentifier();
|
||||||
|
|
||||||
Document document = new Document();
|
var document = new Document();
|
||||||
operations.getConverter().write(customer, document);
|
operations.getConverter().write(customer, document);
|
||||||
|
|
||||||
String scriptString = String.format(
|
var scriptString = String.format(
|
||||||
"object = db.%1$s.findOne({\"_id\": \"%2$s\"}); if (object == null) { db.%1s.insert(%3$s); return null; } else { return object; }",
|
"object = db.%1$s.findOne({\"_id\": \"%2$s\"}); if (object == null) { db.%1s.insert(%3$s); return null; } else { return object; }",
|
||||||
collectionName, id, document);
|
collectionName, id, document);
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void setsIdOnSave() {
|
public void setsIdOnSave() {
|
||||||
|
|
||||||
Customer dave = repository.save(new Customer("Dave", "Matthews"));
|
var dave = repository.save(new Customer("Dave", "Matthews"));
|
||||||
assertThat(dave.getId(), is(notNullValue()));
|
assertThat(dave.getId(), is(notNullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void findCustomersUsingQuerydslSort() {
|
public void findCustomersUsingQuerydslSort() {
|
||||||
|
|
||||||
QCustomer customer = QCustomer.customer;
|
var customer = QCustomer.customer;
|
||||||
List<Customer> result = repository.findByLastname("Matthews", new QSort(customer.firstname.asc()));
|
var result = repository.findByLastname("Matthews", new QSort(customer.firstname.asc()));
|
||||||
|
|
||||||
assertThat(result, hasSize(2));
|
assertThat(result, hasSize(2));
|
||||||
assertThat(result.get(0), is(dave));
|
assertThat(result.get(0), is(dave));
|
||||||
@@ -89,7 +89,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void findCustomersAsStream() {
|
public void findCustomersAsStream() {
|
||||||
|
|
||||||
try (Stream<Customer> result = repository.findAllByCustomQueryWithStream()) {
|
try (var result = repository.findAllByCustomQueryWithStream()) {
|
||||||
result.forEach(System.out::println);
|
result.forEach(System.out::println);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,24 +100,24 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void exposesGeoSpatialFunctionality() {
|
public void exposesGeoSpatialFunctionality() {
|
||||||
|
|
||||||
GeospatialIndex indexDefinition = new GeospatialIndex("address.location");
|
var indexDefinition = new GeospatialIndex("address.location");
|
||||||
indexDefinition.getIndexOptions().put("min", -180);
|
indexDefinition.getIndexOptions().put("min", -180);
|
||||||
indexDefinition.getIndexOptions().put("max", 180);
|
indexDefinition.getIndexOptions().put("max", 180);
|
||||||
|
|
||||||
operations.indexOps(Customer.class).ensureIndex(indexDefinition);
|
operations.indexOps(Customer.class).ensureIndex(indexDefinition);
|
||||||
|
|
||||||
Customer ollie = new Customer("Oliver", "Gierke");
|
var ollie = new Customer("Oliver", "Gierke");
|
||||||
ollie.setAddress(new Address(new Point(52.52548, 13.41477)));
|
ollie.setAddress(new Address(new Point(52.52548, 13.41477)));
|
||||||
ollie = repository.save(ollie);
|
ollie = repository.save(ollie);
|
||||||
|
|
||||||
Point referenceLocation = new Point(52.51790, 13.41239);
|
var referenceLocation = new Point(52.51790, 13.41239);
|
||||||
Distance oneKilometer = new Distance(1, Metrics.KILOMETERS);
|
var oneKilometer = new Distance(1, Metrics.KILOMETERS);
|
||||||
|
|
||||||
GeoResults<Customer> result = repository.findByAddressLocationNear(referenceLocation, oneKilometer);
|
var result = repository.findByAddressLocationNear(referenceLocation, oneKilometer);
|
||||||
|
|
||||||
assertThat(result.getContent(), hasSize(1));
|
assertThat(result.getContent(), hasSize(1));
|
||||||
|
|
||||||
Distance distanceToFirstStore = result.getContent().get(0).getDistance();
|
var distanceToFirstStore = result.getContent().get(0).getDistance();
|
||||||
assertThat(distanceToFirstStore.getMetric(), is(Metrics.KILOMETERS));
|
assertThat(distanceToFirstStore.getMetric(), is(Metrics.KILOMETERS));
|
||||||
assertThat(distanceToFirstStore.getValue(), closeTo(0.862, 0.001));
|
assertThat(distanceToFirstStore.getValue(), closeTo(0.862, 0.001));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package example.springdata.mongodb.immutable;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -49,12 +50,29 @@ public class ImmutableEntityIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void setsRandomNumberOnSave() {
|
public void setsRandomNumberOnSave() {
|
||||||
|
|
||||||
ImmutablePerson unsaved = new ImmutablePerson();
|
var unsaved = new ImmutablePerson();
|
||||||
assertThat(unsaved.getRandomNumber()).isZero();
|
assertThat(unsaved.getRandomNumber()).isZero();
|
||||||
|
|
||||||
ImmutablePerson saved = operations.save(unsaved);
|
var saved = operations.save(unsaved);
|
||||||
|
|
||||||
assertThat(saved.getId()).isNotNull();
|
assertThat(saved.getId()).isNotNull();
|
||||||
assertThat(saved.getRandomNumber()).isNotZero();
|
assertThat(saved.getRandomNumber()).isNotZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case to show that automatically generated ids are assigned to the immutable domain object and how the
|
||||||
|
* {@link ImmutableRecord#getRandomNumber()} gets set via {@link ApplicationConfiguration#beforeConvertCallback()}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void setsRandomNumberOnSaveRecord() {
|
||||||
|
|
||||||
|
var unsaved = new ImmutableRecord(null, 0);
|
||||||
|
assertThat(unsaved.randomNumber()).isZero();
|
||||||
|
|
||||||
|
var saved = operations.save(unsaved);
|
||||||
|
|
||||||
|
assertThat(saved.id()).isNotNull();
|
||||||
|
assertThat(saved.randomNumber()).isNotZero();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void projectsEntityIntoInterface() {
|
public void projectsEntityIntoInterface() {
|
||||||
|
|
||||||
Collection<CustomerProjection> result = customers.findAllProjectedBy();
|
var result = customers.findAllProjectedBy();
|
||||||
|
|
||||||
assertThat(result, hasSize(2));
|
assertThat(result, hasSize(2));
|
||||||
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
||||||
@@ -72,16 +72,16 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void projectsToDto() {
|
public void projectsToDto() {
|
||||||
|
|
||||||
Collection<CustomerDto> result = customers.findAllDtoedBy();
|
var result = customers.findAllDtoedBy();
|
||||||
|
|
||||||
assertThat(result, hasSize(2));
|
assertThat(result, hasSize(2));
|
||||||
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
assertThat(result.iterator().next().firstname(), is("Dave"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void projectsDynamically() {
|
public void projectsDynamically() {
|
||||||
|
|
||||||
Collection<CustomerProjection> result = customers.findByFirstname("Dave", CustomerProjection.class);
|
var result = customers.findByFirstname("Dave", CustomerProjection.class);
|
||||||
|
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
||||||
@@ -90,7 +90,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void projectsIndividualDynamically() {
|
public void projectsIndividualDynamically() {
|
||||||
|
|
||||||
CustomerSummary result = customers.findProjectedById(dave.getId(), CustomerSummary.class);
|
var result = customers.findProjectedById(dave.getId(), CustomerSummary.class);
|
||||||
|
|
||||||
assertThat(result, is(notNullValue()));
|
assertThat(result, is(notNullValue()));
|
||||||
assertThat(result.getFullName(), is("Dave Matthews"));
|
assertThat(result.getFullName(), is("Dave Matthews"));
|
||||||
@@ -102,7 +102,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void projectIndividualInstance() {
|
public void projectIndividualInstance() {
|
||||||
|
|
||||||
CustomerProjection result = customers.findProjectedById(dave.getId());
|
var result = customers.findProjectedById(dave.getId());
|
||||||
|
|
||||||
assertThat(result, is(notNullValue()));
|
assertThat(result, is(notNullValue()));
|
||||||
assertThat(result.getFirstname(), is("Dave"));
|
assertThat(result.getFirstname(), is("Dave"));
|
||||||
@@ -112,7 +112,7 @@ public class CustomerRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void supportsProjectionInCombinationWithPagination() {
|
public void supportsProjectionInCombinationWithPagination() {
|
||||||
|
|
||||||
Page<CustomerProjection> page = customers
|
var page = customers
|
||||||
.findPagedProjectedBy(PageRequest.of(0, 1, Sort.by(Direction.ASC, "lastname")));
|
.findPagedProjectedBy(PageRequest.of(0, 1, Sort.by(Direction.ASC, "lastname")));
|
||||||
|
|
||||||
assertThat(page.getContent().get(0).getFirstname(), is("Carter"));
|
assertThat(page.getContent().get(0).getFirstname(), is("Carter"));
|
||||||
|
|||||||
@@ -53,13 +53,13 @@ class UnwrappingIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
void documentStructure() {
|
void documentStructure() {
|
||||||
|
|
||||||
org.bson.Document stored = operations.execute(User.class, collection -> {
|
var stored = operations.execute(User.class, collection -> {
|
||||||
return collection.find(Filters.eq("_id", rogelio.getId())).first();
|
return collection.find(Filters.eq("_id", rogelio.getId())).first();
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(stored).containsAllEntriesOf(new Document("_id", rogelio.getId())
|
assertThat(stored).containsAllEntriesOf(new Document("_id", rogelio.getId())
|
||||||
.append("username", rogelio.getUserName().getUsername())
|
.append("username", rogelio.getUserName().getUsername())
|
||||||
.append("primary_email", rogelio.getEmail().getEmail())
|
.append("primary_email", rogelio.getEmail().email())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +77,6 @@ class UnwrappingIntegrationTests {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void queryViaPropertyOfValueType() {
|
void queryViaPropertyOfValueType() {
|
||||||
assertThat(repository.findByEmailEmail(jane.getEmail().getEmail())).isEqualTo(jane);
|
assertThat(repository.findByEmailEmail(jane.getEmail().email())).isEqualTo(jane);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.fluent;
|
package example.springdata.mongodb.fluent;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Data
|
record Human(String firstname, String lastname) {
|
||||||
class Human {
|
|
||||||
|
|
||||||
final String firstname;
|
|
||||||
final String lastname;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.fluent;
|
package example.springdata.mongodb.fluent;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.geo.Point;
|
import org.springframework.data.geo.Point;
|
||||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
||||||
@@ -24,9 +22,6 @@ import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
|
|||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Data
|
public record Planet(@Id String name, @GeoSpatialIndexed Point coordinates) {
|
||||||
public class Planet {
|
|
||||||
|
|
||||||
final @Id String name;
|
|
||||||
final @GeoSpatialIndexed Point coordinates;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,30 +40,30 @@ public class ApplicationConfiguration {
|
|||||||
template.dropCollection(COLLECTION);
|
template.dropCollection(COLLECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeospatialIndex index = new GeospatialIndex("homePlanet.coordinates") //
|
var index = new GeospatialIndex("homePlanet.coordinates") //
|
||||||
.typed(GeoSpatialIndexType.GEO_2DSPHERE) //
|
.typed(GeoSpatialIndexType.GEO_2DSPHERE) //
|
||||||
.named("planet-coordinate-idx");
|
.named("planet-coordinate-idx");
|
||||||
|
|
||||||
template.createCollection(COLLECTION);
|
template.createCollection(COLLECTION);
|
||||||
template.indexOps(SWCharacter.class).ensureIndex(index);
|
template.indexOps(SWCharacter.class).ensureIndex(index);
|
||||||
|
|
||||||
Planet alderaan = new Planet("alderaan", new Point(-73.9667, 40.78));
|
var alderaan = new Planet("alderaan", new Point(-73.9667, 40.78));
|
||||||
Planet stewjon = new Planet("stewjon", new Point(-73.9836, 40.7538));
|
var stewjon = new Planet("stewjon", new Point(-73.9836, 40.7538));
|
||||||
Planet tatooine = new Planet("tatooine", new Point(-73.9928, 40.7193));
|
var tatooine = new Planet("tatooine", new Point(-73.9928, 40.7193));
|
||||||
|
|
||||||
Jedi anakin = new Jedi("anakin", "skywalker");
|
var anakin = new Jedi("anakin", "skywalker");
|
||||||
anakin.setHomePlanet(tatooine);
|
anakin.setHomePlanet(tatooine);
|
||||||
|
|
||||||
Jedi luke = new Jedi("luke", "skywalker");
|
var luke = new Jedi("luke", "skywalker");
|
||||||
luke.setHomePlanet(tatooine);
|
luke.setHomePlanet(tatooine);
|
||||||
|
|
||||||
Jedi leia = new Jedi("leia", "organa");
|
var leia = new Jedi("leia", "organa");
|
||||||
leia.setHomePlanet(alderaan);
|
leia.setHomePlanet(alderaan);
|
||||||
|
|
||||||
Jedi obiWan = new Jedi("obi-wan", "kenobi");
|
var obiWan = new Jedi("obi-wan", "kenobi");
|
||||||
obiWan.setHomePlanet(stewjon);
|
obiWan.setHomePlanet(stewjon);
|
||||||
|
|
||||||
Human han = new Human("han", "solo");
|
var han = new Human("han", "solo");
|
||||||
|
|
||||||
template.save(anakin, COLLECTION);
|
template.save(anakin, COLLECTION);
|
||||||
template.save(luke, COLLECTION);
|
template.save(luke, COLLECTION);
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class FluentMongoApiTests {
|
|||||||
@Test
|
@Test
|
||||||
public void fetchInterfaceProjection() {
|
public void fetchInterfaceProjection() {
|
||||||
|
|
||||||
Sith anakin = mongoOps.query(SWCharacter.class) // SWCharacter does only define the collection, id and name
|
var anakin = mongoOps.query(SWCharacter.class) // SWCharacter does only define the collection, id and name
|
||||||
.as(Sith.class) // use an interface as return type to create a projection
|
.as(Sith.class) // use an interface as return type to create a projection
|
||||||
.matching(query(where("firstname").is("anakin"))) // so properties are taken as is
|
.matching(query(where("firstname").is("anakin"))) // so properties are taken as is
|
||||||
.oneValue();
|
.oneValue();
|
||||||
@@ -179,7 +179,7 @@ public class FluentMongoApiTests {
|
|||||||
@Test
|
@Test
|
||||||
public void geoNearQuery() {
|
public void geoNearQuery() {
|
||||||
|
|
||||||
GeoResults<Jedi> results = mongoOps.query(SWCharacter.class) // SWCharacter defines collection, id and name
|
var results = mongoOps.query(SWCharacter.class) // SWCharacter defines collection, id and name
|
||||||
.as(Jedi.class) // but we want to map the results to Jedi
|
.as(Jedi.class) // but we want to map the results to Jedi
|
||||||
.near(alderaanWithin3Parsecs) // and find those with home planet near alderaan
|
.near(alderaanWithin3Parsecs) // and find those with home planet near alderaan
|
||||||
.all();
|
.all();
|
||||||
@@ -204,7 +204,7 @@ public class FluentMongoApiTests {
|
|||||||
@Test
|
@Test
|
||||||
public void querySpecificCollection() {
|
public void querySpecificCollection() {
|
||||||
|
|
||||||
List<Human> skywalkers = mongoOps.query(Human.class) // Human does not define a collection via @Document
|
var skywalkers = mongoOps.query(Human.class) // Human does not define a collection via @Document
|
||||||
.inCollection("star-wars") // so we set an explicit collection name
|
.inCollection("star-wars") // so we set an explicit collection name
|
||||||
.matching(query(where("lastname").is("skywalker"))) // to find all documents with a matching "lastname"
|
.matching(query(where("lastname").is("skywalker"))) // to find all documents with a matching "lastname"
|
||||||
.all();
|
.all();
|
||||||
@@ -218,7 +218,7 @@ public class FluentMongoApiTests {
|
|||||||
@Test
|
@Test
|
||||||
public void justInsertOne() {
|
public void justInsertOne() {
|
||||||
|
|
||||||
SWCharacter chewbacca = new SWCharacter("Chewbacca");
|
var chewbacca = new SWCharacter("Chewbacca");
|
||||||
|
|
||||||
mongoOps.insert(SWCharacter.class).one(chewbacca);
|
mongoOps.insert(SWCharacter.class).one(chewbacca);
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@ public class FluentMongoApiTests {
|
|||||||
@Test
|
@Test
|
||||||
public void updateAndUpsert() {
|
public void updateAndUpsert() {
|
||||||
|
|
||||||
UpdateResult result = mongoOps.update(Jedi.class) // Jedi defines the collection and field mapping
|
var result = mongoOps.update(Jedi.class) // Jedi defines the collection and field mapping
|
||||||
.matching(query(where("lastname").is("windu"))) // so "last" maps to "lastname".
|
.matching(query(where("lastname").is("windu"))) // so "last" maps to "lastname".
|
||||||
.apply(update("name", "mence")) // We'll update the "firstname" to "mence"
|
.apply(update("name", "mence")) // We'll update the "firstname" to "mence"
|
||||||
.upsert(); // and add a new document if it does not exist already.
|
.upsert(); // and add a new document if it does not exist already.
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ public class ApplicationConfiguration {
|
|||||||
*/
|
*/
|
||||||
public @Bean AbstractRepositoryPopulatorFactoryBean repositoryPopulator() {
|
public @Bean AbstractRepositoryPopulatorFactoryBean repositoryPopulator() {
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
var mapper = new ObjectMapper();
|
||||||
mapper.addMixIn(GeoJsonPoint.class, GeoJsonPointMixin.class);
|
mapper.addMixIn(GeoJsonPoint.class, GeoJsonPointMixin.class);
|
||||||
mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
Jackson2RepositoryPopulatorFactoryBean factoryBean = new Jackson2RepositoryPopulatorFactoryBean();
|
var factoryBean = new Jackson2RepositoryPopulatorFactoryBean();
|
||||||
factoryBean.setResources(new Resource[] { new ClassPathResource("starbucks-in-nyc.json") });
|
factoryBean.setResources(new Resource[] { new ClassPathResource("starbucks-in-nyc.json") });
|
||||||
factoryBean.setMapper(mapper);
|
factoryBean.setMapper(mapper);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.geojson;
|
package example.springdata.mongodb.geojson;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Value;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
@@ -23,26 +23,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@Document(collection = "starbucks")
|
@Document(collection = "starbucks")
|
||||||
public class Store {
|
public record Store(String id, String name, String street, String city, GeoJsonPoint location) {
|
||||||
|
|
||||||
String id;
|
|
||||||
String name;
|
|
||||||
String street;
|
|
||||||
String city;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code location} is stored in GeoJSON format.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* <code>
|
|
||||||
* {
|
|
||||||
* "type" : "Point",
|
|
||||||
* "coordinates" : [ x, y ]
|
|
||||||
* }
|
|
||||||
* </code>
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
GeoJsonPoint location;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,11 +114,11 @@ public class StoreRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findStoresThatIntersectGivenPolygon() {
|
public void findStoresThatIntersectGivenPolygon() {
|
||||||
|
|
||||||
Document geoJsonDbo = new Document();
|
var geoJsonDbo = new Document();
|
||||||
|
|
||||||
operations.getConverter().write(GEO_JSON_POLYGON, geoJsonDbo);
|
operations.getConverter().write(GEO_JSON_POLYGON, geoJsonDbo);
|
||||||
|
|
||||||
BasicQuery bq = new BasicQuery(
|
var bq = new BasicQuery(
|
||||||
new Document("location", new Document("$geoIntersects", new Document("$geometry", geoJsonDbo))));
|
new Document("location", new Document("$geoIntersects", new Document("$geometry", geoJsonDbo))));
|
||||||
|
|
||||||
operations.find(bq, Store.class).forEach(System.out::println);
|
operations.find(bq, Store.class).forEach(System.out::println);
|
||||||
|
|||||||
@@ -15,25 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.gridfs;
|
package example.springdata.mongodb.gridfs;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hartmut Lang
|
* @author Hartmut Lang
|
||||||
*/
|
*/
|
||||||
@Data
|
public record Customer(String firstName, String lastName) {
|
||||||
@NoArgsConstructor
|
|
||||||
public class Customer {
|
|
||||||
|
|
||||||
@Id private String id;
|
|
||||||
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
|
|
||||||
public Customer(String firstName, String lastName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class GridFsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get file or resource by filename
|
// get file or resource by filename
|
||||||
GridFSFile file = gridFsOperations.findOne(query(whereFilename().is("example-file.txt")));
|
var file = gridFsOperations.findOne(query(whereFilename().is("example-file.txt")));
|
||||||
|
|
||||||
assertThat(file.getFilename()).isEqualTo("example-file.txt");
|
assertThat(file.getFilename()).isEqualTo("example-file.txt");
|
||||||
}
|
}
|
||||||
@@ -76,12 +76,12 @@ public class GridFsTests {
|
|||||||
try (InputStream is = new BufferedInputStream(new ClassPathResource("./example-file.txt").getInputStream())) {
|
try (InputStream is = new BufferedInputStream(new ClassPathResource("./example-file.txt").getInputStream())) {
|
||||||
|
|
||||||
// store file with metaData
|
// store file with metaData
|
||||||
Customer customerMetaData = new Customer("Hardy", "Lang");
|
var customerMetaData = new Customer("Hardy", "Lang");
|
||||||
gridFsOperations.store(is, "example-file.txt", customerMetaData);
|
gridFsOperations.store(is, "example-file.txt", customerMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// search by metaData
|
// search by metaData
|
||||||
GridFSFile file = gridFsOperations.findOne(query(whereMetaData("firstName").is("Hardy")));
|
var file = gridFsOperations.findOne(query(whereMetaData("firstName").is("Hardy")));
|
||||||
assertThat(file.getFilename()).isEqualTo("example-file.txt");
|
assertThat(file.getFilename()).isEqualTo("example-file.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,10 +96,10 @@ public class GridFsTests {
|
|||||||
// store file
|
// store file
|
||||||
gridFsOperations.store(new ByteArrayInputStream(bytes), "example-file.txt");
|
gridFsOperations.store(new ByteArrayInputStream(bytes), "example-file.txt");
|
||||||
|
|
||||||
GridFsResource resource = gridFsOperations.getResource("example-file.txt");
|
var resource = gridFsOperations.getResource("example-file.txt");
|
||||||
|
|
||||||
byte[] loaded;
|
byte[] loaded;
|
||||||
try (InputStream is = resource.getInputStream()) {
|
try (var is = resource.getInputStream()) {
|
||||||
loaded = StreamUtils.copyToByteArray(is);
|
loaded = StreamUtils.copyToByteArray(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.customer;
|
package example.springdata.mongodb.customer;
|
||||||
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import org.jmolecules.ddd.annotation.ValueObject;
|
import org.jmolecules.ddd.annotation.ValueObject;
|
||||||
|
|
||||||
@Value
|
|
||||||
@ValueObject
|
@ValueObject
|
||||||
public class Address {
|
public record Address(String street, String city, String zipCode) {
|
||||||
private final String street, city, zipCode;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.order;
|
package example.springdata.mongodb.order;
|
||||||
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import org.jmolecules.ddd.annotation.ValueObject;
|
import org.jmolecules.ddd.annotation.ValueObject;
|
||||||
|
|
||||||
@Value
|
|
||||||
@ValueObject
|
@ValueObject
|
||||||
public class LineItem {
|
public record LineItem(String description) {
|
||||||
String description;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class Order implements AggregateRoot<Order, Order.OrderId> {
|
|||||||
|
|
||||||
public Order addLineItem(String description) {
|
public Order addLineItem(String description) {
|
||||||
|
|
||||||
LineItem item = new LineItem(description);
|
var item = new LineItem(description);
|
||||||
|
|
||||||
this.lineItems.add(item);
|
this.lineItems.add(item);
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public class Order implements AggregateRoot<Order, Order.OrderId> {
|
|||||||
@Value(staticConstructor = "of")
|
@Value(staticConstructor = "of")
|
||||||
public static class OrderId implements Identifier {
|
public static class OrderId implements Identifier {
|
||||||
|
|
||||||
private final UUID orderId;
|
UUID orderId;
|
||||||
|
|
||||||
public static OrderId create() {
|
public static OrderId create() {
|
||||||
return OrderId.of(UUID.randomUUID());
|
return OrderId.of(UUID.randomUUID());
|
||||||
|
|||||||
@@ -25,11 +25,10 @@ import example.springdata.mongodb.order.Orders;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Oliver Drotbohm
|
* @author Oliver Drotbohm
|
||||||
@@ -43,9 +42,9 @@ class ApplicationIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
void exposesAssociationInMetamodel() {
|
void exposesAssociationInMetamodel() {
|
||||||
|
|
||||||
MongoMappingContext mapping = context.getBean(MongoMappingContext.class);
|
var mapping = context.getBean(MongoMappingContext.class);
|
||||||
MongoPersistentEntity<?> entity = mapping.getRequiredPersistentEntity(Order.class);
|
var entity = mapping.getRequiredPersistentEntity(Order.class);
|
||||||
MongoPersistentProperty customer = entity.getRequiredPersistentProperty("customer");
|
var customer = entity.getRequiredPersistentProperty("customer");
|
||||||
|
|
||||||
assertThat(customer.isAssociation()).isTrue();
|
assertThat(customer.isAssociation()).isTrue();
|
||||||
}
|
}
|
||||||
@@ -53,19 +52,19 @@ class ApplicationIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
void persistsDomainModel() {
|
void persistsDomainModel() {
|
||||||
|
|
||||||
Address address = new Address("41 Greystreet", "Dreaming Tree", "2731");
|
var address = new Address("41 Greystreet", "Dreaming Tree", "2731");
|
||||||
|
|
||||||
Customers customers = context.getBean(Customers.class);
|
var customers = context.getBean(Customers.class);
|
||||||
Customer customer = customers.save(new Customer("Dave", "Matthews", address));
|
var customer = customers.save(new Customer("Dave", "Matthews", address));
|
||||||
|
|
||||||
Orders orders = context.getBean(Orders.class);
|
var orders = context.getBean(Orders.class);
|
||||||
|
|
||||||
Order order = new Order(customer)
|
var order = new Order(customer)
|
||||||
.addLineItem("Foo")
|
.addLineItem("Foo")
|
||||||
.addLineItem("Bar");
|
.addLineItem("Bar");
|
||||||
|
|
||||||
Order result = orders.save(order);
|
var result = orders.save(order);
|
||||||
|
|
||||||
assertThat(customers.resolveRequired(result.getCustomer()));
|
assertThat(customers.resolveRequired(result.getCustomer())).isNotNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class ContactRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void countByConcreteSubtypeExample() {
|
public void countByConcreteSubtypeExample() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person(null, null, null));
|
var example = Example.of(new Person(null, null, null));
|
||||||
|
|
||||||
assertThat(userRepository.count(example), is(3L));
|
assertThat(userRepository.count(example), is(3L));
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ public class ContactRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllPersonsBySimpleExample() {
|
public void findAllPersonsBySimpleExample() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person(".*", null, null), //
|
var example = Example.of(new Person(".*", null, null), //
|
||||||
matching().withStringMatcher(StringMatcher.REGEX));
|
matching().withStringMatcher(StringMatcher.REGEX));
|
||||||
|
|
||||||
assertThat(userRepository.findAll(example), containsInAnyOrder(skyler, walter, flynn));
|
assertThat(userRepository.findAll(example), containsInAnyOrder(skyler, walter, flynn));
|
||||||
@@ -92,7 +92,7 @@ public class ContactRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllRelativesBySimpleExample() {
|
public void findAllRelativesBySimpleExample() {
|
||||||
|
|
||||||
Example<Relative> example = Example.of(new Relative(".*", null, null), //
|
var example = Example.of(new Relative(".*", null, null), //
|
||||||
matching().withStringMatcher(StringMatcher.REGEX));
|
matching().withStringMatcher(StringMatcher.REGEX));
|
||||||
|
|
||||||
assertThat(contactRepository.findAll(example), containsInAnyOrder(hank, marie));
|
assertThat(contactRepository.findAll(example), containsInAnyOrder(hank, marie));
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void ignoreNullProperties() {
|
public void ignoreNullProperties() {
|
||||||
|
|
||||||
Query query = query(byExample(new Person(null, null, 17)));
|
var query = query(byExample(new Person(null, null, 17)));
|
||||||
|
|
||||||
assertThat(operations.find(query, Person.class), hasItems(flynn));
|
assertThat(operations.find(query, Person.class), hasItems(flynn));
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void substringMatching() {
|
public void substringMatching() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("er", null, null), matching().//
|
var example = Example.of(new Person("er", null, null), matching().//
|
||||||
withStringMatcher(StringMatcher.ENDING));
|
withStringMatcher(StringMatcher.ENDING));
|
||||||
|
|
||||||
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
|
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
|
||||||
@@ -99,8 +99,8 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void regexMatching() {
|
public void regexMatching() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("(Skyl|Walt)er", null, null), matching().//
|
var example = Example.of(new Person("(Skyl|Walt)er", null, null), matching().//
|
||||||
withMatcher("firstname", matcher -> matcher.regex()));
|
withMatcher("firstname", GenericPropertyMatcher::regex));
|
||||||
|
|
||||||
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
|
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(skyler, walter));
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void matchStartingStringsIgnoreCase() {
|
public void matchStartingStringsIgnoreCase() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
var example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
||||||
withIgnorePaths("age").//
|
withIgnorePaths("age").//
|
||||||
withMatcher("firstname", startsWith()).//
|
withMatcher("firstname", startsWith()).//
|
||||||
withMatcher("lastname", ignoreCase()));
|
withMatcher("lastname", ignoreCase()));
|
||||||
@@ -125,10 +125,10 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void configuringMatchersUsingLambdas() {
|
public void configuringMatchersUsingLambdas() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("Walter", "WHITE", null), matching().//
|
var example = Example.of(new Person("Walter", "WHITE", null), matching().//
|
||||||
withIgnorePaths("age"). //
|
withIgnorePaths("age"). //
|
||||||
withMatcher("firstname", matcher -> matcher.startsWith()). //
|
withMatcher("firstname", GenericPropertyMatcher::startsWith). //
|
||||||
withMatcher("lastname", matcher -> matcher.ignoreCase()));
|
withMatcher("lastname", GenericPropertyMatcher::ignoreCase));
|
||||||
|
|
||||||
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(flynn, walter));
|
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(flynn, walter));
|
||||||
}
|
}
|
||||||
@@ -139,8 +139,8 @@ public class MongoOperationsIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void valueTransformer() {
|
public void valueTransformer() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person(null, "White", 99), matching(). //
|
var example = Example.of(new Person(null, "White", 99), matching(). //
|
||||||
withMatcher("age", matcher -> matcher.transform(value -> Optional.of(Integer.valueOf(50)))));
|
withMatcher("age", matcher -> matcher.transform(value -> Optional.of(50))));
|
||||||
|
|
||||||
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(walter));
|
assertThat(operations.find(query(byExample(example)), Person.class), hasItems(walter));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void countBySimpleExample() {
|
public void countBySimpleExample() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person(null, "White", null));
|
var example = Example.of(new Person(null, "White", null));
|
||||||
|
|
||||||
assertThat(repository.count(example)).isEqualTo(3L);
|
assertThat(repository.count(example)).isEqualTo(3L);
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void ignorePropertiesAndMatchByAge() {
|
public void ignorePropertiesAndMatchByAge() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(flynn, matching(). //
|
var example = Example.of(flynn, matching(). //
|
||||||
withIgnorePaths("firstname", "lastname"));
|
withIgnorePaths("firstname", "lastname"));
|
||||||
|
|
||||||
assertThat(repository.findOne(example)).contains(flynn);
|
assertThat(repository.findOne(example)).contains(flynn);
|
||||||
@@ -87,7 +87,7 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void substringMatching() {
|
public void substringMatching() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("er", null, null), matching(). //
|
var example = Example.of(new Person("er", null, null), matching(). //
|
||||||
withStringMatcher(StringMatcher.ENDING));
|
withStringMatcher(StringMatcher.ENDING));
|
||||||
|
|
||||||
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(skyler, walter);
|
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(skyler, walter);
|
||||||
@@ -99,8 +99,8 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void regexMatching() {
|
public void regexMatching() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("(Skyl|Walt)er", null, null), matching(). //
|
var example = Example.of(new Person("(Skyl|Walt)er", null, null), matching(). //
|
||||||
withMatcher("firstname", matcher -> matcher.regex()));
|
withMatcher("firstname", GenericPropertyMatcher::regex));
|
||||||
|
|
||||||
assertThat(repository.findAll(example)).contains(skyler, walter);
|
assertThat(repository.findAll(example)).contains(skyler, walter);
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void matchStartingStringsIgnoreCase() {
|
public void matchStartingStringsIgnoreCase() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
var example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
||||||
withIgnorePaths("age"). //
|
withIgnorePaths("age"). //
|
||||||
withMatcher("firstname", startsWith()). //
|
withMatcher("firstname", startsWith()). //
|
||||||
withMatcher("lastname", ignoreCase()));
|
withMatcher("lastname", ignoreCase()));
|
||||||
@@ -125,10 +125,10 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void configuringMatchersUsingLambdas() {
|
public void configuringMatchersUsingLambdas() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
var example = Example.of(new Person("Walter", "WHITE", null), matching(). //
|
||||||
withIgnorePaths("age"). //
|
withIgnorePaths("age"). //
|
||||||
withMatcher("firstname", matcher -> matcher.startsWith()). //
|
withMatcher("firstname", GenericPropertyMatcher::startsWith). //
|
||||||
withMatcher("lastname", matcher -> matcher.ignoreCase()));
|
withMatcher("lastname", GenericPropertyMatcher::ignoreCase));
|
||||||
|
|
||||||
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(flynn, walter);
|
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(flynn, walter);
|
||||||
}
|
}
|
||||||
@@ -139,8 +139,8 @@ public class UserRepositoryIntegrationTests {
|
|||||||
@Test
|
@Test
|
||||||
public void valueTransformer() {
|
public void valueTransformer() {
|
||||||
|
|
||||||
Example<Person> example = Example.of(new Person(null, "White", 99), matching(). //
|
var example = Example.of(new Person(null, "White", 99), matching(). //
|
||||||
withMatcher("age", matcher -> matcher.transform(value -> Optional.of(Integer.valueOf(50)))));
|
withMatcher("age", matcher -> matcher.transform(value -> Optional.of(50))));
|
||||||
|
|
||||||
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(walter);
|
assertThat(repository.findAll(example)).containsExactlyInAnyOrder(walter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class Customer {
|
|||||||
if (o == null || getClass() != o.getClass())
|
if (o == null || getClass() != o.getClass())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Customer customer = (Customer) o;
|
var customer = (Customer) o;
|
||||||
|
|
||||||
if (id != null ? !id.equals(customer.id) : customer.id != null)
|
if (id != null ? !id.equals(customer.id) : customer.id != null)
|
||||||
return false;
|
return false;
|
||||||
@@ -91,7 +91,7 @@ public class Customer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = id != null ? id.hashCode() : 0;
|
var result = id != null ? id.hashCode() : 0;
|
||||||
result = 31 * result + (firstname != null ? firstname.hashCode() : 0);
|
result = 31 * result + (firstname != null ? firstname.hashCode() : 0);
|
||||||
result = 31 * result + (lastname != null ? lastname.hashCode() : 0);
|
result = 31 * result + (lastname != null ? lastname.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -15,10 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.people;
|
package example.springdata.mongodb.people;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,13 +24,14 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Document
|
@Document
|
||||||
public class Person {
|
public record Person(@Id String id, String firstname, String lastname, int age) {
|
||||||
|
|
||||||
private @Id String id;
|
@PersistenceConstructor
|
||||||
private final String firstname;
|
public Person {
|
||||||
private final String lastname;
|
}
|
||||||
private final int age;
|
|
||||||
|
public Person(String firstname, String lastname, int age) {
|
||||||
|
this(null, firstname, lastname, age);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ReactiveMongoTemplateIntegrationTest {
|
|||||||
|
|
||||||
StepVerifier.create(template.dropCollection(Person.class)).verifyComplete();
|
StepVerifier.create(template.dropCollection(Person.class)).verifyComplete();
|
||||||
|
|
||||||
Flux<Person> insertAll = template
|
var insertAll = template
|
||||||
.insertAll(Flux.just(new Person("Walter", "White", 50), //
|
.insertAll(Flux.just(new Person("Walter", "White", 50), //
|
||||||
new Person("Skyler", "White", 45), //
|
new Person("Skyler", "White", 45), //
|
||||||
new Person("Saul", "Goodman", 42), //
|
new Person("Saul", "Goodman", 42), //
|
||||||
@@ -66,7 +66,7 @@ public class ReactiveMongoTemplateIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldInsertAndCountData() {
|
public void shouldInsertAndCountData() {
|
||||||
|
|
||||||
Mono<Long> count = template.count(new Query(), Person.class) //
|
var count = template.count(new Query(), Person.class) //
|
||||||
.doOnNext(System.out::println) //
|
.doOnNext(System.out::println) //
|
||||||
.thenMany(template.insertAll(Arrays.asList(new Person("Hank", "Schrader", 43), //
|
.thenMany(template.insertAll(Arrays.asList(new Person("Hank", "Schrader", 43), //
|
||||||
new Person("Mike", "Ehrmantraut", 62)))) //
|
new Person("Mike", "Ehrmantraut", 62)))) //
|
||||||
@@ -83,7 +83,7 @@ public class ReactiveMongoTemplateIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void convertReactorTypesToRxJava2() {
|
public void convertReactorTypesToRxJava2() {
|
||||||
|
|
||||||
Flux<Person> flux = template.find(Query.query(Criteria.where("lastname").is("White")), Person.class);
|
var flux = template.find(Query.query(Criteria.where("lastname").is("White")), Person.class);
|
||||||
|
|
||||||
long count = RxReactiveStreams.toObservable(flux).count().toSingle().toBlocking().value();
|
long count = RxReactiveStreams.toObservable(flux).count().toSingle().toBlocking().value();
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class ReactivePersonRepositoryIntegrationTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
||||||
Mono<MongoCollection<Document>> recreateCollection = operations.collectionExists(Person.class) //
|
var recreateCollection = operations.collectionExists(Person.class) //
|
||||||
.flatMap(exists -> exists ? operations.dropCollection(Person.class) : Mono.just(exists)) //
|
.flatMap(exists -> exists ? operations.dropCollection(Person.class) : Mono.just(exists)) //
|
||||||
.then(operations.createCollection(Person.class, CollectionOptions.empty() //
|
.then(operations.createCollection(Person.class, CollectionOptions.empty() //
|
||||||
.size(1024 * 1024) //
|
.size(1024 * 1024) //
|
||||||
@@ -61,7 +61,7 @@ public class ReactivePersonRepositoryIntegrationTest {
|
|||||||
|
|
||||||
StepVerifier.create(recreateCollection).expectNextCount(1).verifyComplete();
|
StepVerifier.create(recreateCollection).expectNextCount(1).verifyComplete();
|
||||||
|
|
||||||
Flux<Person> insertAll = operations.insertAll(Flux.just(new Person("Walter", "White", 50), //
|
var insertAll = operations.insertAll(Flux.just(new Person("Walter", "White", 50), //
|
||||||
new Person("Skyler", "White", 45), //
|
new Person("Skyler", "White", 45), //
|
||||||
new Person("Saul", "Goodman", 42), //
|
new Person("Saul", "Goodman", 42), //
|
||||||
new Person("Jesse", "Pinkman", 27)).collectList());
|
new Person("Jesse", "Pinkman", 27)).collectList());
|
||||||
@@ -76,7 +76,7 @@ public class ReactivePersonRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldInsertAndCountData() {
|
public void shouldInsertAndCountData() {
|
||||||
|
|
||||||
Mono<Long> saveAndCount = repository.count() //
|
var saveAndCount = repository.count() //
|
||||||
.doOnNext(System.out::println) //
|
.doOnNext(System.out::println) //
|
||||||
.thenMany(repository.saveAll(Flux.just(new Person("Hank", "Schrader", 43), //
|
.thenMany(repository.saveAll(Flux.just(new Person("Hank", "Schrader", 43), //
|
||||||
new Person("Mike", "Ehrmantraut", 62)))) //
|
new Person("Mike", "Ehrmantraut", 62)))) //
|
||||||
@@ -106,7 +106,7 @@ public class ReactivePersonRepositoryIntegrationTest {
|
|||||||
|
|
||||||
Queue<Person> people = new ConcurrentLinkedQueue<>();
|
Queue<Person> people = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
Disposable disposable = repository.findWithTailableCursorBy() //
|
var disposable = repository.findWithTailableCursorBy() //
|
||||||
.doOnNext(System.out::println) //
|
.doOnNext(System.out::println) //
|
||||||
.doOnNext(people::add) //
|
.doOnNext(people::add) //
|
||||||
.doOnComplete(() -> System.out.println("Complete")) //
|
.doOnComplete(() -> System.out.println("Complete")) //
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class RxJava2PersonRepositoryIntegrationTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
||||||
Mono<MongoCollection<Document>> recreateCollection = operations.collectionExists(Person.class) //
|
var recreateCollection = operations.collectionExists(Person.class) //
|
||||||
.flatMap(exists -> exists ? operations.dropCollection(Person.class) : Mono.just(exists)) //
|
.flatMap(exists -> exists ? operations.dropCollection(Person.class) : Mono.just(exists)) //
|
||||||
.then(operations.createCollection(Person.class, CollectionOptions.empty() //
|
.then(operations.createCollection(Person.class, CollectionOptions.empty() //
|
||||||
.size(1024 * 1024) //
|
.size(1024 * 1024) //
|
||||||
@@ -83,7 +83,7 @@ public class RxJava2PersonRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldInsertAndCountData() {
|
public void shouldInsertAndCountData() {
|
||||||
|
|
||||||
Flowable<Person> people = Flowable.just(new Person("Hank", "Schrader", 43), //
|
var people = Flowable.just(new Person("Hank", "Schrader", 43), //
|
||||||
new Person("Mike", "Ehrmantraut", 62));
|
new Person("Mike", "Ehrmantraut", 62));
|
||||||
|
|
||||||
repository.count() //
|
repository.count() //
|
||||||
@@ -124,7 +124,7 @@ public class RxJava2PersonRepositoryIntegrationTest {
|
|||||||
|
|
||||||
Queue<Person> people = new ConcurrentLinkedQueue<>();
|
Queue<Person> people = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
Disposable subscription = repository.findWithTailableCursorBy() //
|
var subscription = repository.findWithTailableCursorBy() //
|
||||||
.doOnNext(System.out::println) //
|
.doOnNext(System.out::println) //
|
||||||
.doOnNext(people::add) //
|
.doOnNext(people::add) //
|
||||||
.doOnComplete(() -> System.out.println("Complete")) //
|
.doOnComplete(() -> System.out.println("Complete")) //
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
Configure a `RepositoryMethodInvocationListener` to capture invocation metrics on `Repository` interfaces.
|
Configure a `RepositoryMethodInvocationListener` to capture invocation metrics on `Repository` interfaces.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
class RepositoryMetricsConfiguration {
|
class RepositoryMetricsConfiguration {
|
||||||
|
|
||||||
@@ -16,13 +17,13 @@ class RepositoryMetricsConfiguration {
|
|||||||
@Override
|
@Override
|
||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
|
||||||
if (bean instanceof RepositoryFactoryBeanSupport) {
|
if (bean instanceof RepositoryFactoryBeanSupport<?, ?, ?> repositoryFactoryBean) {
|
||||||
|
|
||||||
RepositoryFactoryBeanSupport<?, ?, ?> repositoryFactoryBean = (RepositoryFactoryBeanSupport<?, ?, ?>) bean;
|
repositoryFactoryBean
|
||||||
|
.addRepositoryFactoryCustomizer(repositoryFactory -> {
|
||||||
repositoryFactoryBean.addRepositoryFactoryCustomizer(repositoryFactory -> {
|
repositoryFactory
|
||||||
repositoryFactory.addInvocationListener(System.out::println); // register the invocation listener
|
.addInvocationListener(System.out::println); // register the invocation listener
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return bean;
|
return bean;
|
||||||
|
|||||||
@@ -20,30 +20,6 @@ import org.springframework.data.annotation.Id;
|
|||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public class Person {
|
public record Person(@Id String id, String name) {
|
||||||
|
|
||||||
@Id String id;
|
|
||||||
|
|
||||||
String name;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Person{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ public class RepositoryMetricsConfiguration {
|
|||||||
@Override
|
@Override
|
||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
|
||||||
if (bean instanceof RepositoryFactoryBeanSupport) {
|
if (bean instanceof RepositoryFactoryBeanSupport<?, ?, ?> repositoryFactoryBean) {
|
||||||
|
|
||||||
RepositoryFactoryBeanSupport<?, ?, ?> repositoryFactoryBean = (RepositoryFactoryBeanSupport<?, ?, ?>) bean;
|
|
||||||
|
|
||||||
repositoryFactoryBean.addRepositoryFactoryCustomizer(repositoryFactory -> {
|
repositoryFactoryBean.addRepositoryFactoryCustomizer(repositoryFactory -> {
|
||||||
repositoryFactory.addInvocationListener(System.out::println);
|
repositoryFactory.addInvocationListener(System.out::println);
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb;
|
package example.springdata.mongodb;
|
||||||
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -39,19 +38,15 @@ class DemoApplicationTests {
|
|||||||
@Test
|
@Test
|
||||||
void repositoryMetrics() throws InterruptedException {
|
void repositoryMetrics() throws InterruptedException {
|
||||||
|
|
||||||
Person fiona = new Person();
|
var fiona = new Person("p-1", "fiona");
|
||||||
fiona.id = "p-1";
|
|
||||||
fiona.name = "fiona";
|
|
||||||
|
|
||||||
Person frank = new Person();
|
var frank = new Person("p-2", "frank");
|
||||||
frank.id = "p-2";
|
|
||||||
frank.name = "frank";
|
|
||||||
|
|
||||||
System.out.println("- Execute - Save Fiona -");
|
System.out.println("- Execute - Save Fiona -");
|
||||||
repo.save(fiona).then().as(StepVerifier::create).verifyComplete();
|
repo.save(fiona).then().as(StepVerifier::create).verifyComplete();
|
||||||
|
|
||||||
System.out.println("- Prepare - Find All -"); // Nothing captured - Invocation will happen in line 53 when subscribing
|
System.out.println("- Prepare - Find All -"); // Nothing captured - Invocation will happen in line 53 when subscribing
|
||||||
Flux<Person> all = repo.findAll();
|
var all = repo.findAll();
|
||||||
|
|
||||||
System.out.println("- Execute - Save Frank -");
|
System.out.println("- Execute - Save Frank -");
|
||||||
repo.save(frank).as(StepVerifier::create).expectNextCount(1).verifyComplete();
|
repo.save(frank).as(StepVerifier::create).expectNextCount(1).verifyComplete();
|
||||||
|
|||||||
@@ -15,10 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.schema;
|
package example.springdata.mongodb.schema;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
@@ -26,14 +22,7 @@ import org.springframework.lang.Nullable;
|
|||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Document("star-wars")
|
@Document("star-wars")
|
||||||
class Jedi {
|
record Jedi(@Id String id, @Nullable String name, @Nullable String lastname, @Nullable Integer age) {
|
||||||
|
|
||||||
@Id String id;
|
|
||||||
@Nullable String name;
|
|
||||||
@Nullable String lastname;
|
|
||||||
@Nullable Integer age;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class DocumentValidation {
|
|||||||
@Test
|
@Test
|
||||||
public void criteriaValidator() {
|
public void criteriaValidator() {
|
||||||
|
|
||||||
Validator validator = Validator.criteria( //
|
var validator = Validator.criteria( //
|
||||||
where("name").exists(true).ne(null).type(2) // non null String
|
where("name").exists(true).ne(null).type(2) // non null String
|
||||||
.and("age").exists(true).ne(null).type(16).gte(0).lte(125)) // non null int between 0 and 125
|
.and("age").exists(true).ne(null).type(16).gte(0).lte(125)) // non null int between 0 and 125
|
||||||
;
|
;
|
||||||
@@ -116,7 +116,7 @@ public class DocumentValidation {
|
|||||||
@Test
|
@Test
|
||||||
public void schemaValidator() {
|
public void schemaValidator() {
|
||||||
|
|
||||||
Validator validator = Validator.schema(MongoJsonSchema.builder() //
|
var validator = Validator.schema(MongoJsonSchema.builder() //
|
||||||
.required("name", "age") //
|
.required("name", "age") //
|
||||||
.properties( //
|
.properties( //
|
||||||
string("name").minLength(1), //
|
string("name").minLength(1), //
|
||||||
|
|||||||
@@ -75,13 +75,13 @@ public class SchemaQuery {
|
|||||||
@Test
|
@Test
|
||||||
public void criteriaValidator() {
|
public void criteriaValidator() {
|
||||||
|
|
||||||
Jedi luke = new Jedi("luke", "luke", "skywalker", 25);
|
var luke = new Jedi("luke", "luke", "skywalker", 25);
|
||||||
Jedi yoda = new Jedi("yoda", "yoda", null, 900);
|
var yoda = new Jedi("yoda", "yoda", null, 900);
|
||||||
|
|
||||||
mongoOps.save(luke);
|
mongoOps.save(luke);
|
||||||
mongoOps.save(yoda);
|
mongoOps.save(yoda);
|
||||||
|
|
||||||
MongoJsonSchema schema = MongoJsonSchema.builder() //
|
var schema = MongoJsonSchema.builder() //
|
||||||
.required("name", "age") //
|
.required("name", "age") //
|
||||||
.properties( //
|
.properties( //
|
||||||
string("name").minLength(1), //
|
string("name").minLength(1), //
|
||||||
|
|||||||
@@ -15,21 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb.security;
|
package example.springdata.mongodb.security;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entity to represent a {@link Person}.
|
* An entity to represent a {@link Person}.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
*/
|
*/
|
||||||
@Data
|
public record Person(@Id String id, String firstname, String lastname) {
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class Person {
|
|
||||||
|
|
||||||
private @Id String id;
|
@PersistenceConstructor
|
||||||
private final String firstname;
|
public Person {
|
||||||
private final String lastname;
|
}
|
||||||
|
|
||||||
|
public Person(String firstname, String lastname) {
|
||||||
|
this(null, firstname, lastname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class PersonRepositoryIntegrationTest {
|
|||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(dave, "x"));
|
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(dave, "x"));
|
||||||
|
|
||||||
List<Person> persons = repository.findAllForCurrentUserById();
|
var persons = repository.findAllForCurrentUserById();
|
||||||
|
|
||||||
assertThat(persons, hasSize(1));
|
assertThat(persons, hasSize(1));
|
||||||
assertThat(persons, contains(dave));
|
assertThat(persons, contains(dave));
|
||||||
@@ -70,11 +70,11 @@ public class PersonRepositoryIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void adminCallingShouldReturnAllUsers() throws Exception {
|
public void adminCallingShouldReturnAllUsers() throws Exception {
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(admin, "x",
|
var auth = new UsernamePasswordAuthenticationToken(admin, "x",
|
||||||
Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN")));
|
Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN")));
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
|
||||||
List<Person> persons = repository.findAllForCurrentUserById();
|
var persons = repository.findAllForCurrentUserById();
|
||||||
|
|
||||||
assertThat(persons, hasSize(4));
|
assertThat(persons, hasSize(4));
|
||||||
assertThat(persons, containsInAnyOrder(admin, dave, carter, oliver));
|
assertThat(persons, containsInAnyOrder(admin, dave, carter, oliver));
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ package example.springdata.mongodb.textsearch;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.mongodb.core.index.TextIndexed;
|
import org.springframework.data.mongodb.core.index.TextIndexed;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
@@ -31,17 +29,7 @@ import org.springframework.data.mongodb.core.mapping.TextScore;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
@Document
|
@Document
|
||||||
@Data
|
public record BlogPost(@Id String id, @TextIndexed(weight = 3) String title, @TextIndexed(weight = 2) String content,
|
||||||
public class BlogPost {
|
@TextIndexed List<String> categories, @TextScore Float score) {
|
||||||
|
|
||||||
private @Id String id;
|
|
||||||
private @TextIndexed(weight = 3) String title;
|
|
||||||
private @TextIndexed(weight = 2) String content;
|
|
||||||
private @TextIndexed List<String> categories;
|
|
||||||
private @TextScore Float score;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "BlogPost [id=" + id + ", score=" + score + ", title=" + title + ", categories=" + categories + "]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class MongoTestConfiguration {
|
|||||||
|
|
||||||
public @Bean Jackson2RepositoryPopulatorFactoryBean repositoryPopulator() {
|
public @Bean Jackson2RepositoryPopulatorFactoryBean repositoryPopulator() {
|
||||||
|
|
||||||
Jackson2RepositoryPopulatorFactoryBean factoryBean = new Jackson2RepositoryPopulatorFactoryBean();
|
var factoryBean = new Jackson2RepositoryPopulatorFactoryBean();
|
||||||
factoryBean.setResources(new Resource[] { new ClassPathResource("spring-blog.atom.json") });
|
factoryBean.setResources(new Resource[] { new ClassPathResource("spring-blog.atom.json") });
|
||||||
return factoryBean;
|
return factoryBean;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ public class MongoTestConfiguration {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void postConstruct() {
|
private void postConstruct() {
|
||||||
|
|
||||||
IndexResolver resolver = IndexResolver.create(operations.getConverter().getMappingContext());
|
var resolver = IndexResolver.create(operations.getConverter().getMappingContext());
|
||||||
|
|
||||||
resolver.resolveIndexFor(BlogPost.class).forEach(operations.indexOps(BlogPost.class)::ensureIndex);
|
resolver.resolveIndexFor(BlogPost.class).forEach(operations.indexOps(BlogPost.class)::ensureIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ public class TextSearchRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsWithRelease() {
|
public void findAllBlogPostsWithRelease() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
|
var criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
|
||||||
List<BlogPost> blogPosts = repo.findAllBy(criteria);
|
var blogPosts = repo.findAllBy(criteria);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
@@ -59,8 +59,8 @@ public class TextSearchRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsWithReleaseButHeyIDoWantTheEngineeringStuff() {
|
public void findAllBlogPostsWithReleaseButHeyIDoWantTheEngineeringStuff() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release").notMatching("engineering");
|
var criteria = TextCriteria.forDefaultLanguage().matchingAny("release").notMatching("engineering");
|
||||||
List<BlogPost> blogPosts = repo.findAllBy(criteria);
|
var blogPosts = repo.findAllBy(criteria);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,8 @@ public class TextSearchRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsByPhrase() {
|
public void findAllBlogPostsByPhrase() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
|
var criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
|
||||||
List<BlogPost> blogPosts = repo.findAllBy(criteria);
|
var blogPosts = repo.findAllBy(criteria);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,8 @@ public class TextSearchRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsByPhraseSortByScore() {
|
public void findAllBlogPostsByPhraseSortByScore() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
|
var criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
|
||||||
List<BlogPost> blogPosts = repo.findAllByOrderByScoreDesc(criteria);
|
var blogPosts = repo.findAllByOrderByScoreDesc(criteria);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ public class TextSearchTemplateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsWithRelease() {
|
public void findAllBlogPostsWithRelease() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
|
var criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
|
||||||
List<BlogPost> blogPosts = operations.find(query(criteria), BlogPost.class);
|
var blogPosts = operations.find(query(criteria), BlogPost.class);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
@@ -71,13 +71,13 @@ public class TextSearchTemplateTests {
|
|||||||
@Test
|
@Test
|
||||||
public void findAllBlogPostsByPhraseSortByScore() {
|
public void findAllBlogPostsByPhraseSortByScore() {
|
||||||
|
|
||||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release");
|
var criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release");
|
||||||
|
|
||||||
TextQuery query = new TextQuery(criteria);
|
var query = new TextQuery(criteria);
|
||||||
query.setScoreFieldName("score");
|
query.setScoreFieldName("score");
|
||||||
query.sortByScore();
|
query.sortByScore();
|
||||||
|
|
||||||
List<BlogPost> blogPosts = operations.find(query, BlogPost.class);
|
var blogPosts = operations.find(query, BlogPost.class);
|
||||||
|
|
||||||
printResult(blogPosts, criteria);
|
printResult(blogPosts, criteria);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ public enum BlogPostInitializer {
|
|||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
private void loadFromClasspathSource(MongoOperations operations) throws Exception {
|
private void loadFromClasspathSource(MongoOperations operations) throws Exception {
|
||||||
|
|
||||||
Jackson2ResourceReader reader = new Jackson2ResourceReader();
|
var reader = new Jackson2ResourceReader();
|
||||||
|
|
||||||
Object source = reader.readFrom(new ClassPathResource("spring-blog.atom.json"), this.getClass().getClassLoader());
|
var source = reader.readFrom(new ClassPathResource("spring-blog.atom.json"), this.getClass().getClassLoader());
|
||||||
|
|
||||||
if (source instanceof Iterable) {
|
if (source instanceof Iterable) {
|
||||||
((Iterable) source).forEach(element -> operations.save(element));
|
((Iterable) source).forEach(operations::save);
|
||||||
} else {
|
} else {
|
||||||
operations.save(source);
|
operations.save(source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class ConsoleResultPrinter {
|
|||||||
System.out.println(String.format("XXXXXXXXXXXX -- Found %s blogPosts matching '%s' --XXXXXXXXXXXX",
|
System.out.println(String.format("XXXXXXXXXXXX -- Found %s blogPosts matching '%s' --XXXXXXXXXXXX",
|
||||||
blogPosts.size(), criteria != null ? criteria.getCriteriaObject() : ""));
|
blogPosts.size(), criteria != null ? criteria.getCriteriaObject() : ""));
|
||||||
|
|
||||||
for (BlogPost blogPost : blogPosts) {
|
for (var blogPost : blogPosts) {
|
||||||
System.out.println(blogPost);
|
System.out.println(blogPost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.mongodb;
|
package example.springdata.mongodb;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
@@ -25,13 +22,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @currentRead The Core - Peter V. Brett
|
* @currentRead The Core - Peter V. Brett
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Document("processes")
|
@Document("processes")
|
||||||
public class Process {
|
public record Process(@Id Integer id, State state, int transitionCount) {
|
||||||
|
|
||||||
@Id Integer id;
|
|
||||||
State state;
|
|
||||||
int transitionCount;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ class TransitionService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void run(Integer id) {
|
public void run(Integer id) {
|
||||||
|
|
||||||
Process process = lookup(id);
|
var process = lookup(id);
|
||||||
|
|
||||||
if (!State.CREATED.equals(process.getState())) {
|
if (!State.CREATED.equals(process.state())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +62,13 @@ class TransitionService {
|
|||||||
|
|
||||||
private void finish(Process process) {
|
private void finish(Process process) {
|
||||||
|
|
||||||
template.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
template.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first();
|
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(Process process) {
|
void start(Process process) {
|
||||||
|
|
||||||
template.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
template.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first();
|
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +77,6 @@ class TransitionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void verify(Process process) {
|
void verify(Process process) {
|
||||||
Assert.state(process.getId() % 3 != 0, "We're sorry but we needed to drop that one");
|
Assert.state(process.id() % 3 != 0, "We're sorry but we needed to drop that one");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,21 +52,21 @@ public class ReactiveManagedTransitionService {
|
|||||||
|
|
||||||
return lookup(id) //
|
return lookup(id) //
|
||||||
.flatMap(process -> start(template, process)) //
|
.flatMap(process -> start(template, process)) //
|
||||||
.flatMap(it -> verify(it)) //
|
.flatMap(this::verify) //
|
||||||
.flatMap(process -> finish(template, process)) //
|
.flatMap(process -> finish(template, process)) //
|
||||||
.map(Process::getId);
|
.map(Process::id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Process> finish(ReactiveMongoOperations operations, Process process) {
|
private Mono<Process> finish(ReactiveMongoOperations operations, Process process) {
|
||||||
|
|
||||||
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first() //
|
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first() //
|
||||||
.then(Mono.just(process));
|
.then(Mono.just(process));
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Process> start(ReactiveMongoOperations operations, Process process) {
|
Mono<Process> start(ReactiveMongoOperations operations, Process process) {
|
||||||
|
|
||||||
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first() //
|
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first() //
|
||||||
.then(Mono.just(process));
|
.then(Mono.just(process));
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ public class ReactiveManagedTransitionService {
|
|||||||
|
|
||||||
Mono<Process> verify(Process process) {
|
Mono<Process> verify(Process process) {
|
||||||
|
|
||||||
Assert.state(process.getId() % 3 != 0, "We're sorry but we needed to drop that one");
|
Assert.state(process.id() % 3 != 0, "We're sorry but we needed to drop that one");
|
||||||
return Mono.just(process);
|
return Mono.just(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,19 +56,19 @@ public class ReactiveTransitionService {
|
|||||||
.flatMap(it -> verify(it)) //
|
.flatMap(it -> verify(it)) //
|
||||||
.flatMap(process -> finish(action, process));
|
.flatMap(process -> finish(action, process));
|
||||||
|
|
||||||
}).next().map(Process::getId);
|
}).next().map(Process::id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Process> finish(ReactiveMongoOperations operations, Process process) {
|
private Mono<Process> finish(ReactiveMongoOperations operations, Process process) {
|
||||||
|
|
||||||
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first() //
|
.apply(Update.update("state", State.DONE).inc("transitionCount", 1)).first() //
|
||||||
.then(Mono.just(process));
|
.then(Mono.just(process));
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Process> start(ReactiveMongoOperations operations, Process process) {
|
Mono<Process> start(ReactiveMongoOperations operations, Process process) {
|
||||||
|
|
||||||
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.getId())))
|
return operations.update(Process.class).matching(Query.query(Criteria.where("id").is(process.id())))
|
||||||
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first() //
|
.apply(Update.update("state", State.ACTIVE).inc("transitionCount", 1)).first() //
|
||||||
.then(Mono.just(process));
|
.then(Mono.just(process));
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ public class ReactiveTransitionService {
|
|||||||
|
|
||||||
Mono<Process> verify(Process process) {
|
Mono<Process> verify(Process process) {
|
||||||
|
|
||||||
Assert.state(process.getId() % 3 != 0, "We're sorry but we needed to drop that one");
|
Assert.state(process.id() % 3 != 0, "We're sorry but we needed to drop that one");
|
||||||
return Mono.just(process);
|
return Mono.just(process);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,13 +88,13 @@ public class TransitionServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
public void txCommitRollback() {
|
public void txCommitRollback() {
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (var i = 0; i < 10; i++) {
|
||||||
|
|
||||||
Process process = transitionService.newProcess();
|
var process = transitionService.newProcess();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
transitionService.run(process.getId());
|
transitionService.run(process.id());
|
||||||
Assertions.assertThat(stateInDb(process)).isEqualTo(State.DONE);
|
Assertions.assertThat(stateInDb(process)).isEqualTo(State.DONE);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
Assertions.assertThat(stateInDb(process)).isEqualTo(State.CREATED);
|
Assertions.assertThat(stateInDb(process)).isEqualTo(State.CREATED);
|
||||||
@@ -107,7 +107,7 @@ public class TransitionServiceTests {
|
|||||||
|
|
||||||
State stateInDb(Process process) {
|
State stateInDb(Process process) {
|
||||||
|
|
||||||
return State.valueOf(client.getDatabase(DB_NAME).getCollection("processes").find(Filters.eq("_id", process.getId()))
|
return State.valueOf(client.getDatabase(DB_NAME).getCollection("processes").find(Filters.eq("_id", process.id()))
|
||||||
.projection(Projections.include("state")).first().get("state", String.class));
|
.projection(Projections.include("state")).first().get("state", String.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ public class ReactiveManagedTransitionServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
public void reactiveTxCommitRollback() {
|
public void reactiveTxCommitRollback() {
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (var i = 0; i < 10; i++) {
|
||||||
managedTransitionService.newProcess() //
|
managedTransitionService.newProcess() //
|
||||||
.map(Process::getId) //
|
.map(Process::id) //
|
||||||
.flatMap(managedTransitionService::run) //
|
.flatMap(managedTransitionService::run) //
|
||||||
.onErrorReturn(-1).as(StepVerifier::create) //
|
.onErrorReturn(-1).as(StepVerifier::create) //
|
||||||
.consumeNextWith(val -> {}) //
|
.consumeNextWith(val -> {}) //
|
||||||
@@ -100,7 +100,7 @@ public class ReactiveManagedTransitionServiceTests {
|
|||||||
.as(StepVerifier::create) //
|
.as(StepVerifier::create) //
|
||||||
.consumeNextWith(list -> {
|
.consumeNextWith(list -> {
|
||||||
|
|
||||||
for (Document document : list) {
|
for (var document : list) {
|
||||||
|
|
||||||
System.out.println("document: " + document);
|
System.out.println("document: " + document);
|
||||||
|
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ public class ReactiveTransitionServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
public void reactiveTxCommitRollback() {
|
public void reactiveTxCommitRollback() {
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (var i = 0; i < 10; i++) {
|
||||||
transitionService.newProcess() //
|
transitionService.newProcess() //
|
||||||
.map(Process::getId) //
|
.map(Process::id) //
|
||||||
.flatMap(transitionService::run) //
|
.flatMap(transitionService::run) //
|
||||||
.onErrorReturn(-1).as(StepVerifier::create) //
|
.onErrorReturn(-1).as(StepVerifier::create) //
|
||||||
.consumeNextWith(val -> {}) //
|
.consumeNextWith(val -> {}) //
|
||||||
@@ -90,7 +90,7 @@ public class ReactiveTransitionServiceTests {
|
|||||||
.as(StepVerifier::create) //
|
.as(StepVerifier::create) //
|
||||||
.consumeNextWith(list -> {
|
.consumeNextWith(list -> {
|
||||||
|
|
||||||
for (Document document : list) {
|
for (var document : list) {
|
||||||
|
|
||||||
System.out.println("document: " + document);
|
System.out.println("document: " + document);
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public class EmbeddedMongo extends ExternalResource {
|
|||||||
|
|
||||||
if (serverPorts.size() > 1 || StringUtils.hasText(replicaSetName)) {
|
if (serverPorts.size() > 1 || StringUtils.hasText(replicaSetName)) {
|
||||||
|
|
||||||
String rsName = StringUtils.hasText(replicaSetName) ? replicaSetName : DEFAULT_REPLICA_SET_NAME;
|
var rsName = StringUtils.hasText(replicaSetName) ? replicaSetName : DEFAULT_REPLICA_SET_NAME;
|
||||||
return new EmbeddedMongo(
|
return new EmbeddedMongo(
|
||||||
new ReplSet(version, rsName, silent, serverPorts.toArray(new Integer[serverPorts.size()])));
|
new ReplSet(version, rsName, silent, serverPorts.toArray(new Integer[serverPorts.size()])));
|
||||||
}
|
}
|
||||||
@@ -306,7 +306,7 @@ public class EmbeddedMongo extends ExternalResource {
|
|||||||
replicaSets.put(replicaSetName, initReplicaSet());
|
replicaSets.put(replicaSetName, initReplicaSet());
|
||||||
|
|
||||||
// create mongos
|
// create mongos
|
||||||
MongosConfig mongosConfig = defaultMongosConfig(serverVersion, mongosPort, defaultCommandOptions(),
|
var mongosConfig = defaultMongosConfig(serverVersion, mongosPort, defaultCommandOptions(),
|
||||||
configServerReplicaSetName, configServerPorts[0]);
|
configServerReplicaSetName, configServerPorts[0]);
|
||||||
|
|
||||||
mongosTestFactory = new MongosSystemForTestFactory(mongosConfig, replicaSets, Collections.emptyList(),
|
mongosTestFactory = new MongosSystemForTestFactory(mongosConfig, replicaSets, Collections.emptyList(),
|
||||||
@@ -341,7 +341,7 @@ public class EmbeddedMongo extends ExternalResource {
|
|||||||
|
|
||||||
List<MongodConfig> configServers = new ArrayList<>(configServerPorts.length);
|
List<MongodConfig> configServers = new ArrayList<>(configServerPorts.length);
|
||||||
|
|
||||||
for (Integer port : configServerPorts) {
|
for (var port : configServerPorts) {
|
||||||
configServers.add(
|
configServers.add(
|
||||||
defaultMongodConfig(serverVersion, port, defaultCommandOptions(), true, false, configServerReplicaSetName));
|
defaultMongodConfig(serverVersion, port, defaultCommandOptions(), true, false, configServerReplicaSetName));
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ public class EmbeddedMongo extends ExternalResource {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
ImmutableMongodConfig.Builder builder = MongodConfig.builder() //
|
var builder = MongodConfig.builder() //
|
||||||
.version(version) //
|
.version(version) //
|
||||||
.putArgs("--quiet", null) //
|
.putArgs("--quiet", null) //
|
||||||
.net(new Net(LOCALHOST, port, Network.localhostIsIPv6())) //
|
.net(new Net(LOCALHOST, port, Network.localhostIsIPv6())) //
|
||||||
@@ -435,7 +435,7 @@ public class EmbeddedMongo extends ExternalResource {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
ImmutableMongosConfig.Builder builder = MongosConfig.builder() //
|
var builder = MongosConfig.builder() //
|
||||||
.version(version) //
|
.version(version) //
|
||||||
.putArgs("--quiet", null) //
|
.putArgs("--quiet", null) //
|
||||||
.net(new Net(LOCALHOST, port, Network.localhostIsIPv6())) //
|
.net(new Net(LOCALHOST, port, Network.localhostIsIPv6())) //
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ class MongosSystemForTestFactory {
|
|||||||
public void start() throws Throwable {
|
public void start() throws Throwable {
|
||||||
this.mongodProcessList = new ArrayList<>();
|
this.mongodProcessList = new ArrayList<>();
|
||||||
this.mongodConfigProcessList = new ArrayList<>();
|
this.mongodConfigProcessList = new ArrayList<>();
|
||||||
for (Entry<String, List<MongodConfig>> entry : replicaSets.entrySet()) {
|
for (var entry : replicaSets.entrySet()) {
|
||||||
initializeReplicaSet(entry);
|
initializeReplicaSet(entry);
|
||||||
}
|
}
|
||||||
for (MongodConfig config : configServers) {
|
for (var config : configServers) {
|
||||||
initializeConfigServer(config);
|
initializeConfigServer(config);
|
||||||
}
|
}
|
||||||
initializeMongos();
|
initializeMongos();
|
||||||
@@ -102,15 +102,15 @@ class MongosSystemForTestFactory {
|
|||||||
|
|
||||||
private void initializeReplicaSet(Entry<String, List<MongodConfig>> entry)
|
private void initializeReplicaSet(Entry<String, List<MongodConfig>> entry)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String replicaName = entry.getKey();
|
var replicaName = entry.getKey();
|
||||||
List<MongodConfig> mongoConfigList = entry.getValue();
|
var mongoConfigList = entry.getValue();
|
||||||
|
|
||||||
if (mongoConfigList.size() < 3) {
|
if (mongoConfigList.size() < 3) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
"A replica set must contain at least 3 members.");
|
"A replica set must contain at least 3 members.");
|
||||||
}
|
}
|
||||||
// Create 3 mongod processes
|
// Create 3 mongod processes
|
||||||
for (MongodConfig mongoConfig : mongoConfigList) {
|
for (var mongoConfig : mongoConfigList) {
|
||||||
if (!mongoConfig.replication().getReplSetName().equals(replicaName)) {
|
if (!mongoConfig.replication().getReplSetName().equals(replicaName)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
"Replica set name must match in mongo configuration");
|
"Replica set name must match in mongo configuration");
|
||||||
@@ -119,28 +119,28 @@ class MongosSystemForTestFactory {
|
|||||||
// .defaultsWithLogger(Command.MongoD,logger)
|
// .defaultsWithLogger(Command.MongoD,logger)
|
||||||
.processOutput(outputFunction.apply(Command.MongoD))
|
.processOutput(outputFunction.apply(Command.MongoD))
|
||||||
.build();
|
.build();
|
||||||
MongodStarter starter = MongodStarter.getInstance(runtimeConfig);
|
var starter = MongodStarter.getInstance(runtimeConfig);
|
||||||
MongodExecutable mongodExe = starter.prepare(mongoConfig);
|
var mongodExe = starter.prepare(mongoConfig);
|
||||||
MongodProcess process = mongodExe.start();
|
var process = mongodExe.start();
|
||||||
mongodProcessList.add(process);
|
mongodProcessList.add(process);
|
||||||
}
|
}
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
MongoClientSettings mo = MongoClientSettings.builder()
|
var mo = MongoClientSettings.builder()
|
||||||
.applyToSocketSettings(builder -> builder.connectTimeout(10, TimeUnit.SECONDS)).applyToClusterSettings(
|
.applyToSocketSettings(builder -> builder.connectTimeout(10, TimeUnit.SECONDS)).applyToClusterSettings(
|
||||||
builder -> builder.hosts(Collections.singletonList(toAddress(mongoConfigList.get(0).net()))))
|
builder -> builder.hosts(Collections.singletonList(toAddress(mongoConfigList.get(0).net()))))
|
||||||
.build();
|
.build();
|
||||||
MongoClient mongo = MongoClients.create(mo);
|
var mongo = MongoClients.create(mo);
|
||||||
MongoDatabase mongoAdminDB = mongo.getDatabase(ADMIN_DATABASE_NAME);
|
var mongoAdminDB = mongo.getDatabase(ADMIN_DATABASE_NAME);
|
||||||
|
|
||||||
Document cr = mongoAdminDB.runCommand(new Document("isMaster", 1));
|
var cr = mongoAdminDB.runCommand(new Document("isMaster", 1));
|
||||||
logger.info("isMaster: {}", cr);
|
logger.info("isMaster: {}", cr);
|
||||||
|
|
||||||
// Build BSON object replica set settings
|
// Build BSON object replica set settings
|
||||||
DBObject replicaSetSetting = new BasicDBObject();
|
DBObject replicaSetSetting = new BasicDBObject();
|
||||||
replicaSetSetting.put("_id", replicaName);
|
replicaSetSetting.put("_id", replicaName);
|
||||||
BasicDBList members = new BasicDBList();
|
var members = new BasicDBList();
|
||||||
int i = 0;
|
var i = 0;
|
||||||
for (MongodConfig mongoConfig : mongoConfigList) {
|
for (var mongoConfig : mongoConfigList) {
|
||||||
DBObject host = new BasicDBObject();
|
DBObject host = new BasicDBObject();
|
||||||
host.put("_id", i++);
|
host.put("_id", i++);
|
||||||
host.put("host", mongoConfig.net().getServerAddress().getHostName()
|
host.put("host", mongoConfig.net().getServerAddress().getHostName()
|
||||||
@@ -176,11 +176,11 @@ class MongosSystemForTestFactory {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List members = (List) setting.get("members");
|
var members = (List) setting.get("members");
|
||||||
for (Object m : members) {
|
for (var m : members) {
|
||||||
Document member = (Document) m;
|
var member = (Document) m;
|
||||||
logger.info(member.toString());
|
logger.info(member.toString());
|
||||||
int state = member.getInteger("state", 0);
|
var state = member.getInteger("state", 0);
|
||||||
logger.info("state: {}", state);
|
logger.info("state: {}", state);
|
||||||
// 1 - PRIMARY, 2 - SECONDARY, 7 - ARBITER
|
// 1 - PRIMARY, 2 - SECONDARY, 7 - ARBITER
|
||||||
if (state != 1 && state != 2 && state != 7) {
|
if (state != 1 && state != 2 && state != 7) {
|
||||||
@@ -195,14 +195,14 @@ class MongosSystemForTestFactory {
|
|||||||
throw new Exception(
|
throw new Exception(
|
||||||
"Mongo configuration is not a defined for a config server.");
|
"Mongo configuration is not a defined for a config server.");
|
||||||
}
|
}
|
||||||
MongodStarter starter = MongodStarter.getDefaultInstance();
|
var starter = MongodStarter.getDefaultInstance();
|
||||||
MongodExecutable mongodExe = starter.prepare(config);
|
var mongodExe = starter.prepare(config);
|
||||||
MongodProcess process = mongodExe.start();
|
var process = mongodExe.start();
|
||||||
mongodProcessList.add(process);
|
mongodProcessList.add(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeMongos() throws Exception {
|
private void initializeMongos() throws Exception {
|
||||||
MongosStarter runtime = MongosStarter.getInstance(RuntimeConfig.builder()
|
var runtime = MongosStarter.getInstance(RuntimeConfig.builder()
|
||||||
// .defaultsWithLogger(Command.MongoS,logger)
|
// .defaultsWithLogger(Command.MongoS,logger)
|
||||||
.processOutput(outputFunction.apply(Command.MongoS))
|
.processOutput(outputFunction.apply(Command.MongoS))
|
||||||
.build());
|
.build());
|
||||||
@@ -213,19 +213,19 @@ class MongosSystemForTestFactory {
|
|||||||
|
|
||||||
private void configureMongos() throws Exception {
|
private void configureMongos() throws Exception {
|
||||||
Document cr;
|
Document cr;
|
||||||
MongoClientSettings options = MongoClientSettings.builder()
|
var options = MongoClientSettings.builder()
|
||||||
.applyToSocketSettings(builder -> builder.connectTimeout(10, TimeUnit.SECONDS))
|
.applyToSocketSettings(builder -> builder.connectTimeout(10, TimeUnit.SECONDS))
|
||||||
.applyToClusterSettings(builder -> builder.hosts(Collections.singletonList(toAddress(this.config.net()))))
|
.applyToClusterSettings(builder -> builder.hosts(Collections.singletonList(toAddress(this.config.net()))))
|
||||||
.build();
|
.build();
|
||||||
try (MongoClient mongo = MongoClients.create(options)) {
|
try (var mongo = MongoClients.create(options)) {
|
||||||
MongoDatabase mongoAdminDB = mongo.getDatabase(ADMIN_DATABASE_NAME);
|
var mongoAdminDB = mongo.getDatabase(ADMIN_DATABASE_NAME);
|
||||||
|
|
||||||
// Add shard from the replica set list
|
// Add shard from the replica set list
|
||||||
for (Entry<String, List<MongodConfig>> entry : this.replicaSets
|
for (var entry : this.replicaSets
|
||||||
.entrySet()) {
|
.entrySet()) {
|
||||||
String replicaName = entry.getKey();
|
var replicaName = entry.getKey();
|
||||||
String command = "";
|
var command = "";
|
||||||
for (MongodConfig mongodConfig : entry.getValue()) {
|
for (var mongodConfig : entry.getValue()) {
|
||||||
if (command.isEmpty()) {
|
if (command.isEmpty()) {
|
||||||
command = replicaName + "/";
|
command = replicaName + "/";
|
||||||
} else {
|
} else {
|
||||||
@@ -251,22 +251,20 @@ class MongosSystemForTestFactory {
|
|||||||
|
|
||||||
// Create index in sharded collection
|
// Create index in sharded collection
|
||||||
logger.info("Create index in sharded collection");
|
logger.info("Create index in sharded collection");
|
||||||
MongoDatabase db = mongo.getDatabase(this.shardDatabase);
|
var db = mongo.getDatabase(this.shardDatabase);
|
||||||
db.getCollection(this.shardCollection).createIndex(new Document(this.shardKey, 1));
|
db.getCollection(this.shardCollection).createIndex(new Document(this.shardKey, 1));
|
||||||
|
|
||||||
// Shard the collection
|
// Shard the collection
|
||||||
logger.info("Shard the collection: {}.{}", this.shardDatabase, this.shardCollection);
|
logger.info("Shard the collection: {}.{}", this.shardDatabase, this.shardCollection);
|
||||||
Document cmd = new Document();
|
var cmd = new Document();
|
||||||
cmd.put("shardCollection", this.shardDatabase + "." + this.shardCollection);
|
cmd.put("shardCollection", this.shardDatabase + "." + this.shardCollection);
|
||||||
cmd.put("key", new BasicDBObject(this.shardKey, 1));
|
cmd.put("key", new BasicDBObject(this.shardKey, 1));
|
||||||
cr = mongoAdminDB.runCommand(cmd);
|
cr = mongoAdminDB.runCommand(cmd);
|
||||||
logger.info(cr.toString());
|
logger.info(cr.toString());
|
||||||
|
|
||||||
logger.info("Get info from config/shards");
|
logger.info("Get info from config/shards");
|
||||||
FindIterable<Document> cursor = mongo.getDatabase("config").getCollection("shards").find();
|
var cursor = mongo.getDatabase("config").getCollection("shards").find();
|
||||||
MongoCursor<Document> iterator = cursor.iterator();
|
for (Document item : cursor) {
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Document item = iterator.next();
|
|
||||||
logger.info(item.toString());
|
logger.info(item.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,10 +277,10 @@ class MongosSystemForTestFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
for (MongodProcess process : this.mongodProcessList) {
|
for (var process : this.mongodProcessList) {
|
||||||
process.stop();
|
process.stop();
|
||||||
}
|
}
|
||||||
for (MongodProcess process : this.mongodConfigProcessList) {
|
for (var process : this.mongodConfigProcessList) {
|
||||||
process.stop();
|
process.stop();
|
||||||
}
|
}
|
||||||
this.mongosProcess.stop();
|
this.mongosProcess.stop();
|
||||||
|
|||||||
Reference in New Issue
Block a user