diff --git a/README.md b/README.md index 8090c670..bfee187f 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ We have separate folders for the samples of individual modules: * `java8` - Example of how to use Spring Data MongoDB with Java 8 date time types as well as the usage of `Optional` as return type for repository methods. Note, this project requires to be build with JDK 8. * `kotlin` - Example for using Cassandra with MongoDB. * `query-by-example` - Example project showing usage of Query by Example with MongoDB. +* `querydsl` - Example project showing sync/reactive [Querydsl](https://github.com/querydsl/querydsl) support for MongoDB. * `reactive` - Example project to show reactive template and repository support. * `security` - Example project showing usage of Spring Security with MongoDB. * `text-search` - Example project showing usage of MongoDB text search feature. diff --git a/mongodb/pom.xml b/mongodb/pom.xml index 277a1c6a..5f6246fe 100644 --- a/mongodb/pom.xml +++ b/mongodb/pom.xml @@ -31,6 +31,7 @@ text-search transactions schema-validation + querydsl util diff --git a/mongodb/querydsl/README.md b/mongodb/querydsl/README.md new file mode 100644 index 00000000..6d2082bf --- /dev/null +++ b/mongodb/querydsl/README.md @@ -0,0 +1,34 @@ +# Spring Data MongoDB - Querydsl example + +This project contains samples of [Querydsl](https://github.com/querydsl/querydsl) usage in Spring Data MongoDB. + +Querydsl is a framework which enables the construction of fluent, type-safe queries for multiple backends including MongoDB. +Spring Data integrates with Querydsl via `QuerydslPredicateExecutor` and its reactive counterpart `ReactiveQuerydslPredicateExecutor`. + +**NOTE**: You may have to run `mvn compile` to generate the required `Q` classes first. + +## Sync + +```java +interface SyncCustomerRepository + extends CrudRepository, QuerydslPredicateExecutor { } + +@Autowired SyncCustomerRepository repository; + +// ... + +List result = repository.findAll(QCustomer.customer.lastname.eq("Matthews")); +``` + +## Reactive + +```java +interface ReactiveCustomerRepository + extends ReactiveCrudRepository, ReactiveQuerydslPredicateExecutor { } + +@Autowired ReactiveCustomerRepository repository; + +// ... + +Flux result = repository.findAll(QCustomer.customer.lastname.eq("Matthews")); +``` diff --git a/mongodb/querydsl/pom.xml b/mongodb/querydsl/pom.xml new file mode 100644 index 00000000..24ee33e7 --- /dev/null +++ b/mongodb/querydsl/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + + spring-data-mongodb-querydsl-example + + Spring Data MongoDB - Querydsl Example + + + org.springframework.data.examples + spring-data-mongodb-examples + 2.0.0.BUILD-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + + io.projectreactor + reactor-test + test + + + + + + + com.mysema.maven + apt-maven-plugin + ${apt.version} + + + com.querydsl + querydsl-apt + ${querydsl.version} + + + + + generate-sources + + process + + + target/generated-sources/queries + org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor + true + + + + + + + + + diff --git a/mongodb/querydsl/src/main/java/example/springdata/mongodb/Customer.java b/mongodb/querydsl/src/main/java/example/springdata/mongodb/Customer.java new file mode 100644 index 00000000..97dccbac --- /dev/null +++ b/mongodb/querydsl/src/main/java/example/springdata/mongodb/Customer.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019 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 + * + * https://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; + +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.util.Assert; + +/** + * An entity to represent a customer. + * + * @author Christoph Strobl + */ +@Document +public class Customer { + + private String id, firstname, lastname; + + /** + * Creates a new {@link Customer} with the given firstname and lastname. + * + * @param firstname must not be {@literal null} or empty. + * @param lastname must not be {@literal null} or empty. + */ + public Customer(String firstname, String lastname) { + + Assert.hasText(firstname, "Firstname must not be null or empty!"); + Assert.hasText(lastname, "Lastname must not be null or empty!"); + + this.firstname = firstname; + this.lastname = lastname; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + @Override + public String toString() { + return "Customer{" + "id='" + id + '\'' + ", firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Customer customer = (Customer) o; + + if (id != null ? !id.equals(customer.id) : customer.id != null) + return false; + if (firstname != null ? !firstname.equals(customer.firstname) : customer.firstname != null) + return false; + return lastname != null ? lastname.equals(customer.lastname) : customer.lastname == null; + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (firstname != null ? firstname.hashCode() : 0); + result = 31 * result + (lastname != null ? lastname.hashCode() : 0); + return result; + } +} diff --git a/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ApplicationConfiguration.java b/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ApplicationConfiguration.java new file mode 100644 index 00000000..df9eb1a7 --- /dev/null +++ b/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ApplicationConfiguration.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 + * + * https://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.reactive; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Configuration to connect to MongoDB using a {@link com.mongodb.reactivestreams.client.MongoClient}.
+ * Enables Spring Data repositories for MongoDB. + * + * @author Christoph Strobl + */ +@SpringBootApplication +class ApplicationConfiguration {} diff --git a/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ReactiveCustomerQuerydslRepository.java b/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ReactiveCustomerQuerydslRepository.java new file mode 100644 index 00000000..387c74b5 --- /dev/null +++ b/mongodb/querydsl/src/main/java/example/springdata/mongodb/reactive/ReactiveCustomerQuerydslRepository.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019 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 + * + * https://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.reactive; + +import example.springdata.mongodb.Customer; + +import org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +/** + * Reactive Querydsl supporting repository interface to manage {@link Customer} instances. + * + * @author Christoph Strobl + */ +interface ReactiveCustomerQuerydslRepository + extends ReactiveCrudRepository, ReactiveQuerydslPredicateExecutor { + +} diff --git a/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/ApplicationConfiguration.java b/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/ApplicationConfiguration.java new file mode 100644 index 00000000..eea5a9ed --- /dev/null +++ b/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/ApplicationConfiguration.java @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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 + * + * https://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.sync; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.mongodb.MongoClient; + +/** + * Configuration to connect to MongoDB using a {@link MongoClient}.
+ * Enables Spring Data repositories for MongoDB. + * + * @author Christoph Strobl + */ +@SpringBootApplication +class ApplicationConfiguration {} diff --git a/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/CustomerQuerydslRepository.java b/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/CustomerQuerydslRepository.java new file mode 100644 index 00000000..7d6a22c9 --- /dev/null +++ b/mongodb/querydsl/src/main/java/example/springdata/mongodb/sync/CustomerQuerydslRepository.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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 + * + * https://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.sync; + +import example.springdata.mongodb.Customer; + +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.repository.CrudRepository; + +/** + * Sync Querydsl supporting repository interface to manage {@link Customer} instances. + * + * @author Christoph Strobl + */ +interface CustomerQuerydslRepository extends CrudRepository, QuerydslPredicateExecutor { + +} diff --git a/mongodb/querydsl/src/test/java/example/springdata/mongodb/reactive/ReactiveCustomerRepositoryTests.java b/mongodb/querydsl/src/test/java/example/springdata/mongodb/reactive/ReactiveCustomerRepositoryTests.java new file mode 100644 index 00000000..078db80f --- /dev/null +++ b/mongodb/querydsl/src/test/java/example/springdata/mongodb/reactive/ReactiveCustomerRepositoryTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019 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 + * + * https://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.reactive; + +import static org.assertj.core.api.Assertions.*; + +import example.springdata.mongodb.Customer; +import example.springdata.mongodb.QCustomer; +import reactor.test.StepVerifier; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author Christoph Strobl + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ReactiveCustomerRepositoryTests { + + @Autowired ReactiveCustomerQuerydslRepository repository; + @Autowired MongoOperations operations; + + Customer dave, oliver, carter; + + @Before + public void setUp() { + + repository.deleteAll().as(StepVerifier::create).verifyComplete(); + + dave = new Customer("Dave", "Matthews"); + oliver = new Customer("Oliver August", "Matthews"); + carter = new Customer("Carter", "Beauford"); + + repository.save(dave).then().as(StepVerifier::create).verifyComplete(); + repository.save(oliver).then().as(StepVerifier::create).verifyComplete(); + repository.save(carter).then().as(StepVerifier::create).verifyComplete(); + } + + @Test + public void findAllByPredicate() { + + repository.findAll(QCustomer.customer.lastname.eq("Matthews")) // + .collectList() // + .as(StepVerifier::create) // + .assertNext(it -> assertThat(it).containsExactlyInAnyOrder(dave, oliver)) // + .verifyComplete(); + } + +} diff --git a/mongodb/querydsl/src/test/java/example/springdata/mongodb/sync/CustomerRepositoryTests.java b/mongodb/querydsl/src/test/java/example/springdata/mongodb/sync/CustomerRepositoryTests.java new file mode 100644 index 00000000..cd9b75dd --- /dev/null +++ b/mongodb/querydsl/src/test/java/example/springdata/mongodb/sync/CustomerRepositoryTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019 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 + * + * https://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.sync; + +import static org.assertj.core.api.Assertions.*; + +import example.springdata.mongodb.Customer; +import example.springdata.mongodb.QCustomer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author Christoph Strobl + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class CustomerRepositoryTests { + + @Autowired CustomerQuerydslRepository repository; + @Autowired MongoOperations operations; + + Customer dave, oliver, carter; + + @Before + public void setUp() { + + repository.deleteAll(); + + dave = repository.save(new Customer("Dave", "Matthews")); + oliver = repository.save(new Customer("Oliver August", "Matthews")); + carter = repository.save(new Customer("Carter", "Beauford")); + } + + @Test + public void findAllByPredicate() { + assertThat(repository.findAll(QCustomer.customer.lastname.eq("Matthews"))).containsExactlyInAnyOrder(dave, oliver); + } + +} diff --git a/mongodb/querydsl/src/test/resources/application.properties b/mongodb/querydsl/src/test/resources/application.properties new file mode 100644 index 00000000..c59a689b --- /dev/null +++ b/mongodb/querydsl/src/test/resources/application.properties @@ -0,0 +1,2 @@ +# Random port for embedded MongoDB +spring.data.mongodb.port=0