Skip to content

Commit

Permalink
Merge pull request #3 from jeansossmeier/feature/version-2.1.0
Browse files Browse the repository at this point in the history
Allow parsing complex parameter structures as json and propagating via binary expression attributes
  • Loading branch information
jeansossmeier authored Apr 12, 2024
2 parents fcf6049 + 7825943 commit ff14e8a
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.intuit.graphql</groupId>
<artifactId>graphql-filter-java</artifactId>
<version>2.0.0</version>
<version>2.1.0</version>

<name>${project.artifactId}</name>
<description>A java library to transform graphql filter into database filter</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.intuit.graphql.filter.ast;

import java.util.Map;

/**
* Base class for a node in the
* expression tree. All concrete expression nodes
Expand All @@ -27,6 +29,7 @@ public abstract class AbstractExpression implements Expression {
private Expression leftOperand;
private Operator operator;
private Expression rightOperand;
private Map<String, Object> attributes;

/**
* Default constructor.
Expand Down Expand Up @@ -110,4 +113,13 @@ public void setOperator(Operator operator) {
public void setRightOperand(Expression rightOperand) {
this.rightOperand = rightOperand;
}

public void setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}

public Map<String, Object> getAttributes() {
return attributes;
}

}
1 change: 1 addition & 0 deletions src/main/java/com/intuit/graphql/filter/ast/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public enum Kind {
public static final String TYPE_STRING = "String";
public static final String TYPE_NUMERIC = "Numeric";
public static final String TYPE_DATETIME = "DateTime";
public static final String TYPE_JSON = "Json";

public static final Operator AND = new Operator("and", Operator.Kind.COMPOUND, TYPE_LOGICAL);
public static final Operator OR = new Operator("or", Operator.Kind.COMPOUND, TYPE_LOGICAL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.intuit.graphql.filter.client;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intuit.graphql.filter.ast.BinaryExpression;
import com.intuit.graphql.filter.ast.CompoundExpression;
import com.intuit.graphql.filter.ast.Expression;
Expand Down Expand Up @@ -48,13 +50,22 @@ public class FilterExpressionParser {
private static final String KIND_UNARY = Operator.Kind.UNARY.name();

private final OperatorRegistry operatorRegistry;
private final ObjectMapper objectMapper;


public FilterExpressionParser() {
this.operatorRegistry = OperatorRegistry.withDefaultOperators();
this.objectMapper = new ObjectMapper();
}

public FilterExpressionParser(OperatorRegistry operatorRegistry) {
this.operatorRegistry = operatorRegistry;
this.objectMapper = new ObjectMapper();
}

public FilterExpressionParser(OperatorRegistry operatorRegistry, ObjectMapper objectMapper) {
this.operatorRegistry = operatorRegistry;
this.objectMapper = objectMapper;
}

public Expression parseFilterExpression(Map filterArgs) {
Expand Down Expand Up @@ -102,8 +113,7 @@ private Expression handleFieldExpression(Map.Entry entry, final String key) {
final ExpressionField leftOperand = new ExpressionField(entry.getKey().toString());
final BinaryExpression binaryExpression =
(entry.getValue() instanceof Map)
? (BinaryExpression)
createExpressionTree((Map) entry.getValue())
? (BinaryExpression) createExpressionTree((Map) entry.getValue())
: (BinaryExpression) handleBinary(entry, Operator.IN.getKey());

binaryExpression.setLeftOperand(leftOperand);
Expand All @@ -115,21 +125,35 @@ private Expression handleUnary(Map.Entry entry, String key) {
return new UnaryExpression(operand, getOperator(key), null);
}

private Expression handleBinary(Map.Entry entry, String key) {
private Expression handleBinary(Map.Entry entry, String key) throws RuntimeException{
final BinaryExpression binaryExpression = new BinaryExpression();
binaryExpression.setOperator(getOperator(key));
final Operator operator = getOperator(key);
binaryExpression.setOperator(operator);

if (entry.getValue() instanceof Collection) {
final List<Comparable> expressionValues = new ArrayList<>();
for (Comparable value : (List<Comparable>) entry.getValue()) {
expressionValues.add(convertIfDate(value));
final List expressionValues = new ArrayList<>();
for (Object value : (List) entry.getValue()) {
expressionValues.add(convertObject(value));
}
binaryExpression.setRightOperand(new ExpressionValue(expressionValues));
} else {
binaryExpression.setRightOperand(new ExpressionValue<>(convertIfDate((Comparable) entry.getValue())));
return binaryExpression;
} else if (entry.getValue() instanceof Map) {
binaryExpression.setRightOperand(new ExpressionValue<>(getJson(entry)));
return binaryExpression;
}

binaryExpression.setRightOperand(new ExpressionValue<>(convertObject(entry.getValue())));
return binaryExpression;
}

private String getJson(Map.Entry entry) {
try {
return objectMapper.writeValueAsString(entry.getValue());
} catch (JsonProcessingException e) {
return "";
}
}

private Expression handleCompound(
Deque<Expression> expressionStack, Map.Entry entry, String key) {

Expand Down Expand Up @@ -164,6 +188,14 @@ private boolean isOperator(String key) {
return false;
}
}

private Object convertObject(Object value) {
if (value instanceof Comparable) {
return convertIfDate((Comparable) value);
}
return value;
}

private Comparable convertIfDate(Comparable value) {
if (value == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public interface ExpressionValueHandler {
void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue);
ExpressionValue<? extends Object> expressionValue);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public SQLExpressionValueVisitor(Map<Operator, ExpressionValueHandler> expressio
}

public String visitExpressionValue(
Operator operator, ExpressionValue<? extends Comparable> expressionValue, String data) {
Operator operator, ExpressionValue<? extends Object> expressionValue, String data) {
final StringBuilder expressionBuilder = new StringBuilder(data);

final ExpressionValueHandler handler = expressionValueHandlers.get(operator);
Expand All @@ -43,7 +43,7 @@ public Map<Operator, ExpressionValueHandler> getExpressionValueHandlers() {
return expressionValueHandlers;
}

protected String resolveValue(Comparable value) {
protected String resolveValue(Object value) {
if (value instanceof Number) {
return value.toString();
} else {
Expand All @@ -56,7 +56,7 @@ public class ContainsHandler implements ExpressionValueHandler {
public void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue) {
ExpressionValue<? extends Object> expressionValue) {

final String value = expressionValue.infix();
if (hasWildcardValue(value)) {
Expand All @@ -76,7 +76,7 @@ public class StartsHandler implements ExpressionValueHandler {
public void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue) {
ExpressionValue<? extends Object> expressionValue) {

expressionBuilder.append("'").append(expressionValue.infix()).append("%").append("'");
}
Expand All @@ -87,7 +87,7 @@ public class EndsHandler implements ExpressionValueHandler {
public void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue) {
ExpressionValue<? extends Object> expressionValue) {

expressionBuilder.append("'").append("%").append(expressionValue.infix()).append("'");
}
Expand All @@ -98,9 +98,9 @@ public class BetweenHandler implements ExpressionValueHandler {
public void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue) {
ExpressionValue<? extends Object> expressionValue) {

List<Comparable> expressionValues = (List<Comparable>)expressionValue.value();
List<Object> expressionValues = (List<Object>)expressionValue.value();

expressionBuilder
.append(resolveValue(expressionValues.get(0)))
Expand All @@ -114,9 +114,9 @@ public class InHandler implements ExpressionValueHandler {
public void handle(
Operator operator,
StringBuilder expressionBuilder,
ExpressionValue<? extends Comparable> expressionValue) {
ExpressionValue<? extends Object> expressionValue) {

final List<Comparable> expressionValues = (List<Comparable>)expressionValue.value();
final List<Object> expressionValues = (List<Object>)expressionValue.value();
expressionBuilder.append("(");

for (int i = 0; i < expressionValues.size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.intuit.graphql.filter.visitors;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intuit.graphql.filter.ast.BinaryExpression;
import com.intuit.graphql.filter.ast.CompoundExpression;
import com.intuit.graphql.filter.ast.Expression;
Expand Down Expand Up @@ -63,6 +65,7 @@ public class SQLExpressionVisitor implements ExpressionVisitor<String> {
private Map<Operator, String> mappings;
private Map<String, List<String>> metadataCollector;
private SqlQueryValueNormalizer sqlQueryValueNormalizer;
private ObjectMapper objectMapper;

private boolean generateWherePrefix = true;
private String metadataPrefix = DEFAULT_METADATA_PREFIX;
Expand All @@ -76,6 +79,7 @@ public SQLExpressionVisitor(final Map<String, String> fieldMap) {
this.expressionValueVisitor = SQLExpressionValueVisitor.DEFAULT;
this.fieldValueTransformer = DEFAULT_FIELD_VALUE_TRANSFORMER;
this.sqlQueryValueNormalizer = DEFAULT_NORMALIZER;
this.objectMapper = new ObjectMapper();
}

public SQLExpressionVisitor(
Expand Down Expand Up @@ -130,7 +134,7 @@ public String visitBinaryExpression(final BinaryExpression binaryExpression, fin
operatorStack.push(binaryExpression.getOperator());

final String rightOperand = binaryExpression.getRightOperand().accept(this, "");
final String[] filterValues = rightOperand.replaceAll("[()]", "").split(",");
final String[] filterValues = rightOperand.replaceAll("[(){}]", "").split(",");
collectMetadata(leftOperand, filterValues);

final String normalizedRightOperand = normalizeString(rightOperand);
Expand Down Expand Up @@ -221,6 +225,12 @@ private String prepareCustomExpression(
binaryExpression, fieldName, queryString, resolvedOperator);
}

if (isJsonQueryString(queryString)) {
binaryExpression.setAttributes(stringAsJson(queryString));
return customExpression.generateExpression(
binaryExpression, fieldName, queryString, resolvedOperator);
}

final String enclosingLogicalOperator =
customExpression.getEnclosingLogicalOperator().getValue();
return Arrays.stream(filterValues)
Expand All @@ -229,6 +239,15 @@ binaryExpression, fieldName, normalizeString(filterValue), resolvedOperator))
.collect(Collectors.joining(" " + enclosingLogicalOperator + " "));
}

private Map stringAsJson(String queryString) {
final String query = queryString.substring(1, queryString.length()-1);
try {
return objectMapper.readValue(query, Map.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}

private String formatBinaryExpression(
String data,
String leftOperand,
Expand Down Expand Up @@ -268,6 +287,10 @@ private void collectMetadata(final String metaDataType, final String[] filterVal
metadataCollector.put(metadataPrefix + metaDataType, filterValueList);
}

private boolean isJsonQueryString(String queryString) {
return queryString.startsWith("'{") && queryString.endsWith("}'");
}

public String resolveOperator(Operator operator) {
return mappings.getOrDefault(operator, "");
}
Expand Down Expand Up @@ -327,4 +350,12 @@ public CustomExpressionResolver getCustomExpressionResolver() {
public void setCustomExpressionResolver(CustomExpressionResolver customExpressionResolver) {
this.customExpressionResolver = customExpressionResolver;
}

public ObjectMapper getObjectMapper() {
return objectMapper;
}

public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
}

0 comments on commit ff14e8a

Please sign in to comment.