Skip to content

Commit

Permalink
Merge branch 'main' into v1.2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-thorel-of authored Feb 7, 2024
2 parents cfca7be + 883f7bf commit f80f22c
Show file tree
Hide file tree
Showing 32 changed files with 963 additions and 144 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ name: Build

on:
push:
branches: [ main, [0-9]+.[0-9]+.* ]
branches:
- main
- v*
pull_request:
branches: [ main, [0-9]+.[0-9]+.* ]

branches:
- main
- v*
jobs:
build:
runs-on: ubuntu-latest
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy Package
name: Release

on:
release:
Expand All @@ -11,6 +11,11 @@ jobs:
contents: write
packages: write
steps:
- name: Display versions
run: |
echo "Release Target_Commitish ${{ github.event.release.target_commitish }}"
echo "Release Tag_Name ${{ github.event.release.tag_name }}"
echo "Release Name ${{ github.event.release.name }}"
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.target_commitish }}
Expand All @@ -31,6 +36,6 @@ jobs:
run: |
git config --global user.name 'github-actions'
git config --global user.email 'actions[bot]@github.com'
mvn -ntp -B release:prepare release:perform -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }} -Dtag=temp_$${{ github.event.inputs.releaseVersion }}
mvn -ntp -B release:prepare release:perform -DreleaseVersion=${{ github.event.release.tag_name }} -Dtag=tmp_${{ github.event.release.tag_name }}
- name: Post-Release
run: git push --delete origin temp_$${{ github.event.inputs.releaseVersion }}
run: git push --delete origin tmp_${{ github.event.release.tag_name }}
16 changes: 0 additions & 16 deletions .github/workflows/renovate.yml

This file was deleted.

52 changes: 46 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and provides class and annotation to improve your developer experience using Pos
Add the following dependency to your Maven project:

```xml

<dependency>
<groupId>fr.ouestfrance.querydsl</groupId>
<artifactId>querydsl-postgrest</artifactId>
Expand Down Expand Up @@ -52,8 +53,10 @@ cookies, ...) you need to deploy.

#### WebClient configuration example

Add the dependency :
Add the dependency :

```xml

<dependency>
<groupId>fr.ouestfrance.querydsl</groupId>
<artifactId>querydsl-postgrest-webclient-adapter</artifactId>
Expand Down Expand Up @@ -87,8 +90,10 @@ public class PostgrestConfiguration {

#### RestTemplate configuration example

Add the dependency :
Add the dependency :

```xml

<dependency>
<groupId>fr.ouestfrance.querydsl</groupId>
<artifactId>querydsl-postgrest-resttemplate-adapter</artifactId>
Expand Down Expand Up @@ -198,10 +203,6 @@ You can then create your functions :
- findUsersByName : Will return list of users which name contains part of search content

```java
import fr.ouestfrance.querydsl.FilterField;
import fr.ouestfrance.querydsl.FilterOperation;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -349,6 +350,45 @@ extends FilterOperation with
| CS | Contains for JSON/Range datatype |
| CD | Contained for JSON/Range datatype |

#### Bulk Operations

PostgREST allow to execute operations over a wide range items.
QueryDSL-Postgrest allow to handle pagination fixed by user or fixed by the postgREST max page

```java
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class UserService {

private final UserRepository userRepository;


public void invalidatePassword() {
UserSearch criteria = new UserSearch();
// Will invalidate all passwords with chunk of 1000 users
userRepository.patch(criteria, new UserPatchPassword(false), BulkOptions.builder()
.countsOnly(true)
.pageSize(1000)
.build());
// Generate n calls of
// PATCH /users {"password_validation": false } -H Range 0-999
// PATCH /users {"password_validation": false } -H Range 1000-1999
// PATCH /users {"password_validation": false } -H Range 2000-2999
// etc since the users are all updated
}
}
```

| Option | Default Value | Description |
|------------|---------------|---------------------------------------------------------------------------|
| countsOnly | false | Place return=headers-only if true, otherwise keep default return |
| pageSize | -1 | Specify the size of the chunk, otherwise let postgrest activate its limit |

> Bulk Operations are allowed on `Patch`, `Delete` and `Upsert`
## Need Help ?

If you need help with the library please start a new thread QA / Issue on github
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.ouestfrance.querydsl.postgrest;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springframework.core.ParameterizedTypeReference;

import java.util.List;

/**
* Type Utilities
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ParametrizedTypeUtils {

/**
* Create parametrized type of List of T
*
* @param clazz class of T
* @param <T> type of parametrized list
* @return parametrized type
*/
public static <T> ParameterizedTypeReference<List<T>> listRef(Class<T> clazz) {
return ParameterizedTypeReference.forType(TypeUtils.parameterize(List.class, clazz));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package fr.ouestfrance.querydsl.postgrest;

import fr.ouestfrance.querydsl.postgrest.model.BulkResponse;
import fr.ouestfrance.querydsl.postgrest.model.CountItem;
import fr.ouestfrance.querydsl.postgrest.model.Range;
import fr.ouestfrance.querydsl.postgrest.model.RangeResponse;
import lombok.AccessLevel;
Expand All @@ -19,7 +21,9 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import static fr.ouestfrance.querydsl.postgrest.ParametrizedTypeUtils.listRef;
import static fr.ouestfrance.querydsl.postgrest.ResponseUtils.toBulkResponse;

/**
* Rest interface for querying postgrest
Expand Down Expand Up @@ -53,47 +57,47 @@ public <T> RangeResponse<T> search(String resource, Map<String, List<String>> pa
return Optional.of(response)
.map(HttpEntity::getBody)
.map(x -> {
Range range = Optional.ofNullable(response.getHeaders().get("Content-Range"))
.map(List::stream)
.map(Stream::findFirst)
.filter(Optional::isPresent)
.map(Optional::get)
.map(Range::of).orElse(null);
Range range = ResponseUtils.getCount(response.getHeaders())
.orElse(null);
return new RangeResponse<>(x, range);
}).orElse(new RangeResponse<>(List.of(), null));
}

@Override
public <T> List<T> post(String resource, List<Object> value, Map<String, List<String>> headers, Class<T> clazz) {
HttpHeaders httpHeaders = toHeaders(headers);
return restTemplate.exchange(resource, HttpMethod.POST, new HttpEntity<>(value, httpHeaders), listRef(clazz)).getBody();
public <T> BulkResponse<T> post(String resource, List<Object> value, Map<String, List<String>> headers, Class<T> clazz) {
ResponseEntity<List<T>> response = restTemplate.exchange(resource, HttpMethod.POST, new HttpEntity<>(value, toHeaders(headers)), listRef(clazz));
return toBulkResponse(response);
}


@Override
public <T> List<T> patch(String resource, Map<String, List<String>> params, Object value, Map<String, List<String>> headers, Class<T> clazz) {
MultiValueMap<String, String> 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();
public <T> BulkResponse<T> patch(String resource, Map<String, List<String>> params, Object value, Map<String, List<String>> headers, Class<T> clazz) {
ResponseEntity<List<T>> response = restTemplate.exchange(restTemplate.getUriTemplateHandler()
.expand(UriComponentsBuilder.fromPath(resource).queryParams(toMultiMap(params)).build().toString(), new HashMap<>()),
HttpMethod.PATCH, new HttpEntity<>(value, toHeaders(headers)), listRef(clazz));
return toBulkResponse(response);
}

@Override
public <T> List<T> delete(String resource, Map<String, List<String>> params, Map<String, List<String>> headers, Class<T> clazz) {
MultiValueMap<String, String> 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();
public <T> BulkResponse<T> delete(String resource, Map<String, List<String>> params, Map<String, List<String>> headers, Class<T> clazz) {
ResponseEntity<List<T>> response = restTemplate.exchange(restTemplate.getUriTemplateHandler().expand(UriComponentsBuilder.fromPath(resource)
.queryParams(toMultiMap(params)).build().toString(), new HashMap<>()), HttpMethod.DELETE, new HttpEntity<>(null, toHeaders(headers)), listRef(clazz));
return toBulkResponse(response);
}

private static <T> ParameterizedTypeReference<List<T>> listRef(Class<T> clazz) {
return ParameterizedTypeReference.forType(TypeUtils.parameterize(List.class, clazz));
@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 MultiValueMap<String, String> toMultiMap(Map<String, List<String>> params) {
return new LinkedMultiValueMap<>(params);
}

private static HttpHeaders toHeaders(Map<String, List<String>> headers) {
return new HttpHeaders(toMultiMap(headers));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package fr.ouestfrance.querydsl.postgrest;

import fr.ouestfrance.querydsl.postgrest.model.BulkResponse;
import fr.ouestfrance.querydsl.postgrest.model.Range;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;

import java.util.List;
import java.util.Optional;

/**
* Utility class that helps to transform response
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ResponseUtils {

/**
* Transform a ResponseEntity of list to bulkResponse
*
* @param response response entity
* @param <T> Type of response
* @return BulkResponse
*/
public static <T> BulkResponse<T> toBulkResponse(ResponseEntity<List<T>> response) {
return Optional.ofNullable(response)
.map(x -> {
Optional<Range> count = getCount(x.getHeaders());
return new BulkResponse<>(x.getBody(), count.map(Range::getCount).orElse(0L), count.map(Range::getTotalElements).orElse(0L));
})
.orElse(new BulkResponse<>(List.of(), 0L, 0L));
}

/**
* Extract Range headers
*
* @param headers headers where Content-Range is
* @return range object
*/
public static Optional<Range> getCount(HttpHeaders headers) {
return Optional.ofNullable(headers.get("Content-Range"))
.flatMap(x -> x.stream().findFirst())
.map(Range::of);
}
}
Loading

0 comments on commit f80f22c

Please sign in to comment.