Skip to content

Commit

Permalink
Merge pull request #1 from jeansossmeier/feature/refactor-operator-ex…
Browse files Browse the repository at this point in the history
…tensibility

Feature: Create initial operator extensibility by making it a class and creating a registry
  • Loading branch information
jeansossmeier authored Apr 4, 2024
2 parents cea44c9 + d97b9ca commit 1985940
Show file tree
Hide file tree
Showing 12 changed files with 415 additions and 368 deletions.
5 changes: 5 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Roadmap
- Support custom operators and registry
- Make transformers more flexible
- Cleanup on code and optimize performance
- Move to Java 17
25 changes: 12 additions & 13 deletions src/main/java/com/intuit/graphql/filter/ast/ExpressionValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,20 @@ public ExpressionValue(V value) {
*/
@Override
public String infix() {
StringBuilder infix = new StringBuilder("");
String result = null;
if (value != null) {
if (value instanceof Iterable) {
Iterable<V> vals = (Iterable<V>) value;
for (V val : vals) {
infix.append(value.toString()).append(",");
}
result = infix.toString() == "" ? "" : infix.substring(0, infix.length()-1);
} else {
infix.append(value);
result = infix.toString();
final StringBuilder infix = new StringBuilder();
if (value == null) {
return null;
}

if (value instanceof Iterable) {
for (V val : (Iterable<V>) value) {
infix.append(val.toString()).append(",");
}
return infix.toString() == "" ? "" : infix.substring(0, infix.length()-1);
} else {
infix.append(value);
return infix.toString();
}
return result;
}

/**
Expand Down
105 changes: 31 additions & 74 deletions src/main/java/com/intuit/graphql/filter/ast/Operator.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright 2020 Intuit Inc.
Modifications Copyright 2024 Jean Luck Sossmeier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -16,92 +17,48 @@
package com.intuit.graphql.filter.ast;

/**
* Enum of operators for supporting relational
* and logical expressions.
* Class of operators for supporting relational and logical expressions.
*
* @author sjaiswal
* @author jeansossmeier
*/
public enum Operator {

/* Logical Operators */
AND("and", "Logical", Kind.COMPOUND),
OR ("or", "Logical", Kind.COMPOUND),
NOT ("not", "Logical", Kind.UNARY),

/* String Operators */
EQUALS("equals", "String", Kind.BINARY),
CONTAINS("contains", "String", Kind.BINARY),
STARTS("starts", "String", Kind.BINARY),
ENDS("ends", "String", Kind.BINARY),

/* Numeric Operators */
EQ("eq", "Numeric", Kind.BINARY),
GT("gt", "Numeric", Kind.BINARY),
GTE("gte", "Numeric", Kind.BINARY),
LT("lt", "Numeric", Kind.BINARY),
LTE("lte", "Numeric", Kind.BINARY),

/* Range Operators */
IN("in", "String|Numeric", Kind.BINARY),
BETWEEN("between","DateTime|Numeric", Kind.BINARY);

/**
* Enum of operator kind.
*/
enum Kind {
COMPOUND,
BINARY,
UNARY;
}

public class Operator {
private String name;
private String type;
private Kind kind;

Operator(String name, String type, Kind kind) {
this.type = type;
public Operator(String name, Kind kind, String... type) {
this.name = name;
this.kind = kind;
this.type = String.join("|", type);
}

/**
* Returns the Operator enum based
* on operator name.
* @param name
* @return
*/
public static Operator getOperator(String name) {
for (Operator operator : Operator.values()) {
if (operator.getName().equals(name)) {
return operator;
}
}
throw new IllegalArgumentException(String.valueOf(name));
}

/**
* Returns Operator kind based
* on operator name.
* @param name
* @return
*/
public static String getOperatorKind(String name) {
return getOperator(name).getKind().name();
}
public String getName() { return name; }
public String getType() { return type; }
public Kind getKind() { return kind; }

/**
* Returns operator name.
* @return
*/
public String getName() {
return name;
public enum Kind {
COMPOUND, BINARY, UNARY
}

/**
* Returns operator kind.
* @return
*/
public Kind getKind() {
return kind;
}
}
public static final String TYPE_LOGICAL = "Logical";
public static final String TYPE_STRING = "String";
public static final String TYPE_NUMERIC = "Numeric";
public static final String TYPE_DATETIME = "DateTime";

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);
public static final Operator NOT = new Operator("not", Operator.Kind.UNARY, TYPE_LOGICAL);
public static final Operator EQUALS = new Operator("equals", Operator.Kind.BINARY, TYPE_STRING);
public static final Operator CONTAINS = new Operator("contains", Operator.Kind.BINARY, TYPE_STRING);
public static final Operator STARTS = new Operator("starts", Operator.Kind.BINARY, TYPE_STRING);
public static final Operator ENDS = new Operator("ends", Operator.Kind.BINARY, TYPE_STRING);
public static final Operator EQ = new Operator("eq", Operator.Kind.BINARY, TYPE_NUMERIC);
public static final Operator GT = new Operator("gt", Operator.Kind.BINARY, TYPE_NUMERIC);
public static final Operator GTE = new Operator("gte", Operator.Kind.BINARY, TYPE_NUMERIC);
public static final Operator LT = new Operator("lt", Operator.Kind.BINARY, TYPE_NUMERIC);
public static final Operator LTE = new Operator("lte", Operator.Kind.BINARY, TYPE_NUMERIC);
public static final Operator IN = new Operator("in", Operator.Kind.BINARY, TYPE_STRING, TYPE_NUMERIC);
public static final Operator BETWEEN = new Operator("between", Operator.Kind.BINARY, TYPE_DATETIME, TYPE_NUMERIC);
}
90 changes: 90 additions & 0 deletions src/main/java/com/intuit/graphql/filter/ast/OperatorRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
Copyright 2020 Intuit Inc.
Modifications Copyright 2024 Jean Luck Sossmeier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.intuit.graphql.filter.ast;

import java.util.HashMap;
import java.util.Map;

import static com.intuit.graphql.filter.ast.Operator.AND;
import static com.intuit.graphql.filter.ast.Operator.BETWEEN;
import static com.intuit.graphql.filter.ast.Operator.CONTAINS;
import static com.intuit.graphql.filter.ast.Operator.ENDS;
import static com.intuit.graphql.filter.ast.Operator.EQ;
import static com.intuit.graphql.filter.ast.Operator.EQUALS;
import static com.intuit.graphql.filter.ast.Operator.GT;
import static com.intuit.graphql.filter.ast.Operator.GTE;
import static com.intuit.graphql.filter.ast.Operator.IN;
import static com.intuit.graphql.filter.ast.Operator.LT;
import static com.intuit.graphql.filter.ast.Operator.LTE;
import static com.intuit.graphql.filter.ast.Operator.NOT;
import static com.intuit.graphql.filter.ast.Operator.OR;
import static com.intuit.graphql.filter.ast.Operator.STARTS;

/**
* Class that represents an operator registry
*
* @author jeansossmeier
*/
public class OperatorRegistry {
private static final OperatorRegistry INSTANCE = new OperatorRegistry();

public static OperatorRegistry defaultInstance() {
return INSTANCE;
}

private final Map<String, Operator> operators = new HashMap<>();

public void registerOperator(Operator operator) {
operators.put(operator.getName(), operator);
}

public Operator getOperator(String name) {
final Operator operator = operators.get(name);
if (operator == null) {
throw new IllegalArgumentException("No operator found with name: " + name);
}
return operator;
}

public static OperatorRegistry withDefaultOperators() {
final OperatorRegistry registry = OperatorRegistry.defaultInstance();

// Logical Operators
registry.registerOperator(AND);
registry.registerOperator(OR);
registry.registerOperator(NOT);

// String Operators
registry.registerOperator(EQUALS);
registry.registerOperator(CONTAINS);
registry.registerOperator(STARTS);
registry.registerOperator(ENDS);

// Numeric Operators
registry.registerOperator(EQ);
registry.registerOperator(GT);
registry.registerOperator(GTE);
registry.registerOperator(LT);
registry.registerOperator(LTE);

// Range Operators
registry.registerOperator(IN);
registry.registerOperator(BETWEEN);

return registry;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
* expression visitors.
*
* @author sjaiswal
* @author jeansossmeier
*/
class ExpressionVisitorFactory {
public class ExpressionVisitorFactory {

/**
* Factory method for creating and returning
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* of specified format.
*
* @author sjaiswal
* @author jeansossmeier
*/
public class FilterExpression {

Expand All @@ -48,12 +49,12 @@ private FilterExpression(FilterExpressionBuilder expressionBuilder) {
* instance of FilterExpression class.
*/
public static class FilterExpressionBuilder {
private static final String FILTER_ARG = "filter";

private Field field;
private Map<String,String> fieldMap;
private Expression expressionAst;
private Map args;
private final String FILTER_ARG = "filter";
private FieldValueTransformer fieldValueTransformer;

private FilterExpressionBuilder () {
Expand Down Expand Up @@ -93,8 +94,8 @@ public FilterExpression build() {
expressionAst = expressionParser.parseFilterExpression((Map) filter);
}
}
FilterExpression expression = new FilterExpression(this);
return expression;

return new FilterExpression(this);
}
}

Expand Down
Loading

0 comments on commit 1985940

Please sign in to comment.