Skip to content

Commit

Permalink
10 - add count (#17)
Browse files Browse the repository at this point in the history
* feat(count): support count feature
  • Loading branch information
arnaud-thorel-of authored Feb 7, 2024
1 parent 6d388ae commit 76432fb
Show file tree
Hide file tree
Showing 13 changed files with 244 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package fr.ouestfrance.querydsl.postgrest;

import fr.ouestfrance.querydsl.postgrest.model.CountItem;
import fr.ouestfrance.querydsl.postgrest.model.Page;
import fr.ouestfrance.querydsl.postgrest.model.PageImpl;
import fr.ouestfrance.querydsl.postgrest.model.Range;
import fr.ouestfrance.querydsl.postgrest.model.RangeResponse;
import lombok.AccessLevel;
Expand Down Expand Up @@ -85,6 +88,12 @@ public <T> List<T> delete(String resource, Map<String, List<String>> params, Map
.queryParams(queryParams).build().toString(), new HashMap<>()), HttpMethod.DELETE, new HttpEntity<>(null, toHeaders(headers)), listRef(clazz)).getBody();
}

@Override
public List<CountItem> count(String resource, Map<String, List<String>> map) {
return restTemplate.exchange(restTemplate.getUriTemplateHandler().expand(UriComponentsBuilder.fromPath(resource)
.queryParams(toMultiMap(map)).build().toString(), new HashMap<>()), HttpMethod.GET, new HttpEntity<>(null, new HttpHeaders()), listRef(CountItem.class)).getBody();
}

private static <T> ParameterizedTypeReference<List<T>> listRef(Class<T> clazz) {
return ParameterizedTypeReference.forType(TypeUtils.parameterize(List.class, clazz));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockserver.client.MockServerClient;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.junit.jupiter.MockServerSettings;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
Expand All @@ -27,7 +28,7 @@
import static org.junit.jupiter.api.Assertions.*;

@MockServerSettings(ports = 8007)
class PostgrestRepositoryTest {
class PostgrestRestTemplateRepositoryTest {

private PostgrestRepository<Post> repository;

Expand All @@ -52,6 +53,14 @@ void shouldSearchPosts(MockServerClient client) {
search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x));
}

@Test
void shouldCountPosts(ClientAndServer client) {
client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "count()"))
.respond(jsonFileResponse("count_response.json"));
long count = repository.count(new PostRequest());
assertEquals(300, count);
}

@Test
void shouldSearchPostsWithoutContentRange(MockServerClient client) {
client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "*,authors(*)"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"count": 300
}
]
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.ouestfrance.querydsl.postgrest;

import fr.ouestfrance.querydsl.postgrest.model.CountItem;
import fr.ouestfrance.querydsl.postgrest.model.Page;
import fr.ouestfrance.querydsl.postgrest.model.PageImpl;
import fr.ouestfrance.querydsl.postgrest.model.Range;
Expand Down Expand Up @@ -75,6 +76,19 @@ public <T> RangeResponse<T> search(String resource, Map<String, List<String>> pa
}).orElse(new RangeResponse<>(List.of(), null));
}

@Override
public List<CountItem> count(String resource, Map<String, List<String>> params) {
ResponseEntity<List<CountItem>> response = webClient.get().uri(uriBuilder -> {
uriBuilder.path(resource);
uriBuilder.queryParams(toMultiMap(params));
return uriBuilder.build();
})
.retrieve()
.toEntity(listRef(CountItem.class))
.block();
return Optional.ofNullable(response).map(HttpEntity::getBody).orElse(List.of());
}

private static void safeAdd(Map<String, List<String>> headers, HttpHeaders httpHeaders) {
Optional.ofNullable(headers)
.map(PostgrestWebClient::toMultiMap).ifPresent(httpHeaders::addAll);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
import fr.ouestfrance.querydsl.postgrest.model.Pageable;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.junit.jupiter.MockServerExtension;
import org.mockserver.junit.jupiter.MockServerSettings;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
Expand All @@ -25,7 +23,7 @@
import static org.junit.jupiter.api.Assertions.*;

@MockServerSettings(ports = 8007)
class PostrgrestRepositoryTest {
class PostrgrestWebClientRepositoryTest {

private final PostgrestRepository<Post> repository = new PostRepository(PostgrestWebClient.of(WebClient.builder()
.baseUrl("http://localhost:8007/")
Expand All @@ -46,6 +44,14 @@ void shouldSearchPosts(ClientAndServer client) {
search.getData().stream().map(Object::getClass).forEach(x -> assertEquals(Post.class, x));
}

@Test
void shouldCountPosts(ClientAndServer client) {
client.when(HttpRequest.request().withPath("/posts").withQueryStringParameter("select", "count()"))
.respond(jsonFileResponse("count_response.json"));
long count = repository.count(new PostRequest());
assertEquals(300, count);
}

@Test
void shouldFindById(ClientAndServer client) {
client.when(HttpRequest.request().withPath("/posts")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[
{
"count": 300
}
]
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.ouestfrance.querydsl.postgrest;

import fr.ouestfrance.querydsl.postgrest.model.CountItem;
import fr.ouestfrance.querydsl.postgrest.model.RangeResponse;

import java.util.List;
Expand Down Expand Up @@ -60,4 +61,12 @@ <T> RangeResponse<T> search(String resource, Map<String, List<String>> params,
*/
<T> List<T> delete(String resource, Map<String, List<String>> params, Map<String, List<String>> headers, Class<T> clazz);

/**
* Count data
*
* @param resource resource name
* @param map query params
* @return list of count items
*/
List<CountItem> count(String resource, Map<String, List<String>> map);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,17 @@
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.Filter;
import fr.ouestfrance.querydsl.postgrest.model.Page;
import fr.ouestfrance.querydsl.postgrest.model.PageImpl;
import fr.ouestfrance.querydsl.postgrest.model.Pageable;
import fr.ouestfrance.querydsl.postgrest.model.RangeResponse;
import fr.ouestfrance.querydsl.postgrest.model.*;
import fr.ouestfrance.querydsl.postgrest.model.exceptions.MissingConfigurationException;
import fr.ouestfrance.querydsl.postgrest.model.exceptions.PostgrestRequestException;
import fr.ouestfrance.querydsl.postgrest.model.impl.CountFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.OrderFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.SelectFilter;
import fr.ouestfrance.querydsl.postgrest.services.ext.PostgrestQueryProcessorService;
import fr.ouestfrance.querydsl.service.ext.QueryDslProcessorService;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;

/**
* Postgrest repository implementation
Expand Down Expand Up @@ -74,7 +65,7 @@ public Page<T> search(Object criteria, Pageable pageable) {
if (pageable.getPageSize() > 0) {
headers.put("Range-Unit", List.of("items"));
headers.put("Range", List.of(pageable.toRange()));
headers.computeIfAbsent("Prefer", x -> new ArrayList<>())
headers.computeIfAbsent("Prefers", x -> new ArrayList<>())
.add("count=" + annotation.countStrategy().name().toLowerCase());
}
// Add sort if present
Expand All @@ -93,6 +84,17 @@ public Page<T> search(Object criteria, Pageable pageable) {
return new PageImpl<>(response.data(), pageable, response.getTotalElements(), (int) Math.ceil((double) response.getTotalElements() / pageSize));
}


@Override
public long count(Object criteria) {
List<Filter> queryParams = processorService.process(criteria);
queryParams.add(CountFilter.of());
List<CountItem> response = client.count(annotation.resource(), toMap(queryParams));
// Retrieve result headers
return response.stream().findFirst().map(x -> x.get("count")).map(Long::valueOf).orElse(0L);
}


@Override
public List<T> upsert(List<Object> values) {
return client.post(annotation.resource(), values, headerMap(Header.Method.UPSERT), clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ default Page<T> search(Object criteria) {
return search(criteria, Pageable.unPaged());
}


/**
* Count all items
*
* @return count result
*/
default long count() {
return count(null);
}

/**
* Count from criteria object
*
* @param criteria search criteria
* @return count result
*/
long count(Object criteria);

/**
* Search from criteria object with pagination
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import fr.ouestfrance.querydsl.postgrest.model.Filter;
import fr.ouestfrance.querydsl.postgrest.model.Sort;
import fr.ouestfrance.querydsl.postgrest.model.impl.CompositeFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.OrderFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.QueryFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.SelectFilter;
import fr.ouestfrance.querydsl.postgrest.model.impl.*;

import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -63,6 +60,16 @@ public void visit(SelectFilter filter) {
.collect(Collectors.joining(",")));
}


/**
* Transform a Select filter to Query
*
* @param filter select filter
*/
public void visit(CountFilter filter) {
builder.append(filter.getMethod());
}

/**
* Transform a Composite filter to Query
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.ouestfrance.querydsl.postgrest.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.HashMap;

@Getter
@Setter
@NoArgsConstructor
public class CountItem extends HashMap<String, String> {

public static CountItem of(int count) {
CountItem countItem = new CountItem();
countItem.put("count", String.valueOf(count));
return countItem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fr.ouestfrance.querydsl.postgrest.model.impl;

import fr.ouestfrance.querydsl.postgrest.builders.FilterVisitor;
import fr.ouestfrance.querydsl.postgrest.builders.QueryFilterVisitor;
import fr.ouestfrance.querydsl.postgrest.model.Filter;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
* Select filter allow to describe a selection
*/
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class CountFilter implements Filter, FilterVisitor {

/**
* Default query param key for selection
*/
private static final String KEY_PARAMETER = "select";

/**
* Create select filter from embedded resources
*
* @return select filter
*/
public static Filter of() {
return new CountFilter();
}

@Override
public void accept(QueryFilterVisitor visitor) {
visitor.visit(this);
}

@Override
public String getKey() {
return KEY_PARAMETER;
}

public String getMethod() {
return "count()";
}
}
Loading

0 comments on commit 76432fb

Please sign in to comment.