Skip to content

Commit

Permalink
Enhancing filters
Browse files Browse the repository at this point in the history
  • Loading branch information
denis-itskovich committed Apr 10, 2019
1 parent 03c9db2 commit 1c53bc0
Show file tree
Hide file tree
Showing 21 changed files with 121 additions and 33 deletions.
2 changes: 1 addition & 1 deletion libs.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# suppress inspection "UnusedProperty" for whole file
slimUtilsVer = 0.3.76
slimUtilsVer = 0.3.77
slimUtilsGroup = com.slimgears.utils
slimStreamUtils = $slimUtilsGroup:stream-utils:$slimUtilsVer
slimRxUtils = $slimUtilsGroup:rx-utils:$slimUtilsVer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
package com.slimgears.rxrepo.apt;

import com.google.auto.service.AutoService;
import com.slimgears.apt.data.TypeInfo;
import com.slimgears.util.autovalue.apt.Context;
import com.slimgears.util.autovalue.apt.PropertyInfo;
import com.slimgears.util.autovalue.apt.extensions.Extension;

import javax.annotation.processing.SupportedAnnotationTypes;
import java.util.Collection;
import java.util.stream.Collectors;

@AutoService(Extension.class)
@SupportedAnnotationTypes("com.slimgears.rxrepo.annotations.UseFilters")
public class FiltersExtension implements Extension {
@Override
public String generateClassBody(Context context) {
return context.evaluateResource("filter-body.java.vm");
Collection<PropertyInfo> filterableProperties = context.properties()
.stream()
.filter(p -> p.annotations()
.stream()
.anyMatch(a -> a.type().equals(TypeInfo.of("com.slimgears.rxrepo.annotations.Filterable"))))
.collect(Collectors.toList());

return context.evaluatorForResource("filter-body.java.vm")
.variable("filterableProperties", filterableProperties)
.evaluate();
}
}
24 changes: 11 additions & 13 deletions rxrepo-apt/src/main/resources/filter-body.java.vm
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,19 @@

@$[com.google.auto.value.AutoValue]
public static abstract class Filter#typeParamsDeclaration($sourceClass) implements com.slimgears.rxrepo.filters.Filter<${targetClass.simpleName()}#typeParams($sourceClass)>, $[com.slimgears.rxrepo.filters.TextFilter] {
#foreach ($p in $properties)
#foreach ($p in $filterableProperties)
@$[javax.annotation.Nullable] public abstract #filterType($p) ${p.name()}();
#end
@Override @$[javax.annotation.Nullable] public abstract String matchesText();
@Override @$[javax.annotation.Nullable] public abstract String searchText();

@Override
public <__S> $[java.util.Optional]<$[com.slimgears.rxrepo.expressions.BooleanExpression]<__S>> toExpression($[com.slimgears.rxrepo.expressions.ObjectExpression]<__S, $targetClass.simpleName()#typeParams($sourceClass)> arg) {
Expressions<__S#foreach ($tp in $sourceClass.typeParams()), $tp.name()#end> self = new Expressions<>(arg);
return $[com.slimgears.rxrepo.filters.Filters].combine(
#foreach ($p in $properties)
$[java.util.Optional].ofNullable(${p.name()}()).flatMap(f -> f.toExpression(self.${p.name()}))#if ($foreach.hasNext),#end##
#if ($foreach.hasNext)##

##
#end
return $[com.slimgears.rxrepo.filters.Filters].combineExpressions(
$[com.slimgears.rxrepo.filters.Filters].fromTextFilter(this, arg)##
#foreach ($p in $filterableProperties)##
,
$[java.util.Optional].ofNullable(${p.name()}()).flatMap(f -> f.toExpression(self.${p.name()}))
#end##
);
}
Expand All @@ -41,7 +39,7 @@
}

public static #typeParamsDeclaration($sourceClass) Filter#typeParams($sourceClass) create(
#foreach ($p in $properties)
#foreach ($p in $filterableProperties)
@$[javax.annotation.Nullable] #filterType($p) ${p.name()}##
#if ($foreach.hasNext),##

Expand All @@ -50,18 +48,18 @@
#end##
) {
return Filter.#typeParams($sourceClass)builder()
#foreach ($p in $properties)
#foreach ($p in $filterableProperties)
.${p.name()}($p.name())
#end
.build();
}

@AutoValue.Builder
public interface Builder#typeParamsDeclaration($sourceClass) {
#foreach ($p in $properties)
#foreach ($p in $filterableProperties)
Builder#typeParams($sourceClass) ${p.name()}(#filterType($p) ${p.name()});
#end
Builder#typeParams($sourceClass) matchesText(String matchesText);
Builder#typeParams($sourceClass) searchText(String searchText);
Filter#typeParams($sourceClass) build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.slimgears.rxrepo.queries;

import com.slimgears.rxrepo.annotations.Filterable;
import com.slimgears.rxrepo.annotations.Indexable;
import com.slimgears.rxrepo.expressions.ObjectExpression;
import com.slimgears.rxrepo.filters.ComparableFilter;
import com.slimgears.rxrepo.filters.StringFilter;
Expand Down Expand Up @@ -86,7 +88,7 @@ public void testFilterToExpression() {
.refEntity(TestRefEntity.Filter.builder().id(ComparableFilter.greaterOrEqual(8)).build())
.number(ComparableFilter.lessThan(5))
.text(StringFilter.contains("ity 1"))
.matchesText("ity")
.searchText("ity")
.build();

Function<TestEntity, Boolean> func = filter.toExpression(ObjectExpression.arg(TestEntity.class))
Expand All @@ -96,4 +98,11 @@ public void testFilterToExpression() {
Assert.assertTrue(func.apply(testEntity1));
Assert.assertFalse(func.apply(testEntity2));
}

@Test
public void testAnnotationRetrieval() {
Assert.assertTrue(TestEntity.metaClass.text.hasAnnotation(Filterable.class));
Assert.assertTrue(TestEntity.metaClass.number.hasAnnotation(Indexable.class));
Assert.assertFalse(TestEntity.metaClass.refEntity.hasAnnotation(Indexable.class));
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package com.slimgears.rxrepo.queries;

import com.slimgears.rxrepo.annotations.Filterable;
import com.slimgears.rxrepo.annotations.Indexable;
import com.slimgears.rxrepo.annotations.UseFilters;
import com.slimgears.util.autovalue.annotations.AutoValuePrototype;
import com.slimgears.util.autovalue.annotations.Key;
import com.slimgears.util.autovalue.annotations.Reference;
import com.slimgears.util.autovalue.annotations.UseCopyAnnotator;

import java.util.Collection;

@AutoValuePrototype
@UseFilters
@UseCopyAnnotator
public interface TestEntityPrototype {
@Key TestKey key();
String text();
int number();
@Reference TestRefEntity refEntity();
@Indexable @Filterable String text();
@Indexable @Filterable int number();
@Reference @Filterable TestRefEntity refEntity();
Collection<TestRefEntity> refEntities();
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.slimgears.rxrepo.queries;

import com.slimgears.rxrepo.annotations.Filterable;
import com.slimgears.rxrepo.annotations.UseFilters;
import com.slimgears.util.autovalue.annotations.AutoValuePrototype;
import com.slimgears.util.autovalue.annotations.Key;

@AutoValuePrototype
@UseFilters
public interface TestRefEntityPrototype {
@Key int id();
String text();
@Filterable @Key int id();
@Filterable String text();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.slimgears.rxrepo.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Filterable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.slimgears.rxrepo.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Indexable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.slimgears.rxrepo.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Searchable {
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ enum Type {
ToUpper(StringUnaryOperationExpression.class, OperationType.Unary, ValueType.String, just(String.class)),
Trim(StringUnaryOperationExpression.class, OperationType.Unary, ValueType.String, just(String.class)),

SearchText(BooleanBinaryOperationExpression.class, OperationType.Binary, ValueType.Boolean, just(Boolean.class)),

Negate(NumericUnaryOperationExpression.class, OperationType.Unary, ValueType.Numeric, Type::fromArgument),
Add(NumericBinaryOperationExpression.class, OperationType.Binary, ValueType.Numeric, Type::fromFirstArgument),
Sub(NumericBinaryOperationExpression.class, OperationType.Binary, ValueType.Numeric, Type::fromFirstArgument),
Expand Down Expand Up @@ -107,6 +109,7 @@ enum Type {
AsNumeric(NumericUnaryOperationExpression.class, OperationType.Unary, ValueType.Numeric, Type::fromArgument),
AsString(StringUnaryOperationExpression.class, OperationType.Unary, ValueType.String, just(String.class)),
AsBoolean(BooleanUnaryOperationExpression.class, OperationType.Unary, ValueType.Boolean, just(Boolean.class)),

;

Type(Class<? extends Expression> type, OperationType opType, ValueType valType, Function<ObjectExpression<?, ?>, TypeToken<?>> typeResolver) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,20 @@ default BooleanExpression<S> eq(ObjectExpression<S, T> value) {
}

default BooleanExpression<S> eq(T value) {
return eq(ConstantExpression.of(value));
return value != null
? eq(ConstantExpression.of(value))
: isNull();
}

default BooleanExpression<S> notEq(ObjectExpression<S, T> value) {
return eq(value).not();
}

default BooleanExpression<S> notEq(T value) {
return eq(value).not();
return value != null
? eq(value).not()
: isNotNull();

}

default BooleanExpression<S> isNull() {
Expand Down Expand Up @@ -110,12 +115,12 @@ default <E> CollectionExpression<S, E> ref(CollectionPropertyExpression<?, T, E>
return PropertyExpression.ofCollection(this, expression.property());
}

default BooleanExpression<S> matches(ObjectExpression<S, String> pattern) {
return BooleanBinaryOperationExpression.create(Type.Matches, this, pattern);
default BooleanExpression<S> searchText(ObjectExpression<S, String> pattern) {
return BooleanBinaryOperationExpression.create(Type.SearchText, this, pattern);
}

default BooleanExpression<S> matches(String pattern) {
return matches(ConstantExpression.of(pattern));
default BooleanExpression<S> searchText(String pattern) {
return searchText(ConstantExpression.of(pattern));
}

static <S> ObjectExpression<S, S> arg(TypeToken<S> type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.slimgears.rxrepo.expressions;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.slimgears.rxrepo.expressions.internal.BooleanBinaryOperationExpression;
import com.slimgears.rxrepo.expressions.internal.BooleanPropertyExpression;
import com.slimgears.rxrepo.expressions.internal.CollectionPropertyExpression;
import com.slimgears.rxrepo.expressions.internal.ComparablePropertyExpression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ default BooleanExpression<S> matches(String substr) {
return matches(ConstantExpression.of(substr));
}

default BooleanExpression<S> matches(ObjectExpression<S, String> substr) {
return BooleanBinaryOperationExpression.create(Type.Matches, this, substr);
}

default NumericExpression<S, Integer> length() {
return NumericUnaryOperationExpression.create(Type.Length, this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface ComparableFilterPrototype<T extends Comparable<T>> extends Valu
@Override
default <S> Optional<BooleanExpression<S>> toExpression(ObjectExpression<S, T> arg) {
ComparableExpression<S, T> comparableArg = ObjectExpression.asComparable(arg);
return Filters.combine(
return Filters.combineExpressions(
ValueFilterPrototype.super.toExpression(comparableArg),
Optional.ofNullable(lessThan()).map(comparableArg::lessThan),
Optional.ofNullable(lessOrEqual()).map(comparableArg::lessOrEqual),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default Filter<T> combineWith(Filter<T> filter) {
return new Filter<T>() {
@Override
public <S> Optional<BooleanExpression<S>> toExpression(ObjectExpression<S, T> arg) {
return Filters.combine(self.toExpression(arg), filter.toExpression(arg));
return Filters.combineExpressions(self.toExpression(arg), filter.toExpression(arg));
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package com.slimgears.rxrepo.filters;

import com.slimgears.rxrepo.expressions.BooleanExpression;
import com.slimgears.rxrepo.expressions.ObjectExpression;

import java.util.Arrays;
import java.util.Optional;

public class Filters {
public static <S, T> Optional<BooleanExpression<S>> fromTextFilter(TextFilter filter, ObjectExpression<S, T> arg) {
return Optional.ofNullable(filter.searchText()).map(arg::searchText);
}

@SafeVarargs
public static <T> Optional<BooleanExpression<T>> combine(Optional<BooleanExpression<T>>... filters) {
public static <T> Optional<BooleanExpression<T>> combineExpressions(Optional<BooleanExpression<T>>... filters) {
return Arrays.stream(filters)
.filter(Optional::isPresent)
.map(Optional::get)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface StringFilterPrototype extends ComparableFilterPrototype<String>
@Override
default <S> Optional<BooleanExpression<S>> toExpression(ObjectExpression<S, String> arg) {
StringExpression<S> stringArg = ObjectExpression.asString(arg);
return Filters.combine(
return Filters.combineExpressions(
ComparableFilterPrototype.super.toExpression(stringArg),
Optional.ofNullable(contains()).map(stringArg::contains),
Optional.ofNullable(startsWith()).map(stringArg::startsWith),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
import javax.annotation.Nullable;

public interface TextFilter {
@Nullable String matchesText();
@Nullable String searchText();
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface ValueFilterPrototype<T> extends Filter<T> {

@Override
default <S> Optional<BooleanExpression<S>> toExpression(ObjectExpression<S, T> arg) {
return Filters.combine(
return Filters.combineExpressions(
Optional.ofNullable(equalsTo()).map(arg::eq),
Optional.ofNullable(equalsToAny()).map(arg::in));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ private static class InternalVisitor extends ExpressionVisitor<Void, Function> {
.put(Expression.Type.Min, notSupported())
.put(Expression.Type.Max, notSupported())
.put(Expression.Type.Sum, notSupported())
.put(Expression.Type.SearchText, Expressions.fromBinary((Object obj, String str) -> obj.toString().contains(str)))
.build();

private final static ImmutableMap<Expression.OperationType, Function<Function[], Function>> operationTypeReducersMap = ImmutableMap.<Expression.OperationType, Function<Function[], Function>>builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public DefaultSqlExpressionGenerator() {

protected ExpressionTextGenerator.Builder createBuilder() {
return ExpressionTextGenerator.builder()
.add(Expression.Type.IsNull, "(%s is null)")
.add(Expression.Type.Add, "(%s + %s)")
.add(Expression.Type.Sub, "(%s - %s)")
.add(Expression.Type.Mul, "(%s * %s)")
Expand Down Expand Up @@ -47,6 +48,10 @@ protected ExpressionTextGenerator.Builder createBuilder() {
.add(Expression.Type.Sum, "SUM(%s)")
.add(Expression.Type.StringConstant, "'%s'")
.add(Expression.Type.AsString, "CONVERT(varchar, %s)")
.add(Expression.Type.AsBoolean, "%s")
.add(Expression.Type.AsNumeric, "%s")
.add(Expression.Type.AsComparable, "%s")
.add(Expression.Type.SearchText, notSupported())
.add(Expression.OperationType.Argument, "__argument__")
.add(Expression.OperationType.Constant, "%s")
.add(Expression.OperationType.Property, ExpressionTextGenerator.Reducer.join("."))
Expand Down Expand Up @@ -74,6 +79,12 @@ public <S, T> String toSqlExpression(ObjectExpression<S, T> expression, ObjectEx
return withParams(params, () -> toSqlExpression(expression, arg));
}

protected static ExpressionTextGenerator.Reducer notSupported() {
return str -> {
throw new IllegalArgumentException("Not supported expression");
};
}

private static ExpressionTextGenerator.Reducer formatAndFixQuotes(String format) {
return ExpressionTextGenerator.Reducer.fromFormat(format).andThen(str -> str.replaceAll("' \\+ '", ""));
}
Expand Down

0 comments on commit 1c53bc0

Please sign in to comment.