Skip to content

Commit

Permalink
Create initial operator extensibility by making it a class and creati…
Browse files Browse the repository at this point in the history
…ng a registry
  • Loading branch information
Jean Sossmeier committed Apr 3, 2024
1 parent cea44c9 commit 1279484
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 111 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
102 changes: 27 additions & 75 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,43 @@
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, String type, Kind kind) {
this.name = name;
this.type = type;
this.kind = kind;
}

/**
* 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 Operator AND = new Operator("and", "Logical", Operator.Kind.COMPOUND);

public static final Operator OR = new Operator("or", "Logical", Operator.Kind.COMPOUND);
public static final Operator NOT = new Operator("not", "Logical", Operator.Kind.UNARY);
public static final Operator EQUALS = new Operator("equals", "String", Operator.Kind.BINARY);
public static final Operator CONTAINS = new Operator("contains", "String", Operator.Kind.BINARY);
public static final Operator STARTS = new Operator("starts", "String", Operator.Kind.BINARY);
public static final Operator ENDS = new Operator("ends", "String", Operator.Kind.BINARY);
public static final Operator EQ = new Operator("eq", "Numeric", Operator.Kind.BINARY);
public static final Operator GT = new Operator("gt", "Numeric", Operator.Kind.BINARY);
public static final Operator GTE = new Operator("gte", "Numeric", Operator.Kind.BINARY);
public static final Operator LT = new Operator("lt", "Numeric", Operator.Kind.BINARY);
public static final Operator LTE = new Operator("lte", "Numeric", Operator.Kind.BINARY);
public static final Operator IN = new Operator("in", "String|Numeric", Operator.Kind.BINARY);
public static final Operator BETWEEN = new Operator("between", "DateTime|Numeric", Operator.Kind.BINARY);
}
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 a registry
*
* @author jeansossmeier
*/
public class OperatorRegistry {
private static final OperatorRegistry INSTANCE = new OperatorRegistry();

public static OperatorRegistry getInstance() {
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.getInstance();

// 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,6 +30,21 @@
import java.util.List;
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;

/**
* This class is responsible for traversing
* the expression tree and generating an
Expand Down Expand Up @@ -207,48 +222,33 @@ public String visitExpressionValue(ExpressionValue<? extends Comparable> value,

private String resolveOperator(Operator operator) {
String op = "";
switch (operator) {
/* Logical operators */
case AND:
case OR:
case NOT:
op = operator.getName().toUpperCase();
break;
/* Logical operators */
if (operator.equals(AND) || operator.equals(OR) || operator.equals(NOT)) {
op = operator.getName().toUpperCase();

/* Relational string operators*/
case EQUALS:
op = "=";
break;
case CONTAINS:
case STARTS:
case ENDS:
op = "LIKE";
break;
} else if (operator.equals(EQUALS)) {
op = "=";
} else if (operator.equals(CONTAINS) || operator.equals(STARTS) || operator.equals(ENDS)) {
op = "LIKE";

/* Relational numeric operators*/
case LT:
op = "<";
break;
case GT:
op = ">";
break;
case EQ:
op = "=";
break;
case GTE:
op = ">=";
break;
case LTE:
op = "<=";
break;
} else if (operator.equals(LT)) {
op = "<";
} else if (operator.equals(GT)) {
op = ">";
} else if (operator.equals(EQ)) {
op = "=";
} else if (operator.equals(GTE)) {
op = ">=";
} else if (operator.equals(LTE)) {
op = "<=";

/* Common operators */
case IN:
op = "IN";
break;
case BETWEEN:
op = "BETWEEN";
break;
} else if (operator.equals(IN)) {
op = "IN";
} else if (operator.equals(BETWEEN)) {
op = "BETWEEN";
}
return op;
}
Expand Down

0 comments on commit 1279484

Please sign in to comment.