diff --git a/.gitignore b/.gitignore index b6a9550..436fae4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ /.idea *.iml .gitlab-ci.yml - +**/target/ diff --git a/README.md b/README.md index 93e2ca0..3cad942 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ and provides class and annotation to improve your developer experience using Pos Add the following dependency to your Maven project: ```xml - fr.ouestfrance.querydsl querydsl-postgrest @@ -51,7 +50,16 @@ implementing `PostgrestClient` interface. You can also specify authenticators, interceptors (retry, transform) and every configuration (timeout, default headers, cookies, ...) you need to deploy. -**Webclient configuration example** +#### WebClient configuration example + +Add the dependency : +```xml + + fr.ouestfrance.querydsl + querydsl-postgrest-webclient-adapter + ${querydsl-postgrest.version} + +``` ```java import com.fasterxml.jackson.databind.ObjectMapper; @@ -77,6 +85,42 @@ public class PostgrestConfiguration { } ``` +#### RestTemplate configuration example + +Add the dependency : +```xml + + fr.ouestfrance.querydsl + querydsl-postgrest-resttemplate-adapter + ${querydsl-postgrest.version} + +``` + +```java +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ouestfrance.querydsl.postgrest.PostgrestClient; +import fr.ouestfrance.querydsl.postgrest.PostgrestRestTemplate; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@Configuration +public class PostgrestConfiguration { + + @Bean + public PostgrestClient podstgrestClient() { + String serviceUrl = "http://localhost:9000"; + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(serviceUrl)); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault())); + return PostgrestRestTemplate.of(webclient); + } +} +``` + ### Create your first repository #### Specify your first search criteria @@ -334,4 +378,4 @@ The QueryDSL is licensed under [MIT License](https://opensource.org/license/mit/ [sonar-image]: https://sonarcloud.io/api/project_badges/measure?project=Ouest-France_querydsl-postgrest&metric=alert_status -[sonar-url]: https://sonarcloud.io/summary/new_code?id=Ouest-France_querydsl-postgrest \ No newline at end of file +[sonar-url]: https://sonarcloud.io/summary/new_code?id=Ouest-France_querydsl-postgrest diff --git a/pom.xml b/pom.xml index 535a73d..6946188 100644 --- a/pom.xml +++ b/pom.xml @@ -3,9 +3,10 @@ 4.0.0 fr.ouestfrance.querydsl - querydsl-postgrest + querydsl-postgrest-bom 1.2.2-SNAPSHOT - querydsl-postgrest + pom + querydsl-postgrest-bom Implementation of unified queryDSL for postgRest API https://github.com/ouest-france/querydsl-postgrest @@ -23,6 +24,11 @@ https://www.ouest-france.fr/qui-sommes-nous + + querydsl-postgrest + querydsl-postgrest-webclient-adapter + querydsl-postgrest-resttemplate-adapter + @@ -50,34 +56,13 @@ - - fr.ouestfrance.querydsl - querydsl - 1.2.0 - - - org.springframework - spring-webflux - 6.1.1 - - org.projectlombok lombok 1.18.28 provided - - com.fasterxml.jackson.core - jackson-databind - 2.15.3 - - - org.apache.commons - commons-lang3 - 3.13.0 - org.junit.jupiter junit-jupiter @@ -111,22 +96,16 @@ 3.2.2 - org.jacoco - jacoco-maven-plugin - 0.8.11 + org.apache.maven.plugins + maven-source-plugin + 3.2.1 - default-prepare-agent - - prepare-agent - - - - report + attach-sources + verify - report + jar-no-fork - test @@ -144,17 +123,23 @@ - org.apache.maven.plugins - maven-source-plugin - 3.2.1 + org.jacoco + jacoco-maven-plugin + 0.8.11 - attach-sources - verify + default-prepare-agent - jar-no-fork + prepare-agent + + report + + report + + test + @@ -193,4 +178,4 @@ - \ No newline at end of file + diff --git a/querydsl-postgrest-resttemplate-adapter/README.md b/querydsl-postgrest-resttemplate-adapter/README.md new file mode 100644 index 0000000..8f8150e --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/README.md @@ -0,0 +1,104 @@ +
+ logo-ouest-france +

PostgRest-RestTemplate-Adapter

+
+
+ +[![Build Status][maven-build-image]][maven-build-url] +[![Coverage][coverage-image]][coverage-url] +[![Quality Gate Status][sonar-image]][sonar-url] +[![Download][maven-central-image]][maven-central-url] + +
+ +**QueryDSL-PostgRest-RestTemplate-Adapter** is a httpclient adapter of [QueryDSL-Postgrest](https://github.com/Ouest-France/querydsl-postgrest). + +**PostgREST** is an open source project that provides a fully RESTful API from any existing PostgreSQL database + +## Getting Started + +### Maven integration + +Add the following dependency to your Maven project: + +```xml + + fr.ouestfrance.querydsl + querydsl-postgrest-resttemplate-adapter + ${querydsl-postgrest.version} + +``` + +### Gradle integration + +Add the following dependency to your gradle project: + +```groovy +implementation 'fr.ouestfrance.querydsl:querydsl-postgrest-resttemplate-adapter:${querydsl-postgrest.version}' +``` + +### Configure PostgrestClient +QueryDsl postgrest need implementation of PostgrestClient with a specific HttpAdapter. + +It's really easy to create your own HttpClientAdapter (RestTemplate, OkHttpClient, HttpConnexion, ...) by +implementing `PostgrestClient` interface. + +You can also specify authenticators, interceptors (retry, transform) and every configuration (timeout, default headers, +cookies, ...) you need to deploy. + +#### Configuration example + +```java +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ouestfrance.querydsl.postgrest.PostgrestClient; +import fr.ouestfrance.querydsl.postgrest.PostgrestRestTemplate; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@Configuration +public class PostgrestConfiguration { + + @Bean + public PostgrestClient podstgrestClient() { + String serviceUrl = "http://localhost:9000"; + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(serviceUrl)); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault())); + return PostgrestRestTemplate.of(webclient); + } +} +``` + +## Need Help ? + +If you need help with the library please start a new thread QA / Issue on github + +## Contributing + +If you want to request a feature or report a bug, please create a GitHub Issue + +If you want to make a contribution to the project, please create a PR + +## License + +The QueryDSL is licensed under [MIT License](https://opensource.org/license/mit/) + +[maven-build-image]: https://github.com/Ouest-France/querydsl-postgrest/actions/workflows/build.yml/badge.svg + +[maven-build-url]: https://github.com/Ouest-France/querydsl-postgrest/actions/workflows/build.yml + +[coverage-image]: https://codecov.io/gh/ouest-france/querydsl-postgrest/graph/badge.svg + +[coverage-url]: https://codecov.io/gh/ouest-france/querydsl-postgrest + +[maven-central-image]: https://maven-badges.herokuapp.com/maven-central/fr.ouestfrance.querydsl/querydsl-postgrest/badge.svg + +[maven-central-url]: https://mvnrepository.com/artifact/fr.ouestfrance.querydsl/querydsl-postgrest + +[sonar-image]: https://sonarcloud.io/api/project_badges/measure?project=Ouest-France_querydsl-postgrest&metric=alert_status + +[sonar-url]: https://sonarcloud.io/summary/new_code?id=Ouest-France_querydsl-postgrest diff --git a/querydsl-postgrest-resttemplate-adapter/pom.xml b/querydsl-postgrest-resttemplate-adapter/pom.xml new file mode 100644 index 0000000..d4aab66 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + fr.ouestfrance.querydsl + querydsl-postgrest-bom + ../pom.xml + 1.2.2-SNAPSHOT + + + querydsl-postgrest-resttemplate-adapter + + + + fr.ouestfrance.querydsl + querydsl-postgrest + ${project.version} + provided + + + org.springframework + spring-web + 6.1.2 + + + org.apache.commons + commons-lang3 + 3.14.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.3 + + + org.apache.httpcomponents.client5 + httpclient5 + 5.3 + test + + + diff --git a/querydsl-postgrest-resttemplate-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRestTemplate.java b/querydsl-postgrest-resttemplate-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRestTemplate.java new file mode 100644 index 0000000..38546f9 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRestTemplate.java @@ -0,0 +1,99 @@ +package fr.ouestfrance.querydsl.postgrest; + +import fr.ouestfrance.querydsl.postgrest.model.Page; +import fr.ouestfrance.querydsl.postgrest.model.PageImpl; +import fr.ouestfrance.querydsl.postgrest.model.Range; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.reflect.TypeUtils; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Rest interface for querying postgrest + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class PostgrestRestTemplate implements PostgrestClient { + + /** + * restTemplate + */ + private final RestTemplate restTemplate; + + /** + * Postgrest restTemplate adapter + * + * @param restTemplate restTemplate + * @return PostgrestResttemplate implementation + */ + public static PostgrestRestTemplate of(RestTemplate restTemplate) { + return new PostgrestRestTemplate(restTemplate); + } + + @Override + public Page search(String resource, Map> params, + Map> headers, Class clazz) { + ResponseEntity> response = restTemplate.exchange(restTemplate.getUriTemplateHandler() + .expand(UriComponentsBuilder.fromPath(resource) + .queryParams(toMultiMap(params)).build().toString(), new HashMap<>()), HttpMethod.GET, + new HttpEntity<>(null, toHeaders(headers)), listRef(clazz)); + // Retrieve result headers + return Optional.of(response) + .map(HttpEntity::getBody) + .map(x -> { + PageImpl page = new PageImpl<>(x, null, x.size(), 1); + List contentRangeHeaders = response.getHeaders().get("Content-Range"); + if (contentRangeHeaders != null) { + Range range = Range.of(contentRangeHeaders.stream().findFirst().toString()); + page.withRange(range); + } + return (Page) page; + }).orElse(Page.empty()); + } + + @Override + public List post(String resource, List value, Map> headers, Class clazz) { + HttpHeaders httpHeaders = toHeaders(headers); + return restTemplate.exchange(resource, HttpMethod.POST, new HttpEntity<>(value, httpHeaders), listRef(clazz)).getBody(); + } + + @Override + public List patch(String resource, Map> params, Object value, Map> headers, Class clazz) { + MultiValueMap queryParams = toMultiMap(params); + return restTemplate.exchange(restTemplate.getUriTemplateHandler() + .expand(UriComponentsBuilder.fromPath(resource).queryParams(queryParams).build().toString(), new HashMap<>()), + HttpMethod.PATCH, new HttpEntity<>(value, toHeaders(headers)), listRef(clazz)) + .getBody(); + } + + @Override + public List delete(String resource, Map> params, Map> headers, Class clazz) { + MultiValueMap queryParams = toMultiMap(params); + return restTemplate.exchange(restTemplate.getUriTemplateHandler().expand(UriComponentsBuilder.fromPath(resource) + .queryParams(queryParams).build().toString(), new HashMap<>()), HttpMethod.DELETE, new HttpEntity<>(null, toHeaders(headers)), listRef(clazz)).getBody(); + } + + private static ParameterizedTypeReference> listRef(Class clazz) { + return ParameterizedTypeReference.forType(TypeUtils.parameterize(List.class, clazz)); + } + + private static MultiValueMap toMultiMap(Map> params) { + return new LinkedMultiValueMap<>(params); + } + + private static HttpHeaders toHeaders(Map> headers) { + return new HttpHeaders(toMultiMap(headers)); + } +} diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryTest.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryTest.java new file mode 100644 index 0000000..3724ad4 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryTest.java @@ -0,0 +1,137 @@ +package fr.ouestfrance.querydsl.postgrest; + +import fr.ouestfrance.querydsl.postgrest.app.Post; +import fr.ouestfrance.querydsl.postgrest.app.PostRepository; +import fr.ouestfrance.querydsl.postgrest.app.PostRequest; +import fr.ouestfrance.querydsl.postgrest.criterias.Criteria; +import fr.ouestfrance.querydsl.postgrest.model.Page; +import fr.ouestfrance.querydsl.postgrest.model.Pageable; +import lombok.SneakyThrows; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.client.MockServerClient; +import org.mockserver.junit.jupiter.MockServerSettings; +import org.mockserver.model.HttpRequest; +import org.mockserver.model.HttpResponse; +import org.mockserver.model.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; +import shaded_package.org.apache.commons.io.IOUtils; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@MockServerSettings(ports = 8007) +class PostgrestRepositoryTest { + + private PostgrestRepository repository; + + @BeforeEach + void beforeEach(MockServerClient client) { + client.reset(); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://localhost:8007")); + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault())); + repository = new PostRepository(PostgrestRestTemplate.of(restTemplate)); + } + + @Test + void shouldSearchPosts(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "*,authors(*)")) + .respond(jsonFileResponse("posts.json").withHeader("Content-Range", "0-6/300")); + Page search = repository.search(new PostRequest(), Pageable.ofSize(6)); + assertEquals(300, search.getTotalElements()); + assertEquals(50, search.getTotalPages()); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldSearchPostsWithoutContentRange(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "*,authors(*)")) + .respond(jsonFileResponse("posts.json")); + Page search = repository.search(new PostRequest(), Pageable.ofSize(6)); + assertEquals(6, search.getTotalElements()); + assertEquals(1, search.getTotalPages()); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldFindById(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts") + .withQueryStringParameter("id", "eq.1") + .withQueryStringParameter("select", "*,authors(*)")) + .respond(jsonFileResponse("posts.json").withHeader("Content-Range", "0-6/300")); + Page search = repository.search(Criteria.byId("1"), Pageable.ofSize(6)); + assertEquals(300, search.getTotalElements()); + assertEquals(50, search.getTotalPages()); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldSearchGetByIds(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts") + .withQueryStringParameter("id", "in.(1,2,3)") + .withQueryStringParameter("select", "*,authors(*)")) + .respond(jsonFileResponse("posts.json").withHeader("Content-Range", "0-6/300")); + Page search = repository.search(Criteria.byIds("1", "2", "3"), Pageable.ofSize(6)); + assertEquals(300, search.getTotalElements()); + assertEquals(50, search.getTotalPages()); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldUpsertPost(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts")) + .respond(jsonFileResponse("new_posts.json")); + List result = repository.upsert(new ArrayList<>(List.of(new Post()))); + assertNotNull(result); + result.stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + + } + + + @Test + void shouldPatchPost(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("userId", "eq.25")) + .respond(jsonFileResponse("posts.json")); + PostRequest criteria = new PostRequest(); + criteria.setUserId(25); + List result = repository.patch(criteria, new Post()); + assertNotNull(result); + result.stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldDeletePost(MockServerClient client) { + client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("userId", "eq.25")) + .respond(jsonFileResponse("posts.json")); + PostRequest criteria = new PostRequest(); + criteria.setUserId(25); + List result = repository.delete(criteria); + assertNotNull(result); + result.stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + private HttpResponse jsonFileResponse(String resourceFileName) { + return HttpResponse.response().withContentType(MediaType.APPLICATION_JSON) + .withBody(jsonOf(resourceFileName)); + } + + @SneakyThrows + private String jsonOf(String name) { + return IOUtils.resourceToString(name, Charset.defaultCharset(), getClass().getClassLoader()); + } +} diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java new file mode 100644 index 0000000..f1f9047 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java @@ -0,0 +1,16 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class Post { + + private Integer userId; + private String id; + private String title; + private String body; +} diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java new file mode 100644 index 0000000..86a69bb --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java @@ -0,0 +1,21 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PostDeleteRequest { + + @FilterField(operation = FilterOperation.IN.class) + private List id; + +} diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java similarity index 93% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java rename to querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java index 88f9d77..1d6dd30 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java @@ -1,7 +1,6 @@ package fr.ouestfrance.querydsl.postgrest.app; import fr.ouestfrance.querydsl.postgrest.PostgrestClient; -import fr.ouestfrance.querydsl.postgrest.PostgrestWebClient; import fr.ouestfrance.querydsl.postgrest.PostgrestRepository; import fr.ouestfrance.querydsl.postgrest.annotations.Header; import fr.ouestfrance.querydsl.postgrest.annotations.PostgrestConfiguration; diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java new file mode 100644 index 0000000..2ad6258 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java @@ -0,0 +1,35 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PostRequest { + + @FilterField + private Integer userId; + @FilterField(operation = FilterOperation.NEQ.class) + private Integer id; + @FilterField(operation = FilterOperation.LIKE.class) + private String title; + @FilterField(operation = FilterOperation.GT.class, key = "birthDate") + @FilterField(operation = FilterOperation.LTE.class, key = "startDate") + @FilterField(operation = FilterOperation.GTE.class, key = "endDate", orNull = true) + @FilterField(operation = FilterOperation.LT.class, key = "deathDate", orNull = true) + private LocalDate validDate; + + @FilterField(operation = FilterOperation.IN.class, key = "status") + private List codes; + @FilterField(operation = FilterOperation.NOTIN.class, key = "status") + private List excludes; +} diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java new file mode 100644 index 0000000..b0eb973 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java @@ -0,0 +1,21 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Select(alias = "author", value = "authors!inner(name)") +public class PostRequestWithAuthorOrSubject { + + // subject = $subject OR author.name= $author + @FilterField(groupName = "subjectOrAuthorName") + private String subject; + + @FilterField(key = "author.name", groupName = "subjectOrAuthorName") + private String author; + +} + diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java rename to querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java diff --git a/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java new file mode 100644 index 0000000..c4094e5 --- /dev/null +++ b/querydsl-postgrest-resttemplate-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java @@ -0,0 +1,36 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Select(alias = "filtreDepartement", value = "editionsRegroupements_v1!inner(edition_v1!inner(departement_v1!inner(code)))") +@Select(alias = "filtreEditionsRegroupements", value = "editionsRegroupements_v1!inner(dateDebutValidite,dateFinValidite)") +@Select(alias = "filtrePublication", value = "publication_v1!inner(code,dateDebutValidite,dateFinValidite)") +public class PublicationRequest { + + @FilterField(key = "filtrePublication.code") + String code; + + @FilterField(key = "filtrePublication.dateDebutValidite", operation = FilterOperation.LTE.class) + @FilterField(key = "filtrePublication.dateFinValidite", operation = FilterOperation.GTE.class, orNull = true) + @FilterField(key = "filtreEditionRegroupements.dateDebutValidite", operation = FilterOperation.LTE.class) + @FilterField(key = "filtreEditionRegroupements.dateFinValidite", operation = FilterOperation.GTE.class, orNull = true) + LocalDate dateValide; + + @FilterField(key = "filtreDepartement.edition_v1.departement_v1.code") + String codeDepartement; + + @FilterField(key = "portee@>") + String portee; +} diff --git a/src/test/resources/new_posts.json b/querydsl-postgrest-resttemplate-adapter/src/test/resources/new_posts.json similarity index 100% rename from src/test/resources/new_posts.json rename to querydsl-postgrest-resttemplate-adapter/src/test/resources/new_posts.json diff --git a/src/test/resources/posts.json b/querydsl-postgrest-resttemplate-adapter/src/test/resources/posts.json similarity index 100% rename from src/test/resources/posts.json rename to querydsl-postgrest-resttemplate-adapter/src/test/resources/posts.json diff --git a/querydsl-postgrest-webclient-adapter/README.md b/querydsl-postgrest-webclient-adapter/README.md new file mode 100644 index 0000000..80a2727 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/README.md @@ -0,0 +1,102 @@ +
+ logo-ouest-france +

PostgRest-WebClient-Adapter

+
+
+ +[![Build Status][maven-build-image]][maven-build-url] +[![Coverage][coverage-image]][coverage-url] +[![Quality Gate Status][sonar-image]][sonar-url] +[![Download][maven-central-image]][maven-central-url] + +
+ +**QueryDSL-PostgRest-WebClient-Adapter** is a httpclient adapter of [QueryDSL-Postgrest](https://github.com/Ouest-France/querydsl-postgrest). + +**PostgREST** is an open source project that provides a fully RESTful API from any existing PostgreSQL database + +## Getting Started + +### Maven integration + +Add the following dependency to your Maven project: + +```xml + + fr.ouestfrance.querydsl + querydsl-postgrest-webclient-adapter + ${querydsl-postgrest.version} + +``` + +### Gradle integration + +Add the following dependency to your gradle project: + +```groovy +implementation 'fr.ouestfrance.querydsl:querydsl-postgrest-webclient-adapter:${querydsl-postgrest.version}' +``` + +### Configure PostgrestClient +QueryDsl postgrest need implementation of PostgrestClient with a specific HttpAdapter. + +It's really easy to create your own HttpClientAdapter (RestTemplate, OkHttpClient, HttpConnexion, ...) by +implementing `PostgrestClient` interface. + +You can also specify authenticators, interceptors (retry, transform) and every configuration (timeout, default headers, +cookies, ...) you need to deploy. + +#### Configuration example + +```java +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ouestfrance.querydsl.postgrest.PostgrestClient; +import fr.ouestfrance.querydsl.postgrest.PostgrestWebClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class PostgrestConfiguration { + + @Bean + public PostgrestClient podstgrestClient() { + String serviceUrl = "http://localhost:9000"; + WebClient webclient = WebClient.builder() + .baseUrl(serviceUrl) + // Here you can add any filters or default configuration you want + .build(); + + return PostgrestWebClient.of(webclient); + } +} +``` +## Need Help ? + +If you need help with the library please start a new thread QA / Issue on github + +## Contributing + +If you want to request a feature or report a bug, please create a GitHub Issue + +If you want to make a contribution to the project, please create a PR + +## License + +The QueryDSL is licensed under [MIT License](https://opensource.org/license/mit/) + +[maven-build-image]: https://github.com/Ouest-France/querydsl-postgrest/actions/workflows/build.yml/badge.svg + +[maven-build-url]: https://github.com/Ouest-France/querydsl-postgrest/actions/workflows/build.yml + +[coverage-image]: https://codecov.io/gh/ouest-france/querydsl-postgrest/graph/badge.svg + +[coverage-url]: https://codecov.io/gh/ouest-france/querydsl-postgrest + +[maven-central-image]: https://maven-badges.herokuapp.com/maven-central/fr.ouestfrance.querydsl/querydsl-postgrest/badge.svg + +[maven-central-url]: https://mvnrepository.com/artifact/fr.ouestfrance.querydsl/querydsl-postgrest + +[sonar-image]: https://sonarcloud.io/api/project_badges/measure?project=Ouest-France_querydsl-postgrest&metric=alert_status + +[sonar-url]: https://sonarcloud.io/summary/new_code?id=Ouest-France_querydsl-postgrest diff --git a/querydsl-postgrest-webclient-adapter/pom.xml b/querydsl-postgrest-webclient-adapter/pom.xml new file mode 100644 index 0000000..65d473c --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + fr.ouestfrance.querydsl + querydsl-postgrest-bom + ../pom.xml + 1.2.2-SNAPSHOT + + + querydsl-postgrest-webclient-adapter + + + + fr.ouestfrance.querydsl + querydsl-postgrest + ${project.version} + provided + + + org.springframework + spring-webflux + 6.1.2 + + + org.apache.commons + commons-lang3 + 3.14.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.3 + + + diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java b/querydsl-postgrest-webclient-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java similarity index 77% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java rename to querydsl-postgrest-webclient-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java index 0391c93..cd5f99d 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java +++ b/querydsl-postgrest-webclient-adapter/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestWebClient.java @@ -11,10 +11,12 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -45,11 +47,11 @@ public static PostgrestWebClient of(WebClient webClient) { } @Override - public Page search(String resource, MultiValueMap params, - MultiValueMap headers, Class clazz) { + public Page search(String resource, Map> params, + Map> headers, Class clazz) { ResponseEntity> response = webClient.get().uri(uriBuilder -> { uriBuilder.path(resource); - uriBuilder.queryParams(params); + uriBuilder.queryParams(toMultiMap(params)); return uriBuilder.build(); }).headers(httpHeaders -> safeAdd(headers, httpHeaders) @@ -71,14 +73,15 @@ public Page search(String resource, MultiValueMap params, }).orElse(Page.empty()); } - private static void safeAdd(MultiValueMap headers, HttpHeaders httpHeaders) { - Optional.ofNullable(headers).ifPresent(httpHeaders::addAll); + private static void safeAdd(Map> headers, HttpHeaders httpHeaders) { + Optional.ofNullable(headers) + .map(PostgrestWebClient::toMultiMap).ifPresent(httpHeaders::addAll); // Add contentType with default on call if webclient default is not set httpHeaders.put(CONTENT_TYPE, List.of(MediaType.APPLICATION_JSON_VALUE)); } @Override - public List post(String resource, List value, MultiValueMap headers, Class clazz) { + public List post(String resource, List value, Map> headers, Class clazz) { return webClient.post().uri(uriBuilder -> { uriBuilder.path(resource); return uriBuilder.build(); @@ -91,10 +94,10 @@ public List post(String resource, List value, MultiValueMap List patch(String resource, MultiValueMap params, Object value, MultiValueMap headers, Class clazz) { + public List patch(String resource, Map> params, Object value, Map> headers, Class clazz) { return webClient.patch().uri(uriBuilder -> { uriBuilder.path(resource); - uriBuilder.queryParams(params); + uriBuilder.queryParams(toMultiMap(params)); return uriBuilder.build(); }) .bodyValue(value) @@ -104,10 +107,10 @@ public List patch(String resource, MultiValueMap params, } @Override - public List delete(String resource, MultiValueMap params, MultiValueMap headers, Class clazz) { + public List delete(String resource, Map> params, Map> headers, Class clazz) { return webClient.delete().uri(uriBuilder -> { uriBuilder.path(resource); - uriBuilder.queryParams(params); + uriBuilder.queryParams(toMultiMap(params)); return uriBuilder.build(); }).headers(httpHeaders -> safeAdd(headers, httpHeaders)) .retrieve() @@ -118,5 +121,8 @@ private static ParameterizedTypeReference> listRef(Class clazz) { return ParameterizedTypeReference.forType(TypeUtils.parameterize(List.class, clazz)); } + private static MultiValueMap toMultiMap(Map> params) { + return new LinkedMultiValueMap<>(params); + } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java similarity index 93% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java rename to querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java index c6dd2ee..0331ab3 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/PostrgrestRepositoryTest.java @@ -24,7 +24,6 @@ import static org.junit.jupiter.api.Assertions.*; -@ExtendWith(MockServerExtension.class) @MockServerSettings(ports = 8007) class PostrgrestRepositoryTest { @@ -32,14 +31,9 @@ class PostrgrestRepositoryTest { .baseUrl("http://localhost:8007/") .build())); - private final ClientAndServer client; - - public PostrgrestRepositoryTest(ClientAndServer client) { - this.client = client; - } @Test - void shouldSearchPosts() { + void shouldSearchPosts(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "*,authors(*)")) .respond(jsonFileResponse("posts.json").withHeader("Content-Range", "0-6/300")); Page search = repository.search(new PostRequest(), Pageable.ofSize(6)); @@ -53,7 +47,7 @@ void shouldSearchPosts() { } @Test - void shouldFindById() { + void shouldFindById(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts") .withQueryStringParameter("id", "eq.1") .withQueryStringParameter("select", "*,authors(*)")) @@ -69,7 +63,7 @@ void shouldFindById() { } @Test - void shouldSearchGetByIds() { + void shouldSearchGetByIds(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts") .withQueryStringParameter("id", "in.(1,2,3)") .withQueryStringParameter("select", "*,authors(*)")) @@ -85,7 +79,7 @@ void shouldSearchGetByIds() { } @Test - void shouldUpsertPost() { + void shouldUpsertPost(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts")) .respond(jsonFileResponse("new_posts.json")); List result = repository.upsert(new ArrayList<>(List.of(new Post()))); @@ -96,7 +90,7 @@ void shouldUpsertPost() { @Test - void shouldPatchPost() { + void shouldPatchPost(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("userId", "eq.25")) .respond(jsonFileResponse("posts.json")); PostRequest criteria = new PostRequest(); @@ -107,7 +101,7 @@ void shouldPatchPost() { } @Test - void shouldDeletePost() { + void shouldDeletePost(ClientAndServer client) { client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("userId", "eq.25")) .respond(jsonFileResponse("posts.json")); PostRequest criteria = new PostRequest(); diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java new file mode 100644 index 0000000..f1f9047 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java @@ -0,0 +1,16 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class Post { + + private Integer userId; + private String id; + private String title; + private String body; +} diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java new file mode 100644 index 0000000..86a69bb --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java @@ -0,0 +1,21 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PostDeleteRequest { + + @FilterField(operation = FilterOperation.IN.class) + private List id; + +} diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java new file mode 100644 index 0000000..1d6dd30 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java @@ -0,0 +1,22 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.postgrest.PostgrestClient; +import fr.ouestfrance.querydsl.postgrest.PostgrestRepository; +import fr.ouestfrance.querydsl.postgrest.annotations.Header; +import fr.ouestfrance.querydsl.postgrest.annotations.PostgrestConfiguration; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import fr.ouestfrance.querydsl.postgrest.model.Prefer; + +import static fr.ouestfrance.querydsl.postgrest.annotations.Header.Method.UPSERT; + +@PostgrestConfiguration(resource = "posts") +@Select("authors(*)") +@Header(key = Prefer.HEADER, value = Prefer.Return.REPRESENTATION) +@Header(key = Prefer.HEADER, value = Prefer.Resolution.MERGE_DUPLICATES, methods = UPSERT) +public class PostRepository extends PostgrestRepository { + + public PostRepository(PostgrestClient client) { + super(client); + } + +} diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java new file mode 100644 index 0000000..2ad6258 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java @@ -0,0 +1,35 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class PostRequest { + + @FilterField + private Integer userId; + @FilterField(operation = FilterOperation.NEQ.class) + private Integer id; + @FilterField(operation = FilterOperation.LIKE.class) + private String title; + @FilterField(operation = FilterOperation.GT.class, key = "birthDate") + @FilterField(operation = FilterOperation.LTE.class, key = "startDate") + @FilterField(operation = FilterOperation.GTE.class, key = "endDate", orNull = true) + @FilterField(operation = FilterOperation.LT.class, key = "deathDate", orNull = true) + private LocalDate validDate; + + @FilterField(operation = FilterOperation.IN.class, key = "status") + private List codes; + @FilterField(operation = FilterOperation.NOTIN.class, key = "status") + private List excludes; +} diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java new file mode 100644 index 0000000..b0eb973 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java @@ -0,0 +1,21 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Select(alias = "author", value = "authors!inner(name)") +public class PostRequestWithAuthorOrSubject { + + // subject = $subject OR author.name= $author + @FilterField(groupName = "subjectOrAuthorName") + private String subject; + + @FilterField(key = "author.name", groupName = "subjectOrAuthorName") + private String author; + +} + diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java new file mode 100644 index 0000000..6dbd62c --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java @@ -0,0 +1,23 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterFields; +import fr.ouestfrance.querydsl.FilterOperation; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Select(alias = "filterFormats", value = "formats!inner(minSize, maxSize)") +public class PostRequestWithSize { + + // size = $size OR (minSize < size AND maxSize > size) + @FilterField(key = "size", groupName = "sizeOrGroup") + @FilterFields(groupName = "sizeOrGroup", value = { + @FilterField(key = "filterFormats.minSize", operation = FilterOperation.GTE.class), + @FilterField(key = "filterFormats.maxSize", operation = FilterOperation.LTE.class, orNull = true) + }) + private String size; +} + diff --git a/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java new file mode 100644 index 0000000..c4094e5 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java @@ -0,0 +1,36 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterOperation; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDate; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Select(alias = "filtreDepartement", value = "editionsRegroupements_v1!inner(edition_v1!inner(departement_v1!inner(code)))") +@Select(alias = "filtreEditionsRegroupements", value = "editionsRegroupements_v1!inner(dateDebutValidite,dateFinValidite)") +@Select(alias = "filtrePublication", value = "publication_v1!inner(code,dateDebutValidite,dateFinValidite)") +public class PublicationRequest { + + @FilterField(key = "filtrePublication.code") + String code; + + @FilterField(key = "filtrePublication.dateDebutValidite", operation = FilterOperation.LTE.class) + @FilterField(key = "filtrePublication.dateFinValidite", operation = FilterOperation.GTE.class, orNull = true) + @FilterField(key = "filtreEditionRegroupements.dateDebutValidite", operation = FilterOperation.LTE.class) + @FilterField(key = "filtreEditionRegroupements.dateFinValidite", operation = FilterOperation.GTE.class, orNull = true) + LocalDate dateValide; + + @FilterField(key = "filtreDepartement.edition_v1.departement_v1.code") + String codeDepartement; + + @FilterField(key = "portee@>") + String portee; +} diff --git a/querydsl-postgrest-webclient-adapter/src/test/resources/new_posts.json b/querydsl-postgrest-webclient-adapter/src/test/resources/new_posts.json new file mode 100644 index 0000000..00383e4 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/resources/new_posts.json @@ -0,0 +1,8 @@ +[ + { + "userId": 1, + "id": 6, + "title": "dolorem eum magni eos aperiam quia", + "body": "ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae" + } +] \ No newline at end of file diff --git a/querydsl-postgrest-webclient-adapter/src/test/resources/posts.json b/querydsl-postgrest-webclient-adapter/src/test/resources/posts.json new file mode 100644 index 0000000..984a7a4 --- /dev/null +++ b/querydsl-postgrest-webclient-adapter/src/test/resources/posts.json @@ -0,0 +1,38 @@ +[ + { + "userId": 1, + "id": 1, + "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" + }, + { + "userId": 1, + "id": 2, + "title": "qui est esse", + "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" + }, + { + "userId": 1, + "id": 3, + "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", + "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" + }, + { + "userId": 1, + "id": 4, + "title": "eum et est occaecati", + "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit" + }, + { + "userId": 1, + "id": 5, + "title": "nesciunt quas odio", + "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque" + }, + { + "userId": 1, + "id": 6, + "title": "dolorem eum magni eos aperiam quia", + "body": "ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae" + } +] \ No newline at end of file diff --git a/querydsl-postgrest/pom.xml b/querydsl-postgrest/pom.xml new file mode 100644 index 0000000..8f3e46f --- /dev/null +++ b/querydsl-postgrest/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + fr.ouestfrance.querydsl + querydsl-postgrest-bom + ../pom.xml + 1.2.2-SNAPSHOT + + + querydsl-postgrest + + + fr.ouestfrance.querydsl + querydsl + 1.2.0 + + + diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java similarity index 69% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java index 6333cf5..d05e748 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestClient.java @@ -1,9 +1,9 @@ package fr.ouestfrance.querydsl.postgrest; import fr.ouestfrance.querydsl.postgrest.model.Page; -import org.springframework.util.MultiValueMap; import java.util.List; +import java.util.Map; /** * Rest interface for querying postgrest @@ -20,8 +20,8 @@ public interface PostgrestClient { * @return ResponseEntity containing the results */ - Page search(String resource, MultiValueMap params, - MultiValueMap headers, Class clazz); + Page search(String resource, Map> params, + Map> headers, Class clazz); /** * Save body @@ -33,7 +33,7 @@ Page search(String resource, MultiValueMap params, * @param clazz type of return * @return list of inserted objects */ - List post(String resource, List value, MultiValueMap headers, Class clazz); + List post(String resource, List value, Map> headers, Class clazz); /** * Patch data @@ -46,7 +46,7 @@ Page search(String resource, MultiValueMap params, * @param clazz type of return * @return list of patched objects */ - List patch(String resource, MultiValueMap params, Object value, MultiValueMap headers, Class clazz); + List patch(String resource, Map> params, Object value, Map> headers, Class clazz); /** * Delete data @@ -58,6 +58,6 @@ Page search(String resource, MultiValueMap params, * @param clazz type of return * @return list of deleted objects */ - List delete(String resource, MultiValueMap params, MultiValueMap headers, Class clazz); + List delete(String resource, Map> params, Map> headers, Class clazz); } diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java similarity index 90% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java index 4722be8..50188e3 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestFilterOperation.java @@ -4,6 +4,9 @@ import fr.ouestfrance.querydsl.service.validators.ValidatedBy; import fr.ouestfrance.querydsl.service.validators.impl.StringValidator; +/** + * Accessors of specific filter operations (extend FilterOperation) + */ public interface PostgrestFilterOperation { /** * Case-insensitive like diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java similarity index 76% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java index bfaf8dd..3504e30 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepository.java @@ -13,10 +13,8 @@ import fr.ouestfrance.querydsl.postgrest.model.impl.SelectFilter; import fr.ouestfrance.querydsl.postgrest.services.ext.PostgrestQueryProcessorService; import fr.ouestfrance.querydsl.service.ext.QueryDslProcessorService; -import org.springframework.core.GenericTypeResolver; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; +import java.lang.reflect.ParameterizedType; import java.util.*; /** @@ -28,9 +26,9 @@ public class PostgrestRepository implements Repository { private final QueryDslProcessorService processorService = new PostgrestQueryProcessorService(); private final PostgrestConfiguration annotation; - private final Map> headersMap = new EnumMap<>(Header.Method.class); + private final Map>> headersMap = new EnumMap<>(Header.Method.class); private final PostgrestClient client; - private final Class clazz; + private Class clazz; /** * Postgrest Repository constructor @@ -45,25 +43,32 @@ public PostgrestRepository(PostgrestClient client) { } annotation = getClass().getAnnotation(PostgrestConfiguration.class); // Create headerMap - Arrays.stream(getClass().getAnnotationsByType(Header.class)).forEach(header -> Arrays.stream(header.methods()) - .forEach(method -> - headersMap.computeIfAbsent(method, x -> new LinkedMultiValueMap<>()) - .addAll(header.key(), Arrays.asList(header.value())) - ) - ); - //noinspection unchecked - clazz = (Class) GenericTypeResolver.resolveTypeArgument(getClass(), PostgrestRepository.class); + Arrays.stream(getClass().getAnnotationsByType(Header.class)) + .forEach(header -> Arrays.stream(header.methods()) + .forEach(method -> + headersMap.computeIfAbsent(method, x -> new LinkedHashMap<>()) + .computeIfAbsent(header.key(), x -> new ArrayList<>()) + .addAll(Arrays.asList(header.value())) + ) + ); + + if (getClass().getGenericSuperclass() instanceof ParameterizedType type) { + //noinspection unchecked + clazz = (Class) type.getActualTypeArguments()[0]; + } + } @Override public Page search(Object criteria, Pageable pageable) { List queryParams = processorService.process(criteria); - MultiValueMap headers = headerMap(Header.Method.GET); + Map> headers = headerMap(Header.Method.GET); // Add pageable if present if (pageable.getPageSize() > 0) { - headers.add("Range-Unit", "items"); - headers.add("Range", pageable.toRange()); - headers.add("Prefers", "count=" + annotation.countStrategy().name().toLowerCase()); + headers.put("Range-Unit", List.of("items")); + headers.put("Range", List.of(pageable.toRange())); + headers.computeIfAbsent("Prefers", x -> new ArrayList<>()) + .add("count=" + annotation.countStrategy().name().toLowerCase()); } // Add sort if present if (pageable.getSort() != null) { @@ -108,9 +113,9 @@ public List delete(Object criteria) { * @param filters list of filters * @return map of query strings */ - private MultiValueMap toMap(List filters) { - MultiValueMap map = new LinkedMultiValueMap<>(); - filters.forEach(x -> map.add(x.getKey(), x.getFilterString())); + private Map> toMap(List filters) { + Map> map = new LinkedHashMap<>(); + filters.forEach(x -> map.computeIfAbsent(x.getKey(), key -> new ArrayList<>()).add(x.getFilterString())); return map; } @@ -133,10 +138,9 @@ private Optional getSelects(Object criteria) { attributes.addAll(Arrays.stream(criteriaAnnotation).map(x -> new SelectFilter.Attribute(x.alias(), x.value())).toList()); } } - if (attributes.isEmpty()) { - return Optional.empty(); - } - return Optional.of(SelectFilter.of(attributes)); + return Optional.of(attributes) + .filter(x -> !x.isEmpty()) + .map(SelectFilter::of); } /** @@ -174,7 +178,10 @@ public T getOne(Object criteria) { * @param method method * @return header map */ - private MultiValueMap headerMap(Header.Method method) { - return Optional.ofNullable(headersMap.get(method)).orElse(new LinkedMultiValueMap<>()); + private Map> headerMap(Header.Method method) { + Map> map = new LinkedHashMap<>(); + Optional.ofNullable(headersMap.get(method)) + .ifPresent(map::putAll); + return map; } } diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/Repository.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/Repository.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/Repository.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/Repository.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Header.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Header.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Header.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Header.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Headers.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Headers.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Headers.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Headers.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/PostgrestConfiguration.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/PostgrestConfiguration.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/PostgrestConfiguration.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/PostgrestConfiguration.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Select.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Select.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Select.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Select.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Selects.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Selects.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Selects.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/annotations/Selects.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/FilterVisitor.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/FilterVisitor.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/builders/FilterVisitor.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/FilterVisitor.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/QueryFilterVisitor.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/QueryFilterVisitor.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/builders/QueryFilterVisitor.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/builders/QueryFilterVisitor.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ById.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ById.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ById.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ById.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ByIds.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ByIds.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ByIds.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/ByIds.java diff --git a/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java new file mode 100644 index 0000000..143b8e4 --- /dev/null +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java @@ -0,0 +1,31 @@ +package fr.ouestfrance.querydsl.postgrest.criterias; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * Criterias class + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class Criteria { + + /** + * Allow to generate a simple ById Criteria + * @param id identifier to search + * @return criteria object + */ + public static Object byId(Comparable id) { + return new ById(id); + } + + /** + * Allow to generate a simple ByIds Criteria + * @param ids list of ids + * @return criteria object + */ + public static Object byIds(Comparable... ids) { + return new ByIds(List.of(ids)); + } +} diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/AbstractMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/AbstractMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/AbstractMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/AbstractMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/EqualsMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/EqualsMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/EqualsMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/EqualsMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanEqualsMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanEqualsMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanEqualsMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanEqualsMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/GreaterThanMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanEqualsMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanEqualsMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanEqualsMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanEqualsMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LessThanMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotEqualsMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotEqualsMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotEqualsMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotEqualsMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapper.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapper.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapper.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapper.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/Operators.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/Operators.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/Operators.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/mappers/Operators.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Filter.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Filter.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Filter.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Filter.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java similarity index 88% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java index 5ddf30c..5fff579 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Page.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @@ -98,10 +99,13 @@ default Page map(Function converter) { return new PageImpl<>(stream().map(converter).toList(), getPageable(), getTotalElements(), getTotalPages()); } + /** + * Check that page has next page + * @return true if totalPages is greater than pageNumber + */ default boolean hasNext() { - if(getPageable() == null) { - return false; - } - return getPageable().getPageNumber() + 1 < getTotalPages(); + return Optional.ofNullable(getPageable()) + .map(pageable -> pageable.getPageNumber() +1 < getTotalPages()) + .orElse(false); } } diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageImpl.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageImpl.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageImpl.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageImpl.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageRequest.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageRequest.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageRequest.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/PageRequest.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java similarity index 93% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java index b3c0769..340b2ea 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Pageable.java @@ -97,10 +97,18 @@ default int pageLimit() { return pageOffset() + getPageSize() - 1; } + /** + * Return the next page + * @return next page + */ default Pageable next() { return new PageRequest(getPageNumber() + 1, getPageSize(), getSort()); } + /** + * Return the previous page or the first one + * @return previous page + */ default Pageable previous() { return getPageNumber() == 0 ? this : new PageRequest(getPageNumber() - 1, getPageSize(), getSort()); } diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java similarity index 98% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java index c5d0da0..5be96d6 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Prefer.java @@ -69,10 +69,10 @@ public static class Resolution { /** * You can make an upsert with POST and the Prefer: resolution=merge-duplicates header */ - public static final String MERGE_DUPLICATES = "resolution=merge_duplicates"; + public static final String MERGE_DUPLICATES = "resolution=merge-duplicates"; /** * You can also choose to ignore the duplicates with Prefer: resolution=ignore-duplicates */ - public static final String IGNORE_DUPLICATES = "resolution=ignore_duplicates"; + public static final String IGNORE_DUPLICATES = "resolution=ignore-duplicates"; } } diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Range.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Range.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Range.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Range.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Sort.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Sort.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/Sort.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/Sort.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/MissingConfigurationException.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/MissingConfigurationException.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/MissingConfigurationException.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/MissingConfigurationException.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/PostgrestRequestException.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/PostgrestRequestException.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/PostgrestRequestException.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/exceptions/PostgrestRequestException.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/CompositeFilter.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/CompositeFilter.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/CompositeFilter.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/CompositeFilter.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/OrderFilter.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/OrderFilter.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/OrderFilter.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/OrderFilter.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/QueryFilter.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/QueryFilter.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/QueryFilter.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/QueryFilter.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/SelectFilter.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/SelectFilter.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/SelectFilter.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/model/impl/SelectFilter.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestQueryProcessorService.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestQueryProcessorService.java similarity index 100% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestQueryProcessorService.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestQueryProcessorService.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java similarity index 83% rename from src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java rename to querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java index 2e67b8a..89f4356 100644 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java +++ b/querydsl-postgrest/src/main/java/fr/ouestfrance/querydsl/postgrest/utils/QueryStringUtils.java @@ -2,10 +2,11 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.springframework.util.MultiValueMap; + import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Class that allow to handle querystring @@ -18,7 +19,7 @@ public final class QueryStringUtils { * @param multimap multimap to transform * @return query string representation */ - public static String toQueryString(MultiValueMap multimap){ + public static String toQueryString(Map> multimap){ List queryList = new ArrayList<>(); multimap.forEach((key,values)-> values.forEach(value-> queryList.add(key+"="+value))); return String.join("&", queryList); diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java similarity index 63% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java index 20c2239..8ac5501 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/AbstractRepositoryMockTest.java @@ -3,13 +3,15 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.util.MultiValueMap; + +import java.util.List; +import java.util.Map; @ExtendWith(MockitoExtension.class) abstract class AbstractRepositoryMockTest { @SuppressWarnings("unchecked") - ArgumentCaptor> multiMapCaptor() { - return ArgumentCaptor.forClass(MultiValueMap.class); + ArgumentCaptor>> multiMapCaptor() { + return ArgumentCaptor.forClass(Map.class); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java similarity index 90% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java index 7c41cc4..5bc71c0 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestMissingConfigurationTest.java @@ -8,7 +8,7 @@ class PostgrestMissingConfigurationTest { static class MyRepository extends PostgrestRepository { - public MyRepository(PostgrestWebClient client) { + public MyRepository(PostgrestClient client) { super(client); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java similarity index 71% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java index 3a39afe..a7f6683 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryDeleteMockTest.java @@ -8,9 +8,9 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.springframework.util.MultiValueMap; import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -34,16 +34,16 @@ void beforeEach() { @Test void shouldDelete() { - ArgumentCaptor> queriesCaptor = multiMapCaptor(); - ArgumentCaptor> headerCaptor = multiMapCaptor(); + ArgumentCaptor>> queriesCaptor = multiMapCaptor(); + ArgumentCaptor>> headerCaptor = multiMapCaptor(); Post deletedPost = new Post(); when(postgrestClient.delete(anyString(), queriesCaptor.capture(), headerCaptor.capture(), eq(Post.class))).thenReturn(List.of(deletedPost)); List delete = repository.delete(new PostDeleteRequest(List.of("1", "2"))); assertNotNull(delete); - MultiValueMap queries = queriesCaptor.getValue(); - assertEquals("in.(1,2)", queries.getFirst("id")); - MultiValueMap headers = headerCaptor.getValue(); - assertEquals("return=representation", headers.getFirst("Prefer")); + Map> queries = queriesCaptor.getValue(); + assertEquals("in.(1,2)", queries.get("id").stream().findFirst().orElseThrow()); + Map> headers = headerCaptor.getValue(); + assertEquals("return=representation", headers.get("Prefer").stream().findFirst().orElseThrow()); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java similarity index 69% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java index 094c7ea..fa8e36b 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryGetMockTest.java @@ -1,6 +1,7 @@ package fr.ouestfrance.querydsl.postgrest; import fr.ouestfrance.querydsl.postgrest.app.*; +import fr.ouestfrance.querydsl.postgrest.criterias.Criteria; import fr.ouestfrance.querydsl.postgrest.model.Page; import fr.ouestfrance.querydsl.postgrest.model.PageImpl; import fr.ouestfrance.querydsl.postgrest.model.Pageable; @@ -12,13 +13,12 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.util.MultiValueMap; -import org.springframework.util.MultiValueMapAdapter; import java.time.LocalDate; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -29,7 +29,7 @@ class PostgrestRepositoryGetMockTest extends AbstractRepositoryMockTest { @Mock - private PostgrestWebClient webClient; + private PostgrestClient webClient; private PostgrestRepository repository; @@ -37,6 +37,7 @@ class PostgrestRepositoryGetMockTest extends AbstractRepositoryMockTest { void beforeEach() { repository = new PostRepository(webClient); } + @Test void shouldSearchAllPosts() { when(webClient.search(anyString(), any(), any(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); @@ -47,10 +48,6 @@ void shouldSearchAllPosts() { assertFalse(search.hasNext()); } - private ResponseEntity> ok(List data) { - MultiValueMap headers = new MultiValueMapAdapter<>(Map.of("Content-Range", List.of("0-" + data.size() + "/" + data.size()))); - return new ResponseEntity<>(data, headers, HttpStatus.OK); - } @Test void shouldSearchWithPaginate() { @@ -61,28 +58,28 @@ void shouldSearchWithPaginate() { request.setCodes(List.of("a", "b", "c")); request.setExcludes(List.of("z")); request.setValidDate(LocalDate.of(2023, 11, 10)); - ArgumentCaptor> queryArgs = multiMapCaptor(); - ArgumentCaptor> headerArgs = multiMapCaptor(); + ArgumentCaptor>> queryArgs = multiMapCaptor(); + ArgumentCaptor>> headerArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), headerArgs.capture(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); Page search = repository.search(request, Pageable.ofSize(10, Sort.by(Sort.Order.asc("id"), Sort.Order.desc("title").nullsFirst(), Sort.Order.asc("author").nullsLast()))); assertNotNull(search); assertEquals(2, search.size()); // Assert query captors - MultiValueMap queries = queryArgs.getValue(); + Map> queries = queryArgs.getValue(); log.info("queries {}", queries); - assertEquals("eq.1", queries.getFirst("userId")); - assertEquals("neq.1", queries.getFirst("id")); - assertEquals("lte.2023-11-10", queries.getFirst("startDate")); - assertEquals("(endDate.gte.2023-11-10,endDate.is.null)", queries.getFirst("or")); - assertEquals("like.Test*", queries.getFirst("title")); - assertEquals("id,title.desc.nullsfirst,author.nullslast", queries.getFirst("order")); - assertEquals("*,authors(*)", queries.getFirst("select")); + assertEquals("eq.1", queries.get("userId").stream().findFirst().orElseThrow()); + assertEquals("neq.1", queries.get("id").stream().findFirst().orElseThrow()); + assertEquals("lte.2023-11-10", queries.get("startDate").stream().findFirst().orElseThrow()); + assertEquals("(endDate.gte.2023-11-10,endDate.is.null)", queries.get("or").stream().findFirst().orElseThrow()); + assertEquals("like.Test*", queries.get("title").stream().findFirst().orElseThrow()); + assertEquals("id,title.desc.nullsfirst,author.nullslast", queries.get("order").stream().findFirst().orElseThrow()); + assertEquals("*,authors(*)", queries.get("select").stream().findFirst().orElseThrow()); assertEquals(2, queries.get("status").size()); // Assert headers captors - MultiValueMap value = headerArgs.getValue(); - assertEquals("0-9", value.getFirst("Range")); - assertEquals("items", value.getFirst("Range-Unit")); + Map> value = headerArgs.getValue(); + assertEquals("0-9", value.get("Range").stream().findFirst().orElseThrow()); + assertEquals("items", value.get("Range-Unit").stream().findFirst().orElseThrow()); // Assert pagination assertNotNull(search.getPageable()); assertEquals(10, search.getPageable().getPageSize()); @@ -94,6 +91,34 @@ void shouldSearchWithPaginate() { assertEquals(0, search.getPageable().previous().getPageNumber()); } + @Test + void shouldFindById() { + ArgumentCaptor>> queryArgs = multiMapCaptor(); + when(webClient.search(anyString(), queryArgs.capture(), any(), eq(Post.class))).thenReturn(Page.of(new Post())); + Page search = repository.search(Criteria.byId("1"), Pageable.ofSize(6)); + // Assert query captors + Map> queries = queryArgs.getValue(); + assertEquals("eq.1", queries.get("id").stream().findFirst().orElseThrow()); + log.info("queries {}", queries); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + + @Test + void shouldFindByIds() { + ArgumentCaptor>> queryArgs = multiMapCaptor(); + when(webClient.search(anyString(), queryArgs.capture(), any(), eq(Post.class))).thenReturn(Page.of(new Post())); + Page search = repository.search(Criteria.byIds("1", "2", "3"), Pageable.ofSize(6)); + // Assert query captors + Map> queries = queryArgs.getValue(); + assertEquals("in.(1,2,3)", queries.get("id").stream().findFirst().orElseThrow()); + log.info("queries {}", queries); + assertNotNull(search); + assertFalse(search.getData().isEmpty()); + search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x)); + } + @Test void shouldSearchWithNextPaginate() { PostRequest request = new PostRequest(); @@ -103,9 +128,7 @@ void shouldSearchWithNextPaginate() { request.setCodes(List.of("a", "b", "c")); request.setExcludes(List.of("z")); request.setValidDate(LocalDate.of(2023, 11, 10)); - ArgumentCaptor> queryArgs = multiMapCaptor(); - ArgumentCaptor> headerArgs = multiMapCaptor(); - when(webClient.search(anyString(), queryArgs.capture(), headerArgs.capture(), eq(Post.class))).thenReturn(new PageImpl<>(List.of(new Post()), null, 2, 2)); + when(webClient.search(anyString(), any(), any(), eq(Post.class))).thenReturn(new PageImpl<>(List.of(new Post()), null, 2, 2)); Page search = repository.search(request, Pageable.ofSize(1, Sort.by(Sort.Order.asc("id")))); assertNotNull(search); @@ -134,8 +157,8 @@ void shouldSearchWithPreviousPaginate() { request.setCodes(List.of("a", "b", "c")); request.setExcludes(List.of("z")); request.setValidDate(LocalDate.of(2023, 11, 10)); - ArgumentCaptor> queryArgs = multiMapCaptor(); - ArgumentCaptor> headerArgs = multiMapCaptor(); + ArgumentCaptor>> queryArgs = multiMapCaptor(); + ArgumentCaptor>> headerArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), headerArgs.capture(), eq(Post.class))).thenReturn(new PageImpl<>(List.of(new Post()), null, 2, 2)); Page search = repository.search(request, Pageable.ofSize(1, 1, Sort.by(Sort.Order.asc("id")))); @@ -157,21 +180,21 @@ void shouldSearchWithPreviousPaginate() { @Test void shouldSearchWithoutOrder() { PostRequest request = new PostRequest(); - ArgumentCaptor> queryArgs = multiMapCaptor(); - ArgumentCaptor> headerArgs = multiMapCaptor(); + ArgumentCaptor>> queryArgs = multiMapCaptor(); + ArgumentCaptor>> headerArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), headerArgs.capture(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); Page search = repository.search(request, Pageable.ofSize(10)); assertNotNull(search); assertEquals(2, search.size()); // Assert query captors - MultiValueMap queries = queryArgs.getValue(); + Map> queries = queryArgs.getValue(); log.info("queries {}", queries); - assertNull(queries.getFirst("order")); + assertNull(queries.get("order")); // Assert headers captors - MultiValueMap value = headerArgs.getValue(); - assertEquals("0-9", value.getFirst("Range")); - assertEquals("items", value.getFirst("Range-Unit")); + Map> value = headerArgs.getValue(); + assertEquals("0-9", value.get("Range").stream().findFirst().orElseThrow()); + assertEquals("items", value.get("Range-Unit").stream().findFirst().orElseThrow()); } @Test @@ -215,19 +238,19 @@ void shouldRaiseExceptionOnEmptyGetOne() { void shouldSearchWithJoin() { PostRequestWithSize request = new PostRequestWithSize(); request.setSize("25"); - ArgumentCaptor> queryArgs = multiMapCaptor(); + ArgumentCaptor>> queryArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), any(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); Page search = repository.search(request, Pageable.unPaged()); assertNotNull(search); assertEquals(2, search.size()); // Assert query captors - MultiValueMap queries = queryArgs.getValue(); + Map> queries = queryArgs.getValue(); String queryString = QueryStringUtils.toQueryString(queries); log.info("queries {}", queries); System.out.println(queries); assertEquals(1, queries.get("or").size()); // Means that you have to make (format.minSize.gte.25 AND format.maxSize.lte.25) OR size.eq.25 - assertEquals("(filterFormats.and(minSize.gte.25,or(maxSize.lte.25,maxSize.is.null)),size.eq.25)", queries.getFirst("or")); + assertEquals("(filterFormats.and(minSize.gte.25,or(maxSize.lte.25,maxSize.is.null)),size.eq.25)", queries.get("or").stream().findFirst().orElseThrow()); } @Test @@ -235,19 +258,19 @@ void shouldSearchWithOrOnMultiple() { PostRequestWithAuthorOrSubject request = new PostRequestWithAuthorOrSubject(); request.setAuthor("IA"); request.setSubject("IA"); - ArgumentCaptor> queryArgs = multiMapCaptor(); + ArgumentCaptor>> queryArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), any(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); Page search = repository.search(request, Pageable.ofSize(10)); assertNotNull(search); assertEquals(2, search.size()); // Assert query captors - MultiValueMap queries = queryArgs.getValue(); + Map> queries = queryArgs.getValue(); String queryString = QueryStringUtils.toQueryString(queries); System.out.println("queries : " + queryString); log.info("queries {}", queries); - assertEquals("(subject.eq.IA,author.name.eq.IA)", queries.getFirst("or")); - String[] selects = Objects.requireNonNull(queries.getFirst("select")).toString().split(","); + assertEquals("(subject.eq.IA,author.name.eq.IA)", queries.get("or").stream().findFirst().orElseThrow()); + String[] selects = queries.get("select").stream().findFirst().orElseThrow().split(","); assertEquals(3, selects.length); assertTrue(Arrays.asList(selects).contains("author:authors!inner(name)")); } @@ -257,17 +280,17 @@ void testPublicationRequest() { PublicationRequest request = new PublicationRequest(); request.setCode("25"); request.setPortee("['DEPARTEMENT']"); - request.setDateValide(LocalDate.of(2023,12,4)); - ArgumentCaptor> queryArgs = multiMapCaptor(); + request.setDateValide(LocalDate.of(2023, 12, 4)); + ArgumentCaptor>> queryArgs = multiMapCaptor(); when(webClient.search(anyString(), queryArgs.capture(), any(), eq(Post.class))).thenReturn(Page.of(new Post(), new Post())); Page search = repository.search(request, Pageable.ofSize(10)); assertNotNull(search); assertEquals(2, search.size()); // Assert query captors - MultiValueMap queries = queryArgs.getValue(); + Map> queries = queryArgs.getValue(); System.out.println(queries); - assertEquals("(dateFinValidite.gte.2023-12-04,dateFinValidite.is.null)", queries.getFirst("filtrePublication.or")); + assertEquals("(dateFinValidite.gte.2023-12-04,dateFinValidite.is.null)", queries.get("filtrePublication.or").stream().findFirst().orElseThrow()); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java similarity index 60% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java index 079bd64..e05d142 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryPatchMockTest.java @@ -8,20 +8,20 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.springframework.util.MultiValueMap; import java.util.List; +import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @Slf4j -class PostgrestRepositoryPatchMockTest extends AbstractRepositoryMockTest{ +class PostgrestRepositoryPatchMockTest extends AbstractRepositoryMockTest { @Mock - private PostgrestWebClient webClient; + private PostgrestClient webClient; private PostgrestRepository repository; @@ -29,19 +29,20 @@ class PostgrestRepositoryPatchMockTest extends AbstractRepositoryMockTest{ void beforeEach() { repository = new PostRepository(webClient); } + @Test void shouldDelete() { - ArgumentCaptor> queriesCaptor = multiMapCaptor(); - ArgumentCaptor> headerCaptor = multiMapCaptor(); + ArgumentCaptor>> queriesCaptor = multiMapCaptor(); + ArgumentCaptor>> headerCaptor = multiMapCaptor(); Post post = new Post(); post.setUserId(26); when(webClient.patch(anyString(), queriesCaptor.capture(), eq(post), headerCaptor.capture(), eq(Post.class))).thenReturn(List.of(post)); List patched = repository.patch(new PostDeleteRequest(List.of("1", "2")), post); assertNotNull(patched); assertEquals(1, patched.size()); - MultiValueMap queries = queriesCaptor.getValue(); - assertEquals("in.(1,2)", queries.getFirst("id")); - MultiValueMap headers = headerCaptor.getValue(); - assertEquals("return=representation", headers.getFirst("Prefer")); + Map> queries = queriesCaptor.getValue(); + assertEquals("in.(1,2)", queries.get("id").stream().findFirst().orElseThrow()); + Map> headers = headerCaptor.getValue(); + assertTrue(headers.get("Prefer").contains("return=representation")); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java similarity index 75% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java index 8df29f2..603a36a 100644 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/PostgrestRepositoryUpsertMockTest.java @@ -3,13 +3,14 @@ import fr.ouestfrance.querydsl.postgrest.app.Post; import fr.ouestfrance.querydsl.postgrest.app.PostRepository; import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.springframework.util.MultiValueMap; import java.util.List; +import java.util.Map; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -22,7 +23,7 @@ class PostgrestRepositoryUpsertMockTest extends AbstractRepositoryMockTest { @Mock - private PostgrestWebClient webClient; + private PostgrestClient webClient; private PostgrestRepository repository; @@ -35,7 +36,7 @@ void beforeEach() { void shouldUpsert() { @SuppressWarnings("unchecked") ArgumentCaptor> postCaptor = ArgumentCaptor.forClass(List.class); - ArgumentCaptor> headerCaptor = multiMapCaptor(); + ArgumentCaptor>> headerCaptor = multiMapCaptor(); String generateId = UUID.randomUUID().toString(); Post save = new Post(); @@ -53,11 +54,11 @@ void shouldUpsert() { assertNotNull(saved); assertEquals(1, postCaptor.getValue().size()); - assertEquals(generateId, saved.getId()); - assertEquals(save.getBody(), saved.getBody()); - assertEquals(save.getTitle(), saved.getTitle()); - MultiValueMap headers = headerCaptor.getValue(); + Assertions.assertEquals(generateId, saved.getId()); + Assertions.assertEquals(save.getBody(), saved.getBody()); + Assertions.assertEquals(save.getTitle(), saved.getTitle()); + Map> headers = headerCaptor.getValue(); assertEquals(2, headers.get("Prefer").size()); - assertEquals("return=representation", headers.getFirst("Prefer")); + assertEquals("return=representation", headers.get("Prefer").stream().findFirst().orElseThrow()); } } diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/Post.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostDeleteRequest.java diff --git a/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java new file mode 100644 index 0000000..1d6dd30 --- /dev/null +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRepository.java @@ -0,0 +1,22 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.postgrest.PostgrestClient; +import fr.ouestfrance.querydsl.postgrest.PostgrestRepository; +import fr.ouestfrance.querydsl.postgrest.annotations.Header; +import fr.ouestfrance.querydsl.postgrest.annotations.PostgrestConfiguration; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import fr.ouestfrance.querydsl.postgrest.model.Prefer; + +import static fr.ouestfrance.querydsl.postgrest.annotations.Header.Method.UPSERT; + +@PostgrestConfiguration(resource = "posts") +@Select("authors(*)") +@Header(key = Prefer.HEADER, value = Prefer.Return.REPRESENTATION) +@Header(key = Prefer.HEADER, value = Prefer.Resolution.MERGE_DUPLICATES, methods = UPSERT) +public class PostRepository extends PostgrestRepository { + + public PostRepository(PostgrestClient client) { + super(client); + } + +} diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithAuthorOrSubject.java diff --git a/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java new file mode 100644 index 0000000..6dbd62c --- /dev/null +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PostRequestWithSize.java @@ -0,0 +1,23 @@ +package fr.ouestfrance.querydsl.postgrest.app; + +import fr.ouestfrance.querydsl.FilterField; +import fr.ouestfrance.querydsl.FilterFields; +import fr.ouestfrance.querydsl.FilterOperation; +import fr.ouestfrance.querydsl.postgrest.annotations.Select; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Select(alias = "filterFormats", value = "formats!inner(minSize, maxSize)") +public class PostRequestWithSize { + + // size = $size OR (minSize < size AND maxSize > size) + @FilterField(key = "size", groupName = "sizeOrGroup") + @FilterFields(groupName = "sizeOrGroup", value = { + @FilterField(key = "filterFormats.minSize", operation = FilterOperation.GTE.class), + @FilterField(key = "filterFormats.maxSize", operation = FilterOperation.LTE.class, orNull = true) + }) + private String size; +} + diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/app/PublicationRequest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/CaseInsensitiveLikeMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainedMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/ContainsMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/InMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/LikeMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapperTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapperTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapperTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/NotInMapperTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/PostgrestFilterOperationTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/PostgrestFilterOperationTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/PostgrestFilterOperationTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/mappers/PostgrestFilterOperationTest.java diff --git a/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java new file mode 100644 index 0000000..82f516c --- /dev/null +++ b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java @@ -0,0 +1,40 @@ +package fr.ouestfrance.querydsl.postgrest.model; + +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +class PageTest { + + @Test + void shouldMap() { + Page map = Page.of("1", "2", "3").map(Integer::parseInt); + assertNotNull(map); + assertTrue(map.stream().anyMatch(Objects::nonNull)); + } + + @Test + void withRange() { + List items = List.of(1, 2, 3); + PageImpl page = new PageImpl<>(items, null, items.size(), 1); + page.withRange(Range.of("0-3/3")); + assertNotNull(page); + assertEquals(3, page.getTotalElements()); + assertEquals(1, page.getTotalPages()); + } + + @Test + void shouldEmptyPage() { + Page page = Page.empty(); + assertNotNull(page); + assertEquals(0, page.getTotalElements()); + assertEquals(0, page.getTotalPages()); + assertTrue(page.getData().isEmpty()); + } +} diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/model/RangeTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/RangeTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/model/RangeTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/RangeTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/model/SortTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/SortTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/model/SortTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/model/SortTest.java diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestTranslatorServiceTest.java b/querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestTranslatorServiceTest.java similarity index 100% rename from src/test/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestTranslatorServiceTest.java rename to querydsl-postgrest/src/test/java/fr/ouestfrance/querydsl/postgrest/services/ext/PostgrestTranslatorServiceTest.java diff --git a/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java b/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java deleted file mode 100644 index 16bdf73..0000000 --- a/src/main/java/fr/ouestfrance/querydsl/postgrest/criterias/Criteria.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.ouestfrance.querydsl.postgrest.criterias; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import java.util.List; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class Criteria { - - public static Object byId(Comparable id) { - return new ById(id); - } - - public static Object byIds(Comparable... id) { - return new ByIds(List.of(id)); - } -} diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/SimpleRepository.java b/src/test/java/fr/ouestfrance/querydsl/postgrest/app/SimpleRepository.java deleted file mode 100644 index ab009cd..0000000 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/app/SimpleRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.ouestfrance.querydsl.postgrest.app; - -import fr.ouestfrance.querydsl.postgrest.PostgrestWebClient; -import fr.ouestfrance.querydsl.postgrest.PostgrestRepository; -import fr.ouestfrance.querydsl.postgrest.annotations.PostgrestConfiguration; - -@PostgrestConfiguration(resource = "posts") -public class SimpleRepository extends PostgrestRepository { - public SimpleRepository(PostgrestWebClient client) { - super(client); - } -} diff --git a/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java b/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java deleted file mode 100644 index 14544fa..0000000 --- a/src/test/java/fr/ouestfrance/querydsl/postgrest/model/PageTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.ouestfrance.querydsl.postgrest.model; - -import org.junit.jupiter.api.Test; - -import java.util.Objects; - -import static org.junit.jupiter.api.Assertions.*; - - -class PageTest { - - @Test - void shouldMap() { - Page map = Page.of("1", "2", "3").map(Integer::parseInt); - assertNotNull(map); - assertTrue(map.stream().anyMatch(Objects::nonNull)); - } - -}