Skip to content

Commit

Permalink
feat(record): add record support
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-thorel-of committed Dec 7, 2023
1 parent 7515e51 commit 5300eb3
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 154 deletions.
15 changes: 0 additions & 15 deletions src/main/java/fr/ouestfrance/querydsl/model/FieldMetadata.java

This file was deleted.

7 changes: 4 additions & 3 deletions src/main/java/fr/ouestfrance/querydsl/model/SimpleFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import fr.ouestfrance.querydsl.FilterOperation;

import java.lang.reflect.Field;

/**
* FilterFieldInfoModel allow to store object representation of FilterField Annotation
* @param key key of the criteria
* @param operation operator to apply
* @param orNull allow the field to be null
* @param metadata metadata of the field representing type, method accessor and field name
* @param field field of the field representing type, method accessor and field name
*/
public record SimpleFilter(String key, FilterOperation operation, boolean orNull,
FieldMetadata metadata) implements Filter {
public record SimpleFilter(String key, FilterOperation operation, boolean orNull, Field field) implements Filter {
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package fr.ouestfrance.querydsl.service.ext;

import fr.ouestfrance.querydsl.FilterOperation;
import fr.ouestfrance.querydsl.model.SimpleFilter;
import fr.ouestfrance.querydsl.model.GroupFilter;
import fr.ouestfrance.querydsl.model.Filter;
import fr.ouestfrance.querydsl.model.GroupFilter;
import fr.ouestfrance.querydsl.model.SimpleFilter;
import fr.ouestfrance.querydsl.service.FilterFieldAnnotationProcessorService;
import fr.ouestfrance.querydsl.utils.ReflectUtils;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand All @@ -17,29 +18,29 @@
* @param <T> Type of returned object
* Example: YOu can define a queryStringTranslatorService that transform filterField annotations to rest call
* <pre>{@code
* class QueryStringTranslatorService implements QueryDslProcessorService<String>{
* List<Mapper<String>> mappers = List.of(InMapper, EqualsMapper, ...);
* class QueryStringTranslatorService implements QueryDslProcessorService<String>{
* List<Mapper<String>> mappers = List.of(InMapper, EqualsMapper, ...);
*
* public Mapper<String> getMapper(FilterOperation operations){
* mappers.stream().filter(x->x.getOperation().equals(operation)).findFirst()
* .orElse(new DefaultMapper());
* }
* public Mapper<String> getMapper(FilterOperation operations){
* mappers.stream().filter(x->x.getOperation().equals(operation)).findFirst()
* .orElse(new DefaultMapper());
* }
*
* public group(List<String> filters, GroupFilter.Operand operand){
* return String.join(" "+operand+" ", filters); // Will result item1 AND item2 AND ...
* }
* }
* }</pre>
* public group(List<String> filters, GroupFilter.Operand operand){
* return String.join(" "+operand+" ", filters); // Will result item1 AND item2 AND ...
* }
* }
* }</pre>
* With mappers implementations like this
* <pre>{@code
* class EqualsMapper implements Mapper<String>{
* class EqualsMapper implements Mapper<String>{
*
* String map(FilterFieldInfoModel model, Object data){
* return model.getKey()+".equals("+data+")"
* // "uuid.equals(25)"
* }
* }
* }</pre>
* String map(FilterFieldInfoModel model, Object data){
* return model.getKey()+".equals("+data+")"
* // "uuid.equals(25)"
* }
* }
* }</pre>
*/
public interface QueryDslProcessorService<T> {

Expand Down Expand Up @@ -106,15 +107,11 @@ private Optional<T> handleGroup(GroupFilter filterGroup, Object object) {
* @return concrete filter with values if the object has data
*/
private Optional<T> handleFilter(SimpleFilter filter, Object object) {
Object data = ReflectUtils.safeGet(object, filter.metadata().getter());
if (data == null) {
return Optional.empty();
}
FilterOperation operation = filter.operation();
Mapper<T> mapper = getMapper(operation);
return Optional.ofNullable(mapper.map(filter, data));
return ReflectUtils.getObject(filter.field(), object)
.map(x -> getMapper(filter.operation()).map(filter, x));
}


/**
* Return concrete mapper for a specific operation
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package fr.ouestfrance.querydsl.service.ext;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.util.Optional;

/**
* Internal reflect class that allow to retrieve object
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class ReflectUtils {


/**
* Get safe value for a field
*
* @param field to retrieve data
* @param object source object
* @return optional value
*/
@SneakyThrows
@SuppressWarnings("java:S3011")
public static Optional<Object> getObject(Field field, Object object) {
// allow to access the field if record or field from clazz
field.setAccessible(true);
return Optional.ofNullable(field.get(object));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import fr.ouestfrance.querydsl.FilterField;
import fr.ouestfrance.querydsl.FilterFields;
import fr.ouestfrance.querydsl.model.FieldMetadata;
import fr.ouestfrance.querydsl.model.SimpleFilter;
import fr.ouestfrance.querydsl.model.GroupFilter;
import fr.ouestfrance.querydsl.model.Filter;
import fr.ouestfrance.querydsl.model.GroupFilter;
import fr.ouestfrance.querydsl.model.SimpleFilter;
import fr.ouestfrance.querydsl.service.validators.FilterFieldConstraintException;
import fr.ouestfrance.querydsl.service.validators.FilterFieldValidatorService;
import fr.ouestfrance.querydsl.service.validators.FilterFieldViolation;
import fr.ouestfrance.querydsl.utils.ReflectUtils;

import java.lang.reflect.Field;
import java.util.*;
Expand Down Expand Up @@ -49,15 +47,14 @@ public List<Filter> scan(Class<?> clazz) {
.filter(this::hasFilterFieldAnnotation)
.forEach(
field -> {
FieldMetadata fieldMetadata = new FieldMetadata(field.getName(), field.getType(), ReflectUtils.getGetter(clazz, field));
FilterFields filterFields = field.getAnnotation(FilterFields.class);
FilterFields filterFields = field.getAnnotation(FilterFields.class);
List<FilterField> groupFilters = new ArrayList<>();
if (filterFields!= null && !filterFields.groupName().isEmpty()) {
groupFilters.addAll(Arrays.stream(filterFields.value()).toList());
GroupFilter filterAndGroup = new GroupFilter(UUID.randomUUID().toString(), new ArrayList<>(), GroupFilter.Operand.AND);
Arrays.stream(filterFields.value())
.forEach(filterField -> {
SimpleFilter filter = new SimpleFilter(firstNotEmpty(filterField.key(), field.getName()), filterField.operation(), filterField.orNull(), fieldMetadata);
SimpleFilter filter = new SimpleFilter(firstNotEmpty(filterField.key(), field.getName()), filterField.operation(), filterField.orNull(), field);
validatorService.validate(filter).ifPresent(violations::add);
filterAndGroup.filters().add(filter);
});
Expand All @@ -69,7 +66,7 @@ public List<Filter> scan(Class<?> clazz) {
.filter(x-> !groupFilters.contains(x))
.forEach(
filterField -> {
SimpleFilter filter = new SimpleFilter(firstNotEmpty(filterField.key(), field.getName()), filterField.operation(), filterField.orNull(), fieldMetadata);
SimpleFilter filter = new SimpleFilter(firstNotEmpty(filterField.key(), field.getName()), filterField.operation(), filterField.orNull(), field);
validatorService.validate(filter).ifPresent(violations::add);
appendToGroup(rootGroup, filterField.groupName(), filter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public class FilterFieldValidatorService {
*/
public Optional<FilterFieldViolation> validate(SimpleFilter filter) {
return getValidator(filter.operation())
.filter(x-> !x.validate((Class<?>) filter.metadata().type()))
.map(x -> new FilterFieldViolation(filter.metadata().name(), "Operation " + filter.operation() + " " + x.message()));
.filter(x-> !x.validate((Class<?>) filter.field().getType()))
.map(x -> new FilterFieldViolation(filter.field().getName(), "Operation " + filter.operation() + " " + x.message()));
}

/**
Expand Down
53 changes: 0 additions & 53 deletions src/main/java/fr/ouestfrance/querydsl/utils/ReflectUtils.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ void shouldLoad() {
assertNotNull(x);
assertTrue(x instanceof SimpleFilter);
SimpleFilter filter = (SimpleFilter)x;
assertNotNull(filter.metadata());
assertNotNull(filter.metadata().getter());
assertNotNull(filter.metadata().type());
assertNotNull(filter.field());
shouldFindOrNull.set(shouldFindOrNull.get() | filter.orNull());
});
assertTrue(shouldFindOrNull.get());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package fr.ouestfrance.querydsl.service.validators;

import fr.ouestfrance.querydsl.FilterOperation;
import fr.ouestfrance.querydsl.model.FieldMetadata;
import fr.ouestfrance.querydsl.model.SimpleFilter;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;

import java.util.List;
Expand All @@ -15,18 +15,25 @@ class FilterFieldValidatorServiceTest {

private final FilterFieldValidatorService validator = new FilterFieldValidatorService();

static class SampleClass{
List<String> lists;
String value;
}

@SneakyThrows
@Test
void shouldSentViolations(){
Optional<FilterFieldViolation> violations = validator.validate(
new SimpleFilter("test", FilterOperation.EQ, false, new FieldMetadata("test", List.class, null)));
new SimpleFilter("test", FilterOperation.EQ, false, SampleClass.class.getDeclaredField("lists")));

assertFalse(violations.isEmpty());
}

@SneakyThrows
@Test
void shouldValidate(){
Optional<FilterFieldViolation> violations = validator.validate(
new SimpleFilter("test", FilterOperation.EQ, false, new FieldMetadata("test", String.class, null)));
new SimpleFilter("test", FilterOperation.EQ, false, SampleClass.class.getDeclaredField("value")));

assertTrue(violations.isEmpty());
}
Expand Down
39 changes: 0 additions & 39 deletions src/test/java/fr/ouestfrance/querydsl/utils/ReflectUtilsTest.java

This file was deleted.

0 comments on commit 5300eb3

Please sign in to comment.