mapOfPair = getOrderedMapPair(child); // delegate to a dedicated visitor
try {
mapOfPair.forEach(map::putIfAbsent); // put contents of the current map pair to the resulting map
} catch (ClassCastException e) {
- throw new AerospikeDSLException("Map constant contains elements of different type");
+ throw new DslParseException("Map constant contains elements of different type");
}
}
@@ -414,12 +412,12 @@ public AbstractPart visitBasePath(ConditionParser.BasePathContext ctx) {
switch (part.getPartType()) {
case BIN_PART -> binPart = (BinPart) overrideType(part, ctx);
case LIST_PART, MAP_PART -> parts.add(overrideType(part, ctx));
- default -> throw new AerospikeDSLException("Unexpected path part: %s".formatted(part.getPartType()));
+ default -> throw new DslParseException("Unexpected path part: %s".formatted(part.getPartType()));
}
}
if (binPart == null) {
- throw new AerospikeDSLException("Expecting bin to be the first path part from the left");
+ throw new DslParseException("Expecting bin to be the first path part from the left");
}
return new BasePath(binPart, parts);
@@ -428,7 +426,7 @@ public AbstractPart visitBasePath(ConditionParser.BasePathContext ctx) {
@Override
public AbstractPart visitVariable(ConditionParser.VariableContext ctx) {
String text = ctx.VARIABLE_REFERENCE().getText();
- return new VariableOperand(extractVariableName(text));
+ return new VariableOperand(extractVariableNameOrFail(text));
}
private AbstractPart overrideType(AbstractPart part, ParseTree ctx) {
@@ -442,8 +440,8 @@ private AbstractPart overrideType(AbstractPart part, ParseTree ctx) {
if (pathFunction != null) {
Exp.Type type = pathFunction.getBinType();
if (type != null) {
- if (part instanceof BinPart) {
- ((BinPart) part).updateExp(type);
+ if (part instanceof BinPart binPart) {
+ binPart.updateExp(type);
} else {
part.setExpType(type);
}
@@ -451,11 +449,11 @@ private AbstractPart overrideType(AbstractPart part, ParseTree ctx) {
}
} else { // Override using Implicit type detection
Exp.Type implicitType = detectImplicitTypeFromUpperTree(ctx);
- if (part instanceof BinPart) {
+ if (part instanceof BinPart binPart) {
if (implicitType == null) {
implicitType = Exp.Type.INT;
}
- ((BinPart) part).updateExp(implicitType);
+ binPart.updateExp(implicitType);
} else { // ListPart or MapPart
if (implicitType == null) {
implicitType = TypeUtils.getDefaultType(part);
@@ -473,10 +471,9 @@ public AbstractPart visitPath(ConditionParser.PathContext ctx) {
// if there are other parts except bin, get a corresponding Exp
if (!parts.isEmpty() || ctx.pathFunction() != null && ctx.pathFunction().pathFunctionCount() != null) {
- Exp exp = PathOperand.processPath(basePath, ctx.pathFunction() == null
+ return new Path(basePath, ctx.pathFunction() == null
? null
: (PathFunction) visit(ctx.pathFunction()));
- return exp == null ? null : new PathOperand(exp);
}
return basePath.getBinPart();
}
@@ -493,7 +490,7 @@ public AbstractPart visitListPart(ConditionParser.ListPartContext ctx) {
if (ctx.listRankRange() != null) return ListRankRange.from(ctx.listRankRange());
if (ctx.listRankRangeRelative() != null)
return ListRankRangeRelative.from(ctx.listRankRangeRelative());
- throw new AerospikeDSLException("Unexpected list part: %s".formatted(ctx.getText()));
+ throw new DslParseException("Unexpected list part: %s".formatted(ctx.getText()));
}
@Override
@@ -513,7 +510,7 @@ public AbstractPart visitMapPart(ConditionParser.MapPartContext ctx) {
return MapRankRangeRelative.from(ctx.mapRankRangeRelative());
if (ctx.mapIndexRangeRelative() != null)
return MapIndexRangeRelative.from(ctx.mapIndexRangeRelative());
- throw new AerospikeDSLException("Unexpected map part: %s".formatted(ctx.getText()));
+ throw new DslParseException("Unexpected map part: %s".formatted(ctx.getText()));
}
@Override
diff --git a/src/main/java/com/aerospike/dsl/visitor/FilterConditionVisitor.java b/src/main/java/com/aerospike/dsl/visitor/FilterConditionVisitor.java
deleted file mode 100644
index c11829f..0000000
--- a/src/main/java/com/aerospike/dsl/visitor/FilterConditionVisitor.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.aerospike.dsl.visitor;
-
-import com.aerospike.client.query.Filter;
-import com.aerospike.dsl.ConditionParser;
-import com.aerospike.dsl.exception.AerospikeDSLException;
-import com.aerospike.dsl.model.AbstractPart;
-import com.aerospike.dsl.model.Expr;
-import com.aerospike.dsl.model.SIndexFilter;
-
-import static com.aerospike.dsl.model.Expr.ExprPartsOperation.*;
-import static com.aerospike.dsl.visitor.VisitorUtils.FilterOperationType.*;
-import static com.aerospike.dsl.visitor.VisitorUtils.getFilterOrFail;
-import static com.aerospike.dsl.visitor.VisitorUtils.validateNumericBin;
-
-public class FilterConditionVisitor extends ExpressionConditionVisitor {
-
- @Override
- public AbstractPart visitGreaterThanExpression(ConditionParser.GreaterThanExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- Filter filter = getFilterOrFail(left, right, GT);
- return new Expr(new SIndexFilter(filter));
- }
-
- @Override
- public AbstractPart visitGreaterThanOrEqualExpression(ConditionParser.GreaterThanOrEqualExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- Filter filter = getFilterOrFail(left, right, GTEQ);
- return new Expr(new SIndexFilter(filter));
- }
-
- @Override
- public AbstractPart visitLessThanExpression(ConditionParser.LessThanExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- Filter filter = getFilterOrFail(left, right, LT);
- return new Expr(new SIndexFilter(filter));
- }
-
- @Override
- public AbstractPart visitLessThanOrEqualExpression(ConditionParser.LessThanOrEqualExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- Filter filter = getFilterOrFail(left, right, LTEQ);
- return new Expr(new SIndexFilter(filter));
- }
-
- @Override
- public AbstractPart visitEqualityExpression(ConditionParser.EqualityExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- Filter filter = getFilterOrFail(left, right, EQ);
- return new Expr(new SIndexFilter(filter));
- }
-
- @Override
- public AbstractPart visitInequalityExpression(ConditionParser.InequalityExpressionContext ctx) {
- throw new AerospikeDSLException("The operation is not supported by secondary index filter");
- }
-
- @Override
- public AbstractPart visitAddExpression(ConditionParser.AddExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- validateNumericBin(left, right);
- return new Expr(left, right, ADD);
- }
-
- @Override
- public AbstractPart visitSubExpression(ConditionParser.SubExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- validateNumericBin(left, right);
- return new Expr(left, right, SUB);
- }
-
- @Override
- public AbstractPart visitDivExpression(ConditionParser.DivExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- validateNumericBin(left, right);
- return new Expr(left, right, DIV);
- }
-
- @Override
- public AbstractPart visitMulExpression(ConditionParser.MulExpressionContext ctx) {
- AbstractPart left = visit(ctx.operand(0));
- AbstractPart right = visit(ctx.operand(1));
-
- validateNumericBin(left, right);
- return new Expr(left, right, MUL);
- }
-}
diff --git a/src/main/java/com/aerospike/dsl/visitor/NoApplicableFilterException.java b/src/main/java/com/aerospike/dsl/visitor/NoApplicableFilterException.java
new file mode 100644
index 0000000..4b6813e
--- /dev/null
+++ b/src/main/java/com/aerospike/dsl/visitor/NoApplicableFilterException.java
@@ -0,0 +1,19 @@
+package com.aerospike.dsl.visitor;
+
+import com.aerospike.client.query.Filter;
+
+/**
+ * Indicates that no applicable {@link Filter} could be generated for a given DSL expression. For internal use.
+ *
+ * This exception is typically thrown when attempting to create a Filter for a DSL expression
+ * but the structure or types of the expression do not match any supported filtering patterns
+ * (e.g., comparing Strings using arithmetical operations, using OR-combined expression etc.).
+ * It signifies that while the expression might be valid in a broader context, it cannot be represented with a
+ * secondary index Filter.
+ */
+class NoApplicableFilterException extends RuntimeException {
+
+ NoApplicableFilterException(String description) {
+ super(description);
+ }
+}
diff --git a/src/main/java/com/aerospike/dsl/visitor/VisitorUtils.java b/src/main/java/com/aerospike/dsl/visitor/VisitorUtils.java
index 744416e..a954924 100644
--- a/src/main/java/com/aerospike/dsl/visitor/VisitorUtils.java
+++ b/src/main/java/com/aerospike/dsl/visitor/VisitorUtils.java
@@ -2,61 +2,150 @@
import com.aerospike.client.exp.Exp;
import com.aerospike.client.query.Filter;
+import com.aerospike.client.query.IndexType;
import com.aerospike.dsl.ConditionParser;
-import com.aerospike.dsl.exception.AerospikeDSLException;
-import com.aerospike.dsl.model.AbstractPart;
-import com.aerospike.dsl.model.BinPart;
-import com.aerospike.dsl.model.Expr;
-import com.aerospike.dsl.model.IntOperand;
-import com.aerospike.dsl.model.MetadataOperand;
-import com.aerospike.dsl.model.StringOperand;
+import com.aerospike.dsl.DslParseException;
+import com.aerospike.dsl.Index;
+import com.aerospike.dsl.parts.AbstractPart;
+import com.aerospike.dsl.parts.ExpressionContainer;
+import com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation;
+import com.aerospike.dsl.parts.controlstructure.ExclusiveStructure;
+import com.aerospike.dsl.parts.controlstructure.WhenStructure;
+import com.aerospike.dsl.parts.controlstructure.WithStructure;
+import com.aerospike.dsl.parts.operand.IntOperand;
+import com.aerospike.dsl.parts.operand.MetadataOperand;
+import com.aerospike.dsl.parts.operand.StringOperand;
+import com.aerospike.dsl.parts.operand.WithOperand;
+import com.aerospike.dsl.parts.path.BinPart;
import lombok.experimental.UtilityClass;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.runtime.tree.ParseTree;
-import java.util.Base64;
-import java.util.Objects;
+import java.util.*;
import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
import java.util.function.UnaryOperator;
-import static com.aerospike.dsl.model.Expr.ExprPartsOperation.*;
+import static com.aerospike.dsl.parts.AbstractPart.PartType.BIN_PART;
+import static com.aerospike.dsl.parts.AbstractPart.PartType.EXPRESSION_CONTAINER;
+import static com.aerospike.dsl.parts.AbstractPart.PartType.INT_OPERAND;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.ADD;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.AND;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.DIV;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.MUL;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.OR;
+import static com.aerospike.dsl.parts.ExpressionContainer.ExprPartsOperation.SUB;
import static com.aerospike.dsl.util.ValidationUtils.validateComparableTypes;
-import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.*;
-import static com.aerospike.dsl.visitor.VisitorUtils.FilterOperationType.*;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.ADDEND;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.DIVIDEND;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.DIVISOR;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.MIN;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.MULTIPLICAND;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.MULTIPLIER;
+import static com.aerospike.dsl.visitor.VisitorUtils.ArithmeticTermType.SUBTR;
@UtilityClass
public class VisitorUtils {
- protected enum FilterOperationType {
- GT,
- GTEQ,
- LT,
- LTEQ,
- EQ,
- NOTEQ
+ private final Map expTypeToIndexType = Map.of(
+ Exp.Type.INT, IndexType.NUMERIC,
+ Exp.Type.STRING, IndexType.STRING,
+ Exp.Type.BLOB, IndexType.BLOB
+ );
+
+ /**
+ * Converts an {@link ExprPartsOperation} enum value to its corresponding {@link FilterOperationType}.
+ *
+ * @param exprPartsOperation The {@link ExprPartsOperation} to convert
+ * @return The corresponding {@link FilterOperationType}
+ * @throws NoApplicableFilterException if the {@link ExprPartsOperation} has no matching {@link FilterOperationType}
+ */
+ private static FilterOperationType getFilterOperation(ExprPartsOperation exprPartsOperation) {
+ return switch (exprPartsOperation) {
+ case GT -> FilterOperationType.GT;
+ case GTEQ -> FilterOperationType.GTEQ;
+ case LT -> FilterOperationType.LT;
+ case LTEQ -> FilterOperationType.LTEQ;
+ case EQ -> FilterOperationType.EQ;
+ case NOTEQ -> FilterOperationType.NOTEQ;
+ default -> throw new NoApplicableFilterException("ExprPartsOperation has no matching FilterOperationType");
+ };
}
- protected enum ArithmeticTermType {
- ADDEND,
- SUBTR,
- MIN,
- DIFFERENCE,
- DIVIDEND,
- DIVISOR,
- QUOTIENT,
- MULTIPLICAND,
- MULTIPLIER,
- PRODUCT
+ /**
+ * Gets the appropriate {@link BinaryOperator} for a given {@link ExprPartsOperation}.
+ *
+ * @param exprPartsOperation The {@link ExprPartsOperation} for which to get the binary operator
+ * @return A {@link BinaryOperator} that performs the corresponding operation on two {@link Exp} operands
+ * @throws NoApplicableFilterException if the {@link ExprPartsOperation} has no matching {@link BinaryOperator}
+ */
+ private static BinaryOperator getExpOperator(ExprPartsOperation exprPartsOperation) {
+ return switch (exprPartsOperation) {
+ case ADD -> Exp::add;
+ case SUB -> Exp::sub;
+ case MUL -> Exp::mul;
+ case DIV -> Exp::div;
+ case MOD -> Exp::mod;
+ case INT_XOR -> Exp::intXor;
+ case L_SHIFT -> Exp::lshift;
+ case R_SHIFT -> Exp::rshift;
+ case INT_AND -> Exp::intAnd;
+ case INT_OR -> Exp::intOr;
+ case AND -> Exp::and;
+ case OR -> Exp::or;
+ case EQ -> Exp::eq;
+ case NOTEQ -> Exp::ne;
+ case LT -> Exp::lt;
+ case LTEQ -> Exp::le;
+ case GT -> Exp::gt;
+ case GTEQ -> Exp::ge;
+ default -> throw new NoApplicableFilterException("ExprPartsOperation has no matching BinaryOperator");
+ };
}
- static String extractVariableName(String variableReference) {
+ /**
+ * Gets the appropriate {@link UnaryOperator} for a given {@link ExprPartsOperation}.
+ *
+ * @param exprPartsOperation The {@link ExprPartsOperation} for which to get the unary operator
+ * @return A {@link UnaryOperator} that performs the corresponding operation on a single {@link Exp} operand
+ * @throws NoApplicableFilterException if the {@link ExprPartsOperation} has no matching {@link UnaryOperator}
+ */
+ private static UnaryOperator getUnaryExpOperator(ExprPartsOperation exprPartsOperation) {
+ return switch (exprPartsOperation) {
+ case INT_NOT -> Exp::intNot;
+ case NOT -> Exp::not;
+ default -> throw new NoApplicableFilterException("ExprPartsOperation has no matching UnaryOperator");
+ };
+ }
+
+ /**
+ * Extracts the variable name from a string formatted as "${variableName}".
+ * If it matches this format, it returns the substring between these markers, otherwise it throws an
+ * {@code IllegalArgumentException}.
+ *
+ * @param variableReference The input string
+ * @return The extracted variable name
+ * @throws IllegalArgumentException if the input string does not match the format
+ */
+ static String extractVariableNameOrFail(String variableReference) {
if (variableReference.startsWith("${") && variableReference.endsWith("}")) {
return variableReference.substring(2, variableReference.length() - 1);
}
throw new IllegalArgumentException("Input string is not in the correct format");
-
}
+ /**
+ * The method traverses the parse tree from the given context {@code ctx}
+ * towards the root. At each level, it checks the children for operand contexts.
+ * If an operand context representing an integer, float, string, or boolean
+ * is found, its corresponding {@link Exp.Type} is returned. The search stops
+ * upon finding the first such operand in the upward path.
+ *
+ * @param ctx The current parse tree context to start searching from.
+ * @return The detected implicit {@link Exp.Type} (INT, FLOAT, STRING, or BOOL),
+ * or {@code null} if no such operand is found in the upper tree levels.
+ */
static Exp.Type detectImplicitTypeFromUpperTree(ParseTree ctx) {
// Search for a "leaf" operand child (Int, Float, String and Boolean)
// in the above levels of the current path in the expression tree
@@ -85,25 +174,58 @@ static Exp.Type detectImplicitTypeFromUpperTree(ParseTree ctx) {
return null;
}
- static void logicalSetBinsAsBooleanExpr(Expr left, Expr right) {
+ /**
+ * Sets the logical bin type for both the left and right expression containers
+ * to {@link Exp.Type#BOOL} if they represent a bin part.
+ *
+ * @param left The left {@link ExpressionContainer}
+ * @param right The right {@link ExpressionContainer}
+ */
+ static void logicalSetBinsAsBooleanExpr(ExpressionContainer left, ExpressionContainer right) {
logicalSetBinAsBooleanExpr(left);
logicalSetBinAsBooleanExpr(right);
}
- static void logicalSetBinAsBooleanExpr(Expr expr) {
- if (expr instanceof BinPart) {
+ /**
+ * Sets the logical bin type for a single expression container to {@link Exp.Type#BOOL}
+ * if it represents a bin part.
+ *
+ * @param expr The {@link ExpressionContainer} to potentially update
+ */
+ static void logicalSetBinAsBooleanExpr(ExpressionContainer expr) {
+ if (expr.getPartType() == BIN_PART) {
((BinPart) expr).updateExp(Exp.Type.BOOL);
}
}
+ /**
+ * Determines whether a child parse tree element at a specific index within a list
+ * should be visited during tree traversal.
+ *
+ * @param i The index of the child element
+ * @param size The total number of children in the list context
+ * @param child The parse tree child element at the given index
+ * @return {@code true} if the child should be visited as a list element, {@code false} otherwise
+ */
static boolean shouldVisitListElement(int i, int size, ParseTree child) {
+ //noinspection GrazieInspection
return size > 0 // size is not 0
&& i != 0 // not the first element ('[')
&& i != size - 1 // not the last element (']')
&& !child.getText().equals(","); // not a comma (list elements separator)
}
+ /**
+ * Determines whether a child parse tree element at a specific index within a map
+ * should be visited during tree traversal.
+ *
+ * @param i The index of the child element
+ * @param size The total number of children in the map context
+ * @param child The parse tree child element at the given index
+ * @return {@code true} if the child should be visited as a map element, {@code false} otherwise
+ */
static boolean shouldVisitMapElement(int i, int size, ParseTree child) {
+ //noinspection GrazieInspection
return size > 0 // size is not 0
&& i != 0 // not the first element ('{')
&& i != size - 1 // not the last element ('}')
@@ -111,157 +233,120 @@ static boolean shouldVisitMapElement(int i, int size, ParseTree child) {
&& !child.getText().equals(","); // not a comma (map pairs separator)
}
- // 2 operands Expressions
- static Exp getExpOrFail(AbstractPart left, AbstractPart right, BinaryOperator operator) {
- if (left == null) {
- throw new AerospikeDSLException("Unable to parse left operand");
- }
- if (right == null) {
- throw new AerospikeDSLException("Unable to parse right operand");
- }
-
- if (left.getPartType() == AbstractPart.PartType.BIN_PART) {
- return getExpLeftBinTypeComparison((BinPart) left, right, operator);
- }
- if (right.getPartType() == AbstractPart.PartType.BIN_PART) {
- return getExpRightBinTypeComparison(left, (BinPart) right, operator);
- }
-
- // Handle non Bin operands cases
- Exp leftExp = left.getExp();
- Exp rightExp = right.getExp();
- return operator.apply(leftExp, rightExp);
- }
-
- static Exp getExpLeftBinTypeComparison(BinPart left, AbstractPart right, BinaryOperator operator) {
- String binNameLeft = left.getBinName();
- return switch (right.getPartType()) {
+ /**
+ * Creates an expression for comparing a bin with another operand.
+ *
+ * @param binPart The bin part
+ * @param otherPart The other operand to compare with
+ * @param operator The binary operator to apply
+ * @param binIsLeft Whether the bin is on the left side of the comparison
+ * @return The resulting expression
+ * @throws DslParseException if the operand type is not supported
+ */
+ private static Exp getExpBinComparison(BinPart binPart, AbstractPart otherPart,
+ BinaryOperator operator, boolean binIsLeft) {
+ Exp binExp = Exp.bin(binPart.getBinName(), binPart.getExpType());
+ Exp otherExp = switch (otherPart.getPartType()) {
case INT_OPERAND -> {
- validateComparableTypes(left.getExpType(), Exp.Type.INT);
- yield operator.apply(left.getExp(), right.getExp());
+ validateComparableTypes(binPart.getExpType(), Exp.Type.INT);
+ yield otherPart.getExp();
}
case FLOAT_OPERAND -> {
- validateComparableTypes(left.getExpType(), Exp.Type.FLOAT);
- yield operator.apply(left.getExp(), right.getExp());
+ validateComparableTypes(binPart.getExpType(), Exp.Type.FLOAT);
+ yield otherPart.getExp();
}
case BOOL_OPERAND -> {
- validateComparableTypes(left.getExpType(), Exp.Type.BOOL);
- yield operator.apply(left.getExp(), right.getExp());
- }
- case STRING_OPERAND -> {
- if (left.getExpType() != null &&
- left.getExpType().equals(Exp.Type.BLOB)) {
- // Base64 Blob
- validateComparableTypes(left.getExpType(), Exp.Type.BLOB);
- String base64String = ((StringOperand) right).getValue();
- byte[] value = Base64.getDecoder().decode(base64String);
- yield operator.apply(left.getExp(), Exp.val(value));
- } else {
- // String
- validateComparableTypes(left.getExpType(), Exp.Type.STRING);
- yield operator.apply(left.getExp(), right.getExp());
- }
+ validateComparableTypes(binPart.getExpType(), Exp.Type.BOOL);
+ yield otherPart.getExp();
}
+ case STRING_OPERAND -> handleStringOperandComparison(binPart, (StringOperand) otherPart);
case METADATA_OPERAND -> {
- // No need to validate, types are determined by metadata function
- Exp.Type binType = Exp.Type.valueOf(((MetadataOperand) right).getMetadataType().toString());
- yield operator.apply(
- Exp.bin(binNameLeft, binType),
- right.getExp()
- );
+ // Handle metadata comparison - type determined by metadata function
+ Exp.Type binType = Exp.Type.valueOf(((MetadataOperand) otherPart).getMetadataType().toString());
+ binExp = Exp.bin(binPart.getBinName(), binType);
+ yield otherPart.getExp();
}
- case EXPR, PATH_OPERAND ->
- operator.apply(left.getExp(), right.getExp()); // Can't validate with Expr on one side
- // Left and right are both bin parts
+ case EXPRESSION_CONTAINER, PATH_OPERAND, VARIABLE_OPERAND ->
+ // Can't validate with expression container
+ otherPart.getExp();
case BIN_PART -> {
- // Validate types if possible
- validateComparableTypes(left.getExpType(), right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
+ // Both are bin parts
+ validateComparableTypes(binPart.getExpType(), otherPart.getExpType());
+ yield otherPart.getExp();
}
case LIST_OPERAND -> {
- validateComparableTypes(left.getExpType(), Exp.Type.LIST);
- yield operator.apply(left.getExp(), right.getExp());
+ validateComparableTypes(binPart.getExpType(), Exp.Type.LIST);
+ yield otherPart.getExp();
}
case MAP_OPERAND -> {
- validateComparableTypes(left.getExpType(), Exp.Type.MAP);
- yield operator.apply(left.getExp(), right.getExp());
+ validateComparableTypes(binPart.getExpType(), Exp.Type.MAP);
+ yield otherPart.getExp();
}
- default -> throw new AerospikeDSLException("Operand type not supported: %s".formatted(right.getPartType()));
+ default -> throw new DslParseException("Operand type not supported: %s".formatted(otherPart.getPartType()));
};
- }
- static Exp getExpRightBinTypeComparison(AbstractPart left, BinPart right, BinaryOperator operator) {
- String binNameRight = right.getBinName();
- return switch (left.getPartType()) {
- case INT_OPERAND -> {
- validateComparableTypes(Exp.Type.INT, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- case FLOAT_OPERAND -> {
- validateComparableTypes(Exp.Type.FLOAT, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- case BOOL_OPERAND -> {
- validateComparableTypes(Exp.Type.BOOL, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- case STRING_OPERAND -> {
- if (right.getExpType() != null &&
- right.getExpType().equals(Exp.Type.BLOB)) {
- // Base64 Blob
- validateComparableTypes(Exp.Type.BLOB, right.getExpType());
- String base64String = ((StringOperand) left).getValue();
- byte[] value = Base64.getDecoder().decode(base64String);
- yield operator.apply(Exp.val(value), right.getExp());
- } else {
- // String
- validateComparableTypes(Exp.Type.STRING, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- }
- case METADATA_OPERAND -> {
- // No need to validate, types are determined by metadata function
- Exp.Type binType = Exp.Type.valueOf(((MetadataOperand) left).getMetadataType().toString());
- yield operator.apply(
- left.getExp(),
- Exp.bin(binNameRight, binType)
- );
- }
- case EXPR, PATH_OPERAND ->
- operator.apply(left.getExp(), right.getExp()); // Can't validate with Expr on one side
- // No need for 2 BIN_OPERAND handling since it's covered in the left condition
- case LIST_OPERAND -> {
- validateComparableTypes(Exp.Type.LIST, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- case MAP_OPERAND -> {
- validateComparableTypes(Exp.Type.MAP, right.getExpType());
- yield operator.apply(left.getExp(), right.getExp());
- }
- default -> throw new AerospikeDSLException("Operand type not supported: %s".formatted(left.getPartType()));
- };
+ return binIsLeft ? operator.apply(binExp, otherExp) : operator.apply(otherExp, binExp);
}
- // 1 operand Expressions
- static Exp getExpOrFail(AbstractPart operand, UnaryOperator operator) {
- if (operand == null) {
- throw new AerospikeDSLException("Unable to parse operand");
+ /**
+ * Handles string operand comparison with type validation and blob handling.
+ *
+ * @param binPart The {@link BinPart} involved in the comparison
+ * @param stringOperand The {@link StringOperand} involved in the comparison
+ * @return The {@link Exp} generated from the {@link StringOperand}
+ * @throws DslParseException if type validation fails (e.g., comparing a non-string/blob bin with a String)
+ */
+ private static Exp handleStringOperandComparison(BinPart binPart, StringOperand stringOperand) {
+ boolean isBlobType = binPart.getExpType() != null && binPart.getExpType().equals(Exp.Type.BLOB);
+ if (isBlobType) {
+ // Handle base64 blob comparison
+ validateComparableTypes(binPart.getExpType(), Exp.Type.BLOB);
+ stringOperand.setBlob(true);
+ } else {
+ // Handle regular string comparison
+ validateComparableTypes(binPart.getExpType(), Exp.Type.STRING);
}
+ return stringOperand.getExp();
+ }
- // 1 Operand Expression is always a BIN Operand
- String binName = ((BinPart) operand).getBinName();
+ /**
+ * Creates an expression for comparing a bin on the left with an operand on the right.
+ *
+ * @param left The {@link BinPart} on the left side of the comparison
+ * @param right The {@link AbstractPart} on the right side of the comparison
+ * @param operator The binary operator to apply
+ * @return The resulting {@link Exp} for the comparison
+ * @throws DslParseException if an unsupported operand type is encountered or type validation fails
+ */
+ private static Exp getExpLeftBinTypeComparison(BinPart left, AbstractPart right, BinaryOperator operator) {
+ return getExpBinComparison(left, right, operator, true);
+ }
- // There is only 1 case of a single operand expression (int not), and it always gets an integer
- return operator.apply(Exp.bin(binName, Exp.Type.INT));
+ /**
+ * Creates an expression for comparing an operand on the left with a bin on the right.
+ *
+ * @param left The {@link AbstractPart} on the left side of the comparison
+ * @param right The {@link BinPart} on the right side of the comparison
+ * @param operator The binary operator to apply
+ * @return The resulting {@link Exp} for the comparison
+ * @throws DslParseException if an unsupported operand type is encountered or type validation fails
+ */
+ private static Exp getExpRightBinTypeComparison(AbstractPart left, BinPart right, BinaryOperator operator) {
+ return getExpBinComparison(right, left, operator, false);
}
+ /**
+ * Extracts the value of a specific parameter from a Path Function parameter context.
+ *
+ * @param paramCtx The parse tree context for the Path Function parameter
+ * @param paramName The name of the parameter to extract the value for
+ * @return The value of the specified parameter if found and matches the name, otherwise {@code null}.
+ */
static String getPathFunctionParam(ConditionParser.PathFunctionParamContext paramCtx, String paramName) {
- String paramNameText;
- String paramNameValue;
String paramValue = null;
if (paramCtx.pathFunctionParamName() != null) {
- paramNameText = paramCtx.pathFunctionParamName().getText();
- paramNameValue = paramCtx.pathFunctionParamValue().getText();
+ String paramNameText = paramCtx.pathFunctionParamName().getText();
+ String paramNameValue = paramCtx.pathFunctionParamValue().getText();
if (paramNameText.equalsIgnoreCase(paramName)) {
paramValue = paramNameValue;
}
@@ -269,118 +354,43 @@ static String getPathFunctionParam(ConditionParser.PathFunctionParamContext para
return paramValue;
}
- static String extractTypeFromMethod(String methodName) {
- if (methodName.startsWith("as") && methodName.endsWith("()")) {
- return methodName.substring(2, methodName.length() - 2);
- } else {
- throw new AerospikeDSLException("Invalid method name: %s".formatted(methodName));
- }
- }
-
- static String extractFunctionName(String text) {
- int startParen = text.indexOf('(');
- return (startParen != -1) ? text.substring(0, startParen) : text;
- }
-
- static Integer extractParameter(String text) {
- int startParen = text.indexOf('(');
- int endParen = text.indexOf(')');
-
- if (startParen != -1 && endParen != -1 && endParen > startParen + 1) {
- String numberStr = text.substring(startParen + 1, endParen);
- return Integer.parseInt(numberStr);
- }
- return null;
- }
-
- // 2 operands Filters
- static Filter getFilterOrFail(AbstractPart left, AbstractPart right, FilterOperationType type) {
- if (left == null) {
- throw new AerospikeDSLException("Unable to parse left operand");
- }
- if (right == null) {
- throw new AerospikeDSLException("Unable to parse right operand");
- }
-
- if (left.getPartType() == AbstractPart.PartType.BIN_PART) {
- return getFilter((BinPart) left, right, type);
- }
- if (right.getPartType() == AbstractPart.PartType.BIN_PART) {
- return getFilter((BinPart) right, left, invertType(type));
- }
-
- // Handle non Bin operands cases
- if (left instanceof Expr leftExpr) {
- return getFilterOrFail(leftExpr.getLeft(), leftExpr.getRight(), leftExpr.getOperationType(), right, type);
- }
- if (right instanceof Expr rightExpr) {
- return getFilterOrFail(rightExpr.getLeft(), rightExpr.getRight(), rightExpr.getOperationType(), left, type);
- }
- return null;
- }
-
- // 2 operands Filters
- static Filter getFilterOrFail(AbstractPart exprLeft, AbstractPart exprRight, Expr.ExprPartsOperation operationType,
- AbstractPart right, FilterOperationType type) {
- if (exprLeft == null) {
- throw new AerospikeDSLException("Unable to parse left operand of expression");
- }
- if (exprRight == null) {
- throw new AerospikeDSLException("Unable to parse right operand of expression");
- }
-
- if (exprLeft.getPartType() == AbstractPart.PartType.BIN_PART) { // bin is on the left side
- if (exprRight instanceof IntOperand leftOperand && right instanceof IntOperand rightOperand) {
- validateComparableTypes(exprLeft.getExpType(), Exp.Type.INT);
- return applyFilterOperator(((BinPart) exprLeft).getBinName(), leftOperand, rightOperand,
- operationType, type, getTermType(operationType, true));
- }
- throw new AerospikeDSLException(
- String.format("Operands not supported in secondary index Filter: %s, %s", exprRight, right));
- }
- if (exprRight.getPartType() == AbstractPart.PartType.BIN_PART) { // bin is on the right side
- if (exprLeft instanceof IntOperand leftOperand && right instanceof IntOperand rightOperand) {
- validateComparableTypes(exprRight.getExpType(), Exp.Type.INT);
- return applyFilterOperator(((BinPart) exprRight).getBinName(), leftOperand, rightOperand,
- operationType, type, getTermType(operationType, false));
- }
- throw new AerospikeDSLException(
- String.format("Operands not supported in secondary index Filter: %s, %s", exprRight, right));
- }
-
- // Handle non Bin operands cases
- if (exprLeft instanceof Expr leftExpr) {
- return getFilterOrFail(leftExpr.getLeft(), leftExpr.getRight(), type);
- }
- return null;
- }
-
- static void validateNumericBin(AbstractPart left, AbstractPart right) {
- if (!isNumericBin(left, right)) {
- throw new AerospikeDSLException("The operation is not supported by secondary index filter");
- }
- }
-
- private static boolean isNumericBin(AbstractPart left, AbstractPart right) {
- return (left instanceof BinPart && right instanceof IntOperand)
- || (right instanceof BinPart && left instanceof IntOperand);
- }
-
- private static ArithmeticTermType getTermType(Expr.ExprPartsOperation operationType, boolean isLeftTerm) {
+ /**
+ * Determines the arithmetic term type based on the operation type and whether it is the left or right operand.
+ *
+ * @param operationType The type of the arithmetic operation
+ * @param isLeftTerm {@code true} if the term is the left operand, {@code false} if it's the right
+ * @return The corresponding {@link ArithmeticTermType}
+ * @throws NoApplicableFilterException if the operation type is not supported for determining arithmetic term type
+ */
+ private static ArithmeticTermType getFilterTermType(ExprPartsOperation operationType, boolean isLeftTerm) {
return switch (operationType) {
case ADD -> ADDEND;
case SUB -> isLeftTerm ? SUBTR : MIN;
case DIV -> isLeftTerm ? DIVIDEND : DIVISOR;
case MUL -> isLeftTerm ? MULTIPLICAND : MULTIPLIER;
- default -> throw new UnsupportedOperationException("Not supported: " + operationType);
+ default -> throw new NoApplicableFilterException(
+ "Operation type is not supported to get arithmetic term type: " + operationType);
};
}
- private static Pair getLimitsForDivision(long left, long right, FilterOperationType type,
- ArithmeticTermType termType) {
+ /**
+ * This method determines the possible range of values for a bin that is either the dividend or the divisor
+ * in a division operation, based on the values of the other operand and the filter operation type*
+ *
+ * @param left The value of the left operand
+ * @param right The value of the right operand
+ * @param type The type of the filter operation
+ * @param termType The {@link ArithmeticTermType} of the bin
+ * @return A {@link Pair} representing the lower and upper bounds of the range for the bin.
+ * A {@code null} value in the pair indicates no bound on that side
+ * @throws NoApplicableFilterException if division by zero occurs or the term type is unsupported
+ * @throws DslParseException if undefined division (0/0) occurs
+ */
+ private static Pair getLimitsForDivisionForFilter(long left, long right, FilterOperationType type,
+ ArithmeticTermType termType) {
// Prevent division by zero
if (right == 0) {
- throw new AerospikeDSLException("Cannot divide by zero");
+ throw new NoApplicableFilterException("Cannot divide by zero");
}
return switch (termType) {
@@ -390,13 +400,25 @@ private static Pair getLimitsForDivision(long left, long right, Filt
};
}
- private static Pair LimitsForBinDividend(long left, long right,
- FilterOperationType operationType) {
+ /**
+ * This method determines the possible range of values for a bin when it is the dividend in a division operation,
+ * based on the value of the divisor (right operand) and the filter operation type.
+ *
+ * @param left The value of the dividend (the bin's value)
+ * @param right The value of the divisor
+ * @param operationType The type of the filter operation
+ * @return A {@link Pair} representing the lower and upper bounds of the range for the bin.
+ * A {@code null} value in the pair indicates no bound on that side
+ * @throws DslParseException if undefined division (0/0) occurs or if the operation type is not supported
+ */
+ private static Pair LimitsForBinDividend(
+ long left, long right, FilterOperationType operationType
+ ) {
if (left > 0 && right > 0) {
// both operands are positive
return getLimitsForBinDividendWithLeftNumberPositive(operationType, left, right);
} else if (left == 0 && right == 0) {
- throw new AerospikeDSLException("Undefined division for 0 / 0");
+ throw new DslParseException("Undefined division for 0 / 0");
} else if (left < 0 && right < 0) {
// both operands are negative
return getLimitsForBinDividendWithLeftNumberNegative(operationType, left, right);
@@ -407,14 +429,24 @@ private static Pair LimitsForBinDividend(long left, long right,
// left negative, right positive
return getLimitsForBinDividendWithLeftNumberNegative(operationType, left, right);
} else if (left != 0) {
- throw new AerospikeDSLException("Division by zero is not allowed");
+ throw new DslParseException("Division by zero is not allowed");
} else {
return new Pair<>(null, null);
}
}
- private static Pair getLimitsForBinDividendWithLeftNumberNegative(FilterOperationType operationType,
- long left, long right) {
+ /**
+ * Calculates the range limits for a bin that is the dividend when the left number is negative.
+ *
+ * @param operationType The type of the filter operation
+ * @param left The value of the dividend
+ * @param right The value of the divisor
+ * @return A {@link Pair} representing the lower and upper bounds of the range for the bin
+ * @throws DslParseException if the operation type is not supported for division
+ */
+ private static Pair getLimitsForBinDividendWithLeftNumberNegative(
+ FilterOperationType operationType, long left, long right
+ ) {
return switch (operationType) {
case GT:
yield new Pair<>(Long.MIN_VALUE, left * right - 1);
@@ -425,12 +457,22 @@ private static Pair getLimitsForBinDividendWithLeftNumberNegative(Fi
case LTEQ:
yield new Pair<>(left * right, Long.MAX_VALUE);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
}
- private static Pair getLimitsForBinDividendWithLeftNumberPositive(FilterOperationType operationType,
- long left, long right) {
+ /**
+ * Calculates the range limits for a bin that is the dividend when the left number is positive.
+ *
+ * @param operationType The type of the filter operation
+ * @param left The value of the dividend
+ * @param right The value of the divisor
+ * @return A {@link Pair} representing the lower and upper bounds of the range for the bin
+ * @throws DslParseException if the operation type is not supported for division
+ */
+ private static Pair getLimitsForBinDividendWithLeftNumberPositive(
+ FilterOperationType operationType, long left, long right
+ ) {
return switch (operationType) {
case GT:
yield new Pair<>(left * right + 1, Long.MAX_VALUE);
@@ -441,10 +483,20 @@ private static Pair getLimitsForBinDividendWithLeftNumberPositive(Fi
case LTEQ:
yield new Pair<>(Long.MIN_VALUE, left * right);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
}
+ /**
+ * Calculates the range limits for a bin that is the divisor in a division operation.
+ *
+ * @param left The value of the dividend
+ * @param right The value of the divisor
+ * @param operationType The type of the filter operation
+ * @return A {@link Pair} representing the lower and upper bounds of the range for the bin.
+ * A {@code null} value in the pair indicates no bound on that side
+ * @throws DslParseException if division by zero occurs or if the operation type is not supported
+ */
private static Pair getLimitsForBinDivisor(long left, long right, FilterOperationType operationType) {
if (left > 0 && right > 0) {
// both operands are positive
@@ -456,10 +508,10 @@ private static Pair getLimitsForBinDivisor(long left, long right, Fi
case LT, LTEQ:
yield new Pair<>(null, null);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
} else if (left == 0 && right == 0) {
- throw new AerospikeDSLException("Cannot divide by zero");
+ throw new DslParseException("Cannot divide by zero");
} else if (left < 0 && right < 0) {
// both operands are negative
return switch (operationType) {
@@ -470,7 +522,7 @@ private static Pair getLimitsForBinDivisor(long left, long right, Fi
case LTEQ:
yield new Pair<>(1L, left / right);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
} else if (left > 0 && right < 0) {
// left positive, right negative
@@ -482,7 +534,7 @@ private static Pair getLimitsForBinDivisor(long left, long right, Fi
case LTEQ:
yield new Pair<>(left / right, -1L);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
} else if (right > 0 && left < 0) {
// right positive, left negative
@@ -494,61 +546,259 @@ private static Pair getLimitsForBinDivisor(long left, long right, Fi
case LT, LTEQ:
yield new Pair<>(null, null);
default:
- throw new AerospikeDSLException("OperationType not supported for division: " + operationType);
+ throw new DslParseException("OperationType not supported for division: " + operationType);
};
} else if (left != 0) {
- throw new AerospikeDSLException("Division by zero is not allowed");
+ throw new DslParseException("Division by zero is not allowed");
} else {
return new Pair<>(null, null);
}
}
+ /**
+ * Generates a {@link Filter} for a division operation based on the calculated value range and operation type.
+ *
+ * @param binName The name of the bin to filter on
+ * @param value A {@link Pair} representing the lower and upper bounds of the acceptable range for the bin.
+ * A {@code null} value in the pair indicates no bound on that side
+ * @param type The type of the filter operation
+ * @return A {@link Filter} representing the condition
+ * @throws DslParseException if the operation type is not supported for generating a filter
+ */
private static Filter getFilterForDivOrFail(String binName, Pair value, FilterOperationType type) {
// Based on the operation type, generate the appropriate filter range
return switch (type) {
case GT, GTEQ, LT, LTEQ -> Filter.range(binName, value.a, value.b); // Range from 1 to value - 1
case EQ -> Filter.equal(binName, value.a); // Exact match for equality case
- default -> throw new AerospikeDSLException("OperationType not supported for division: " + type);
+ default -> throw new DslParseException("OperationType not supported for division: " + type);
};
}
+ /**
+ * Creates a Filter based on a bin and an operand.
+ *
+ * @param bin The bin part
+ * @param operand The operand part
+ * @param type The filter operation type
+ * @return The appropriate Filter
+ * @throws NoApplicableFilterException if no appropriate filter can be created
+ */
private static Filter getFilter(BinPart bin, AbstractPart operand, FilterOperationType type) {
+ validateOperands(bin, operand);
String binName = bin.getBinName();
+
return switch (operand.getPartType()) {
case INT_OPERAND -> {
validateComparableTypes(bin.getExpType(), Exp.Type.INT);
yield getFilterForArithmeticOrFail(binName, ((IntOperand) operand).getValue(), type);
-
}
- case STRING_OPERAND -> {
- if (type != EQ) throw new AerospikeDSLException("Operand type not supported");
-
- if (bin.getExpType() != null &&
- bin.getExpType().equals(Exp.Type.BLOB)) {
- // Base64 Blob
- validateComparableTypes(bin.getExpType(), Exp.Type.BLOB);
- String base64String = ((StringOperand) operand).getValue();
- byte[] value = Base64.getDecoder().decode(base64String);
- yield Filter.equal(binName, value);
- } else {
- // String
- validateComparableTypes(bin.getExpType(), Exp.Type.STRING);
- yield Filter.equal(binName, ((StringOperand) operand).getValue());
- }
- }
- default ->
- throw new AerospikeDSLException("Operand type not supported: %s".formatted(operand.getPartType()));
+ case STRING_OPERAND -> handleStringOperand(bin, binName, (StringOperand) operand, type);
+ default -> throw new NoApplicableFilterException(
+ "Operand type not supported: %s".formatted(operand.getPartType()));
};
}
+ /**
+ * This method is used to generate a {@link Filter} when one of the operands is a {@link BinPart}
+ * and the other is a {@link StringOperand}. It currently only supports equality (`EQ`) comparisons.
+ * It handles both regular strings and base64 encoded BLOBs.
+ *
+ * @param bin The {@link BinPart} involved in the filter
+ * @param binName The name of the bin
+ * @param operand The {@link StringOperand} involved in the filter
+ * @param type The type of the filter operation (must be {@link FilterOperationType#EQ})
+ * @return An Aerospike {@link Filter} for the string or blob comparison
+ * @throws NoApplicableFilterException if the filter operation type is not equality
+ * @throws DslParseException if type validation fails or base64 decoding fails
+ */
+ private static Filter handleStringOperand(BinPart bin, String binName, StringOperand operand,
+ FilterOperationType type) {
+ if (type != FilterOperationType.EQ) {
+ throw new NoApplicableFilterException("Only equality comparison is supported for string operands");
+ }
+
+ // Handle BLOB type
+ if (bin.getExpType() != null && bin.getExpType().equals(Exp.Type.BLOB)) {
+ validateComparableTypes(bin.getExpType(), Exp.Type.BLOB);
+ byte[] value = Base64.getDecoder().decode(operand.getValue());
+ return Filter.equal(binName, value);
+ }
+
+ // Handle STRING type
+ validateComparableTypes(bin.getExpType(), Exp.Type.STRING);
+ return Filter.equal(binName, operand.getValue());
+ }
+
+ /**
+ * Creates a Filter based on two operands and a filter operation type.
+ *
+ * @param left The left operand
+ * @param right The right operand
+ * @param type The filter operation type
+ * @return The appropriate Filter, or null if no filter can be created
+ * @throws DslParseException if operands are invalid
+ */
+ private static Filter getFilterOrFail(AbstractPart left, AbstractPart right, FilterOperationType type) {
+ validateOperands(left, right);
+
+ // Handle bin operands
+ if (left.getPartType() == BIN_PART) {
+ return getFilter((BinPart) left, right, type);
+ }
+
+ if (right.getPartType() == BIN_PART) {
+ return getFilter((BinPart) right, left, invertType(type));
+ }
+
+ // Handle expressions
+ if (left.getPartType() == EXPRESSION_CONTAINER) {
+ return handleExpressionOperand((ExpressionContainer) left, right, type);
+ }
+
+ if (right.getPartType() == EXPRESSION_CONTAINER) {
+ return handleExpressionOperand((ExpressionContainer) right, left, type);
+ }
+
+ return null;
+ }
+
+ /**
+ * This method is used when one of the operands is an {@link ExpressionContainer}.
+ * It recursively processes the nested expression to determine if a filter can be generated from it in combination
+ * with the {@code otherOperand} and the overall {@code type} of the filter operation.
+ *
+ * @param expr The {@link ExpressionContainer} operand
+ * @param otherOperand The other operand in the filter condition
+ * @param type The type of the filter operation
+ * @return A {@link Filter} if one can be generated from the nested expression, otherwise {@code null}
+ * @throws DslParseException if operands within the nested expression are null
+ * @throws NoApplicableFilterException if the nested expression structure is not supported for filtering
+ */
+ private static Filter handleExpressionOperand(ExpressionContainer expr, AbstractPart otherOperand,
+ FilterOperationType type) {
+ AbstractPart exprLeft = expr.getLeft();
+ AbstractPart exprRight = expr.getRight();
+ ExprPartsOperation operation = expr.getOperationType();
+
+ validateOperands(exprLeft, exprRight);
+
+ return getFilterFromExpressionOrFail(exprLeft, exprRight, operation, otherOperand, type);
+ }
+
+ /**
+ * Creates a secondary index {@link Filter} based on an expression and an external operand.
+ * The method examines the structure of the nested expression and attempts to generate a {@link Filter}
+ * by combining it with the {@code externalOperand} and the overall {@code type} of the filter operation.
+ * It specifically looks for cases where a bin is involved in an arithmetic expression with an external operand.
+ *
+ * @param exprLeft The left part of an expression
+ * @param exprRight The right part of an expression
+ * @param operationType The operation type of the expression
+ * @param externalOperand The operand outside the expression
+ * @param type The type of the overall filter operation
+ * @return A {@link Filter} if one can be generated, otherwise {@code null}
+ * @throws NoApplicableFilterException if the expression structure is not supported for filtering
+ */
+ private static Filter getFilterFromExpressionOrFail(AbstractPart exprLeft, AbstractPart exprRight,
+ ExprPartsOperation operationType,
+ AbstractPart externalOperand, FilterOperationType type) {
+ // Handle bin on left side
+ if (exprLeft.getPartType() == BIN_PART) {
+ return handleBinArithmeticExpression((BinPart) exprLeft, exprRight, externalOperand,
+ operationType, type, true);
+ }
+
+ // Handle bin on right side
+ if (exprRight.getPartType() == BIN_PART) {
+ return handleBinArithmeticExpression((BinPart) exprRight, exprLeft, externalOperand,
+ operationType, type, false);
+ }
+
+ // Handle nested expressions
+ if (exprLeft.getPartType() == EXPRESSION_CONTAINER) {
+ return getFilterOrFail(exprLeft, exprRight, type);
+ }
+
+ return null;
+ }
+
+ /**
+ * This method is used when a secondary index {@link Filter} is being generated from an arithmetic
+ * expression where one operand is a bin and the other is a literal value. It enforces
+ * that both the literal operand and the external operand (from the overall filter condition)
+ * must be integers for secondary index filtering.
+ * It then calls{@link #applyFilterOperator} to generate the actual filter.
+ *
+ * @param bin The {@link BinPart} involved in the arithmetic expression
+ * @param operand The other operand within the arithmetic expression (expected to be an integer)
+ * @param externalOperand The operand from the overall filter condition (expected to be an integer)
+ * @param operation The type of the arithmetic operation
+ * @param type The type of the overall filter operation
+ * @param binOnLeft {@code true} if the bin is on the left side of the arithmetic operation, {@code false} otherwise
+ * @return A {@link Filter} for the arithmetic condition
+ * @throws NoApplicableFilterException if operands are not integers or if the operation is not supported
+ * @throws DslParseException if type validation fails
+ */
+ private static Filter handleBinArithmeticExpression(BinPart bin, AbstractPart operand,
+ AbstractPart externalOperand,
+ ExprPartsOperation operation,
+ FilterOperationType type, boolean binOnLeft) {
+ // Only support integer arithmetic in filters
+ if (operand.getPartType() != INT_OPERAND || externalOperand.getPartType() != INT_OPERAND) {
+ throw new NoApplicableFilterException(
+ "Only integer operands are supported in arithmetic filter expressions");
+ }
+
+ validateComparableTypes(bin.getExpType(), Exp.Type.INT);
+
+ IntOperand firstOperand = (IntOperand) operand;
+ IntOperand secondOperand = (IntOperand) externalOperand;
+
+ return applyFilterOperator(bin.getBinName(), firstOperand, secondOperand,
+ operation, type, getFilterTermType(operation, binOnLeft));
+ }
+
+ /**
+ * Validates that both left and right operands are not null.
+ * This is a basic validation helper used to ensure that essential parts
+ * of an expression are present before attempting to process them.
+ *
+ * @param left The left {@link AbstractPart}
+ * @param right The right {@link AbstractPart}
+ * @throws DslParseException if either the left or right operand is null
+ */
+ private static void validateOperands(AbstractPart left, AbstractPart right) {
+ if (left == null) {
+ throw new DslParseException("Left operand cannot be null");
+ }
+ if (right == null) {
+ throw new DslParseException("Right operand cannot be null");
+ }
+ }
+
+ /**
+ * This method handles arithmetic operations between two integer operands and converts the result
+ * into an appropriate secondary index {@link Filter} based on the filter operation type.
+ *
+ * @param binName The name of the bin to apply the filter to
+ * @param leftOperand The left {@link IntOperand}
+ * @param rightOperand The right {@link IntOperand}
+ * @param operationType The type of the arithmetic operation
+ * @param type The type of the filter operation
+ * @param termType The {@link ArithmeticTermType} of the bin
+ * @return A secondary index {@link Filter}
+ * @throws NoApplicableFilterException if the operation is not supported by secondary index filters,
+ * division by zero occurs, or the calculated range is invalid
+ * @throws DslParseException if undefined division (0/0) occurs or other issues arise
+ */
private static Filter applyFilterOperator(String binName, IntOperand leftOperand, IntOperand rightOperand,
- Expr.ExprPartsOperation operationType, FilterOperationType type,
+ ExprPartsOperation operationType, FilterOperationType type,
ArithmeticTermType termType) {
long leftValue = leftOperand.getValue();
long rightValue = rightOperand.getValue();
float value;
if (Objects.requireNonNull(operationType) == ADD) {
- value = rightValue - leftValue;
+ value = (float) rightValue - leftValue;
} else if (operationType == SUB) {
value = switch (termType) {
case SUBTR -> rightValue + leftValue;
@@ -559,17 +809,17 @@ private static Filter applyFilterOperator(String binName, IntOperand leftOperand
default -> throw new IllegalStateException("Unexpected term type: " + termType);
};
} else if (operationType == DIV) {
- Pair valueForDiv = getLimitsForDivision(leftValue, rightValue, type, termType);
+ Pair valueForDiv = getLimitsForDivisionForFilter(leftValue, rightValue, type, termType);
if (valueForDiv.a == null
|| valueForDiv.b == null
|| valueForDiv.a > valueForDiv.b
|| (valueForDiv.a == 0 && valueForDiv.b == 0)) {
- throw new AerospikeDSLException("The operation is not supported by secondary index filter");
+ throw new NoApplicableFilterException("The operation is not supported by secondary index filter");
}
return getFilterForDivOrFail(binName, valueForDiv, type);
} else if (operationType == MUL) {
if (leftValue <= 0) {
- if (leftValue == 0) throw new AerospikeDSLException("Cannot divide by zero");
+ if (leftValue == 0) throw new NoApplicableFilterException("Cannot divide by zero");
type = invertType(type);
}
float val = (float) rightValue / leftValue;
@@ -577,10 +827,18 @@ private static Filter applyFilterOperator(String binName, IntOperand leftOperand
} else {
throw new UnsupportedOperationException("Not supported");
}
-
return getFilterForArithmeticOrFail(binName, value, type);
}
+ /**
+ * Generates a {@link Filter} for an arithmetic operation involving a bin and a value.
+ *
+ * @param binName The name of the bin to filter on
+ * @param value The calculated value from the arithmetic operation
+ * @param type The type of the filter operation
+ * @return A {@link Filter} representing the condition
+ * @throws NoApplicableFilterException if the operation type is not supported for secondary index filter
+ */
private static Filter getFilterForArithmeticOrFail(String binName, float value, FilterOperationType type) {
return switch (type) {
// "$.intBin1 > 100" and "100 < $.intBin1" represent the same Filter
@@ -589,10 +847,17 @@ private static Filter getFilterForArithmeticOrFail(String binName, float value,
case LT -> Filter.range(binName, Long.MIN_VALUE, getClosestLongToTheLeft(value));
case LTEQ -> Filter.range(binName, Long.MIN_VALUE, (long) value);
case EQ -> Filter.equal(binName, (long) value);
- default -> throw new AerospikeDSLException("The operation is not supported by secondary index filter");
+ default ->
+ throw new NoApplicableFilterException("The operation is not supported by secondary index filter");
};
}
+ /**
+ * Finds the closest long integer to the left of a given float value.
+ *
+ * @param value The float value
+ * @return The closest long integer to the left
+ */
private static long getClosestLongToTheLeft(float value) {
// Get the largest integer less than or equal to the float
long flooredValue = (long) Math.floor(value);
@@ -601,10 +866,15 @@ private static long getClosestLongToTheLeft(float value) {
if (value == flooredValue) {
return flooredValue - 1;
}
-
return flooredValue;
}
+ /**
+ * Finds the closest long integer to the right of a given float value.
+ *
+ * @param value The float value
+ * @return The closest long integer to the right
+ */
private static long getClosestLongToTheRight(float value) {
// Get the smallest integer greater than or equal to the float
long ceiledValue = (long) Math.ceil(value);
@@ -617,13 +887,442 @@ private static long getClosestLongToTheRight(float value) {
return ceiledValue;
}
- private FilterOperationType invertType(FilterOperationType type) {
+ /**
+ * This method provides the inverse operation for {@link FilterOperationType} comparison types.
+ * For other Filter operation types, it returns the original type.
+ *
+ * @param type Filter operation type to invert
+ * @return The inverted {@link FilterOperationType}
+ */
+ private static FilterOperationType invertType(FilterOperationType type) {
return switch (type) {
- case GT -> LT;
- case GTEQ -> LTEQ;
- case LT -> GT;
- case LTEQ -> GTEQ;
+ case GT -> FilterOperationType.LT;
+ case GTEQ -> FilterOperationType.LTEQ;
+ case LT -> FilterOperationType.GT;
+ case LTEQ -> FilterOperationType.GTEQ;
default -> type;
};
}
+
+ /**
+ * Builds a secondary index {@link Filter} and a filter {@link Exp} for a given {@link ExpressionContainer}.
+ * This is the main entry point for enriching the parsed expression tree with query filters.
+ *
+ * @param expr The {@link ExpressionContainer} representing the expression tree
+ * @param indexes A map of available secondary indexes, keyed by bin name
+ * @return The updated {@link ExpressionContainer} with the generated {@link Filter} and {@link Exp}.
+ * Either of them can be null if there is no suitable filter
+ */
+ public static AbstractPart buildExpr(ExpressionContainer expr, Map> indexes) {
+ Filter secondaryIndexFilter = null;
+ try {
+ secondaryIndexFilter = getSIFilter(expr, indexes);
+ } catch (NoApplicableFilterException ignored) {
+ }
+ expr.setFilter(secondaryIndexFilter);
+
+ Exp exp = getFilterExp(expr);
+ expr.setExp(exp);
+ return expr;
+ }
+
+ /**
+ * Returns the {@link Exp} generated for a given {@link ExpressionContainer}.
+ *
+ * @param expr The input {@link ExpressionContainer}
+ * @return The corresponding {@link Exp}, or {@code null} if a secondary index filter was applied
+ * or if there is no suitable filter
+ */
+ private static Exp getFilterExp(ExpressionContainer expr) {
+ // Skip the expression already used in creating secondary index Filter
+ if (expr.hasSecondaryIndexFilter()) return null;
+
+ return switch (expr.getOperationType()) {
+ case WITH_STRUCTURE -> withStructureToExp(expr);
+ case WHEN_STRUCTURE -> whenStructureToExp(expr);
+ case EXCLUSIVE_STRUCTURE -> exclStructureToExp(expr);
+ default -> processExpression(expr);
+ };
+ }
+
+ /**
+ * Generates filter {@link Exp} for a WITH structure {@link ExpressionContainer}.
+ *
+ * @param expr The {@link ExpressionContainer} representing WITH structure
+ * @return The resulting {@link Exp} expression
+ */
+ private static Exp withStructureToExp(ExpressionContainer expr) {
+ List expressions = new ArrayList<>();
+ WithStructure withOperandsList = (WithStructure) expr.getLeft(); // extract unary Expr operand
+ List operands = withOperandsList.getOperands();
+ for (WithOperand withOperand : operands) {
+ if (!withOperand.isLastPart()) {
+ expressions.add(Exp.def(withOperand.getString(), getExp(withOperand.getPart())));
+ } else {
+ // the last expression is the action (described after "do")
+ expressions.add(getExp(withOperand.getPart()));
+ }
+ }
+ return Exp.let(expressions.toArray(new Exp[0]));
+ }
+
+ /**
+ * Generates filter {@link Exp} for a WHEN structure {@link ExpressionContainer}.
+ *
+ * @param expr The {@link ExpressionContainer} representing WHEN structure
+ * @return The resulting {@link Exp} expression
+ */
+ private static Exp whenStructureToExp(ExpressionContainer expr) {
+ List expressions = new ArrayList<>();
+ WhenStructure whenOperandsList = (WhenStructure) expr.getLeft(); // extract unary Expr operand
+ List operands = whenOperandsList.getOperands();
+ for (AbstractPart part : operands) {
+ expressions.add(getExp(part));
+ }
+ return Exp.cond(expressions.toArray(new Exp[0]));
+ }
+
+ /**
+ * Generates filter {@link Exp} for an EXCLUSIVE structure {@link ExpressionContainer}.
+ *
+ * @param expr The {@link ExpressionContainer} representing EXCLUSIVE structure
+ * @return The resulting {@link Exp} expression
+ */
+ private static Exp exclStructureToExp(ExpressionContainer expr) {
+ List expressions = new ArrayList<>();
+ ExclusiveStructure whenOperandsList = (ExclusiveStructure) expr.getLeft(); // extract unary Expr operand
+ List operands = whenOperandsList.getOperands();
+ for (ExpressionContainer part : operands) {
+ expressions.add(getExp(part));
+ }
+ return Exp.exclusive(expressions.toArray(new Exp[0]));
+ }
+
+ /**
+ * Processes an {@link ExpressionContainer} to generate the corresponding Exp.
+ *
+ * @param expr The expression to process
+ * @return The processed Exp
+ * @throws DslParseException if left or right operands are null in a binary expression
+ */
+ private static Exp processExpression(ExpressionContainer expr) {
+ // For unary expressions
+ if (expr.isUnary()) {
+ Exp operandExp = processOperand(expr.getLeft());
+ if (operandExp == null) return null;
+
+ UnaryOperator operator = getUnaryExpOperator(expr.getOperationType());
+ return operator.apply(operandExp);
+ }
+
+ // For binary expressions
+ AbstractPart left = expr.getLeft();
+ AbstractPart right = expr.getRight();
+ if (left == null) {
+ throw new DslParseException("Unable to parse left operand");
+ }
+ if (right == null) {
+ throw new DslParseException("Unable to parse right operand");
+ }
+
+ // Process operands
+ Exp leftExp = processOperand(left);
+ Exp rightExp = processOperand(right);
+
+ // Special handling for BIN_PART
+ if (left.getPartType() == BIN_PART) {
+ return getExpLeftBinTypeComparison((BinPart) left, right, getExpOperator(expr.getOperationType()));
+ } else if (right.getPartType() == BIN_PART) {
+ return getExpRightBinTypeComparison(left, (BinPart) right, getExpOperator(expr.getOperationType()));
+ }
+
+ // Special handling for AND operation
+ if (expr.getOperationType() == AND) {
+ if (leftExp == null) return rightExp;
+ if (rightExp == null) return leftExp;
+ }
+
+ // Apply binary operator
+ BinaryOperator operator = getExpOperator(expr.getOperationType());
+ return operator.apply(leftExp, rightExp);
+ }
+
+ /**
+ * Processes an expression operand to generate its corresponding Aerospike {@link Exp}.
+ * If the operand is an {@link ExpressionContainer}, it recursively calls {@link #getFilterExp(ExpressionContainer)}
+ * to get the nested expression's {@link Exp}. Otherwise, it retrieves the {@link Exp} from the part itself.
+ * The generated {@link Exp} is set back on the {@link AbstractPart}.
+ *
+ * @param part The operand to process
+ * @return The processed Exp, or {@code null} if the part is null or represents
+ * an expression container that resulted in a null Exp
+ */
+ private static Exp processOperand(AbstractPart part) {
+ if (part == null) return null;
+
+ Exp exp;
+ if (part.getPartType() == EXPRESSION_CONTAINER) {
+ exp = getFilterExp((ExpressionContainer) part);
+ } else {
+ exp = part.getExp();
+ }
+ part.setExp(exp);
+ return exp;
+ }
+
+ /**
+ * This method that retrieves the {@link Exp} associated with an {@link AbstractPart}.
+ * If the part is an {@link ExpressionContainer}, it calls {@link #getFilterExp(ExpressionContainer)}
+ * to get the nested expression's {@link Exp}. Otherwise, it returns the {@link Exp} stored
+ * directly in the {@link AbstractPart}.
+ *
+ * @param part The {@link AbstractPart} for which to get the {@link Exp}
+ * @return The corresponding {@link Exp} or {@code null}
+ */
+ private static Exp getExp(AbstractPart part) {
+ if (part.getPartType() == EXPRESSION_CONTAINER) {
+ return getFilterExp((ExpressionContainer) part);
+ }
+ return part.getExp();
+ }
+
+ /**
+ * Attempts to generate a secondary index {@link Filter} for a given {@link ExpressionContainer}.
+ * If the expression is not an OR operation (which is not supported
+ * for secondary index filters), the method attempts to find the most suitable
+ * expression within the tree to apply a filter based on index availability and cardinality.
+ *
+ * @param expr The {@link ExpressionContainer} representing the expression tree
+ * @param indexes A map of available secondary indexes, keyed by bin name
+ * @return A secondary index {@link Filter}, or {@code null} if no applicable filter can be generated
+ * @throws NoApplicableFilterException if the expression operation type is not supported
+ */
+ private static Filter getSIFilter(ExpressionContainer expr, Map> indexes) {
+ // If it is an OR query
+ if (expr.getOperationType() == OR) return null;
+
+ ExpressionContainer chosenExpr = chooseExprForFilter(expr, indexes);
+ if (chosenExpr == null) return null;
+
+ return getFilterOrFail(
+ chosenExpr.getLeft(),
+ chosenExpr.getRight(),
+ getFilterOperation(chosenExpr.getOperationType())
+ );
+ }
+
+ /**
+ * Chooses the most suitable {@link ExpressionContainer} within a tree to apply a secondary index filter.
+ * Identifies all potential expressions within the tree that could
+ * utilize a secondary index. Selects the expression associated with the secondary index
+ * having the largest cardinality (highest ratio of unique
+ * bin values). If multiple expressions have the same largest cardinality, it
+ * chooses alphabetically based on the bin name. The chosen expression is marked
+ * as having a secondary index filter applied.
+ *
+ * @param exprContainer The root {@link ExpressionContainer} of the expression tree
+ * @param indexes A map of available secondary indexes, keyed by bin name
+ * @return The chosen {@link ExpressionContainer} for secondary index filtering,
+ * or {@code null} if no suitable expression is found
+ */
+ private static ExpressionContainer chooseExprForFilter(ExpressionContainer exprContainer,
+ Map> indexes) {
+ if (indexes == null || indexes.isEmpty()) return null;
+
+ Map> exprsPerCardinality =
+ getExpressionsPerCardinality(exprContainer, indexes);
+
+ // Find the entry with the largest key (cardinality)
+ Map> largestCardinalityMap = exprsPerCardinality.entrySet().stream()
+ .max(Map.Entry.comparingByKey())
+ .map(entry -> Map.of(entry.getKey(), entry.getValue()))
+ .orElse(Collections.emptyMap());
+
+ List largestCardinalityExprs;
+ if (largestCardinalityMap.isEmpty()) return null;
+ largestCardinalityExprs = largestCardinalityMap.values().iterator().next();
+
+ ExpressionContainer chosenExpr;
+ if (largestCardinalityExprs.size() > 1) {
+ // Choosing alphabetically from a number of expressions
+ chosenExpr = largestCardinalityExprs.stream()
+ .min(Comparator.comparing(expr -> getBinPart(expr, 1).getBinName()))
+ .orElse(null);
+ chosenExpr.hasSecondaryIndexFilter(true);
+ return chosenExpr;
+ }
+
+ // There is only one expression with the largest cardinality
+ chosenExpr = largestCardinalityExprs.get(0);
+ chosenExpr.hasSecondaryIndexFilter(true);
+ return chosenExpr;
+ }
+
+ /**
+ * Collects all {@link ExpressionContainer}s within an expression tree that
+ * correspond to a bin with a secondary index, grouped by the index's cardinality.
+ *
+ * @param exprContainer The root {@link ExpressionContainer} of the expression tree
+ * @param indexes A map of available secondary indexes, keyed by bin name
+ * @return A map where keys are secondary index cardinalities (bin values ratio)
+ * and values are lists of {@link ExpressionContainer}s associated with bins
+ * having that cardinality
+ */
+ private static Map> getExpressionsPerCardinality(
+ ExpressionContainer exprContainer, Map> indexes
+ ) {
+ Map> exprsPerCardinality = new HashMap<>();
+ final BinPart[] binPartPrev = {null};
+ Consumer exprsPerCardinalityCollector = part -> {
+ if (part.getPartType() == EXPRESSION_CONTAINER) {
+ ExpressionContainer expr = (ExpressionContainer) part;
+ BinPart binPart = getBinPart(expr, 2);
+
+ if (binPart == null) return; // no bin found
+ if (!binPart.equals(binPartPrev[0])) {
+ binPartPrev[0] = binPart;
+ } else {
+ return; // the same bin
+ }
+
+ updateExpressionsPerCardinality(exprsPerCardinality, expr, binPart, indexes);
+ }
+ };
+ traverseTree(exprContainer, exprsPerCardinalityCollector, null);
+ return exprsPerCardinality;
+ }
+
+ /**
+ * Updates a map of expression containers grouped by the cardinality of the indexes associated with an
+ * expression container's bin part.
+ * This method iterates through the indexes related to the provided {@code binPart}.
+ * For each index that matches the expression type of the {@code binPart}, it adds the given {@code expr}
+ * to the {@code exprsPerCardinality} map.
+ *
+ * @param exprsPerCardinality A map where keys are integer ratios (representing index cardinality)
+ * and values are lists of {@link ExpressionContainer} objects.
+ * The map is updated by this method
+ * @param expr The {@link ExpressionContainer} to be added to the appropriate list
+ * within {@code exprsPerCardinality}
+ * @param binPart The {@link BinPart} associated with the expression, used to find
+ * relevant indexes and determine the expression type
+ * @param indexes A map where keys are bin names and values are lists of
+ * {@link Index} objects associated with that bin
+ */
+ private static void updateExpressionsPerCardinality(Map> exprsPerCardinality,
+ ExpressionContainer expr, BinPart binPart,
+ Map> indexes) {
+ List indexesByBin = indexes.get(binPart.getBinName());
+ if (indexesByBin == null || indexesByBin.isEmpty()) return;
+
+ for (Index idx : indexesByBin) {
+ // Iterate over all indexes for the same bin
+ if (expTypeToIndexType.get(binPart.getExpType()) == idx.getIndexType()) {
+ List exprsList = exprsPerCardinality.get(idx.getBinValuesRatio());
+ if (exprsList != null) {
+ exprsList.add(expr);
+ } else {
+ exprsList = new ArrayList<>();
+ exprsList.add(expr);
+ }
+ exprsPerCardinality.put(idx.getBinValuesRatio(), exprsList);
+ }
+ }
+ }
+
+ /**
+ * The method traverses the expression tree starting from the given {@link ExpressionContainer},
+ * searching for a {@link BinPart}. It limits the search depth and stops
+ * traversing a branch if a logical expression (AND / OR) is found.
+ *
+ * @param expr The {@link ExpressionContainer} to start searching from
+ * @param depth The maximum depth to traverse
+ * @return The first {@link BinPart} found within the specified depth, or {@code null} if none is found
+ */
+ private static BinPart getBinPart(ExpressionContainer expr, int depth) {
+ final BinPart[] singleBinPartArray = {null};
+ Consumer binPartRetriever = part -> {
+ if (part.getPartType() == BIN_PART) {
+ singleBinPartArray[0] = (BinPart) part;
+ }
+ };
+ Predicate stopOnLogicalExpr = part -> {
+ if (part.getPartType() == EXPRESSION_CONTAINER) {
+ ExpressionContainer logicalExpr = (ExpressionContainer) part;
+ return logicalExpr.getOperationType() == AND || logicalExpr.getOperationType() == OR;
+ }
+ return false;
+ };
+
+ traverseTree(expr, binPartRetriever, depth, stopOnLogicalExpr);
+ return singleBinPartArray[0];
+ }
+
+ /**
+ * Traverses the AbstractPart nodes tree and applies the visitor function to each node.
+ * Uses a pre-order traversal (top-down, root-left-right).
+ * The visitor function can be used to modify the node's state or to extract information.
+ *
+ * @param part The current node being visited (start with the root)
+ * @param visitor The function to apply to each AbstractPart node
+ * @param stopCondition The condition that causes stop of traversing
+ */
+ public static void traverseTree(AbstractPart part, Consumer visitor,
+ Predicate stopCondition) {
+ traverseTree(part, visitor, Integer.MAX_VALUE, stopCondition);
+ }
+
+ /**
+ * Traverses the AbstractPart nodes tree and applies the visitor function to each node with limited depth.
+ * Uses a pre-order traversal (root-left-right).
+ * The visitor function can be used to modify the node's state or to extract information.
+ *
+ * @param part The current node being visited (start with the root)
+ * @param visitor The function to apply to each AbstractPart node
+ * @param depth The depth to limit traversing at
+ */
+ public static void traverseTree(AbstractPart part, Consumer visitor, int depth,
+ Predicate stopCondition) {
+ if (part == null) return;
+
+ // Stop if the depth limit is reached
+ if (depth < 0) {
+ return;
+ }
+
+ // Stop traversing this branch if the stop condition is met
+ if (stopCondition != null && stopCondition.test(part)) {
+ return;
+ }
+
+ visitor.accept(part);
+
+ if (part.getPartType() == EXPRESSION_CONTAINER && depth > 0) {
+ ExpressionContainer container = (ExpressionContainer) part;
+ traverseTree(container.getLeft(), visitor, depth - 1, stopCondition);
+ traverseTree(container.getRight(), visitor, depth - 1, stopCondition);
+ }
+ }
+
+ protected enum FilterOperationType {
+ GT,
+ GTEQ,
+ LT,
+ LTEQ,
+ EQ,
+ NOTEQ
+ }
+
+ protected enum ArithmeticTermType {
+ ADDEND,
+ SUBTR,
+ MIN,
+ DIFFERENCE,
+ DIVIDEND,
+ DIVISOR,
+ QUOTIENT,
+ MULTIPLICAND,
+ MULTIPLIER,
+ PRODUCT
+ }
}
diff --git a/src/test/java/com/aerospike/dsl/expression/ArithmeticExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/ArithmeticExpressionsTests.java
index 7876e58..ec13080 100644
--- a/src/test/java/com/aerospike/dsl/expression/ArithmeticExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/ArithmeticExpressionsTests.java
@@ -1,124 +1,124 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class ArithmeticExpressionsTests {
@Test
void add() {
- parseExpressionAndCompare("($.apples + $.bananas) > 10",
+ parseExpAndCompare("($.apples + $.bananas) > 10",
Exp.gt(Exp.add(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples + 5) > 10",
+ parseExpAndCompare("($.apples + 5) > 10",
Exp.gt(Exp.add(Exp.intBin("apples"), Exp.val(5)), Exp.val(10)));
- parseExpressionAndCompare("(5 + $.bananas) > 10",
+ parseExpAndCompare("(5 + $.bananas) > 10",
Exp.gt(Exp.add(Exp.val(5), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("(5.2 + $.bananas) > 10.2",
+ parseExpAndCompare("(5.2 + $.bananas) > 10.2",
Exp.gt(Exp.add(Exp.val(5.2), Exp.floatBin("bananas")), Exp.val(10.2)));
}
@Test
void sub() {
- parseExpressionAndCompare("($.apples - $.bananas) == 10",
+ parseExpAndCompare("($.apples - $.bananas) == 10",
Exp.eq(Exp.sub(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples - 5) == 10",
+ parseExpAndCompare("($.apples - 5) == 10",
Exp.eq(Exp.sub(Exp.intBin("apples"), Exp.val(5)), Exp.val(10)));
- parseExpressionAndCompare("(15 - $.bananas) == 10",
+ parseExpAndCompare("(15 - $.bananas) == 10",
Exp.eq(Exp.sub(Exp.val(15), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void mul() {
- parseExpressionAndCompare("($.apples * $.bananas) != 10",
+ parseExpAndCompare("($.apples * $.bananas) != 10",
Exp.ne(Exp.mul(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples * 7) != 10",
+ parseExpAndCompare("($.apples * 7) != 10",
Exp.ne(Exp.mul(Exp.intBin("apples"), Exp.val(7)), Exp.val(10)));
- parseExpressionAndCompare("(3 * $.bananas) != 10",
+ parseExpAndCompare("(3 * $.bananas) != 10",
Exp.ne(Exp.mul(Exp.val(3), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void div() {
- parseExpressionAndCompare("($.apples / $.bananas) <= 10",
+ parseExpAndCompare("($.apples / $.bananas) <= 10",
Exp.le(Exp.div(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples / 5) <= 10",
+ parseExpAndCompare("($.apples / 5) <= 10",
Exp.le(Exp.div(Exp.intBin("apples"), Exp.val(5)), Exp.val(10)));
- parseExpressionAndCompare("(33 / $.bananas) <= 10",
+ parseExpAndCompare("(33 / $.bananas) <= 10",
Exp.le(Exp.div(Exp.val(33), Exp.intBin("bananas")), Exp.val(10)));
// Exp should be constructed and equal and therefore the test is passing
// but when actually triggered server will throw divide by zero exception
- parseExpressionAndCompare("($.apples / 0) <= 10",
+ parseExpAndCompare("($.apples / 0) <= 10",
Exp.le(Exp.div(Exp.intBin("apples"), Exp.val(0)), Exp.val(10)));
}
@Test
void mod() {
- parseExpressionAndCompare("($.apples % $.bananas) != 10",
+ parseExpAndCompare("($.apples % $.bananas) != 10",
Exp.ne(Exp.mod(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples % 7) != 10",
+ parseExpAndCompare("($.apples % 7) != 10",
Exp.ne(Exp.mod(Exp.intBin("apples"), Exp.val(7)), Exp.val(10)));
- parseExpressionAndCompare("(3 % $.bananas) != 10",
+ parseExpAndCompare("(3 % $.bananas) != 10",
Exp.ne(Exp.mod(Exp.val(3), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void intAnd() {
- parseExpressionAndCompare("($.apples & $.bananas) != 10",
- Exp.ne(Exp.intAnd(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples & 7) != 10",
+// parseExpAndCompare("($.apples & $.bananas) != 10",
+// Exp.ne(Exp.intAnd(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
+ parseExpAndCompare("($.apples & 7) != 10",
Exp.ne(Exp.intAnd(Exp.intBin("apples"), Exp.val(7)), Exp.val(10)));
- parseExpressionAndCompare("(3 & $.bananas) != 10",
+ parseExpAndCompare("(3 & $.bananas) != 10",
Exp.ne(Exp.intAnd(Exp.val(3), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void intOr() {
- parseExpressionAndCompare("($.apples | $.bananas) != 10",
+ parseExpAndCompare("($.apples | $.bananas) != 10",
Exp.ne(Exp.intOr(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples | 7) != 10",
+ parseExpAndCompare("($.apples | 7) != 10",
Exp.ne(Exp.intOr(Exp.intBin("apples"), Exp.val(7)), Exp.val(10)));
- parseExpressionAndCompare("(3 | $.bananas) != 10",
+ parseExpAndCompare("(3 | $.bananas) != 10",
Exp.ne(Exp.intOr(Exp.val(3), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void intXor() {
- parseExpressionAndCompare("($.apples ^ $.bananas) != 10",
+ parseExpAndCompare("($.apples ^ $.bananas) != 10",
Exp.ne(Exp.intXor(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(10)));
- parseExpressionAndCompare("($.apples ^ 7) != 10",
+ parseExpAndCompare("($.apples ^ 7) != 10",
Exp.ne(Exp.intXor(Exp.intBin("apples"), Exp.val(7)), Exp.val(10)));
- parseExpressionAndCompare("(3 ^ $.bananas) != 10",
+ parseExpAndCompare("(3 ^ $.bananas) != 10",
Exp.ne(Exp.intXor(Exp.val(3), Exp.intBin("bananas")), Exp.val(10)));
}
@Test
void intNot() {
- parseExpressionAndCompare("(~$.apples) != 10",
+ parseExpAndCompare("(~$.apples) != 10",
Exp.ne(Exp.intNot(Exp.intBin("apples")), Exp.val(10)));
}
@Test
void intLShift() {
- parseExpressionAndCompare("$.visits << 1",
+ parseExpAndCompare("$.visits << 1",
Exp.lshift(Exp.intBin("visits"), Exp.val(1)));
}
@Test
void intRShift() {
- parseExpressionAndCompare("(($.flags >> 6) & 1) == 1",
+ parseExpAndCompare("(($.flags >> 6) & 1) == 1",
Exp.eq(Exp.intAnd(Exp.rshift(Exp.intBin("flags"), Exp.val(6)), Exp.val(1)), Exp.val(1)));
}
@Test
void negativeArithmetic() {
- assertThatThrownBy(() -> parseExpression("($.apples.get(type: STRING) + 5) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("($.apples.get(type: STRING) + 5) > 10"))
+ .isInstanceOf(DslParseException.class)
.hasMessageContaining("Cannot compare STRING to INT");
// TODO: should throw an exception (cannot use arithmetic operations on Strings)
diff --git a/src/test/java/com/aerospike/dsl/expression/BinExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/BinExpressionsTests.java
index eb0d85a..1342b8b 100644
--- a/src/test/java/com/aerospike/dsl/expression/BinExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/BinExpressionsTests.java
@@ -1,65 +1,65 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class BinExpressionsTests {
@Test
void binGT() {
- parseExpressionAndCompare("$.intBin1 > 100", Exp.gt(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.stringBin1 > 'text'", Exp.gt(Exp.stringBin("stringBin1"), Exp.val("text")));
- parseExpressionAndCompare("$.stringBin1 > \"text\"", Exp.gt(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.intBin1 > 100", Exp.gt(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.stringBin1 > 'text'", Exp.gt(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.stringBin1 > \"text\"", Exp.gt(Exp.stringBin("stringBin1"), Exp.val("text")));
- parseExpressionAndCompare("100 < $.intBin1", Exp.lt(Exp.val(100), Exp.intBin("intBin1")));
- parseExpressionAndCompare("'text' < $.stringBin1", Exp.lt(Exp.val("text"), Exp.stringBin("stringBin1")));
- parseExpressionAndCompare("\"text\" < $.stringBin1", Exp.lt(Exp.val("text"), Exp.stringBin("stringBin1")));
+ parseExpAndCompare("100 < $.intBin1", Exp.lt(Exp.val(100), Exp.intBin("intBin1")));
+ parseExpAndCompare("'text' < $.stringBin1", Exp.lt(Exp.val("text"), Exp.stringBin("stringBin1")));
+ parseExpAndCompare("\"text\" < $.stringBin1", Exp.lt(Exp.val("text"), Exp.stringBin("stringBin1")));
}
@Test
void binGE() {
- parseExpressionAndCompare("$.intBin1 >= 100", Exp.ge(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.stringBin1 >= 'text'", Exp.ge(Exp.stringBin("stringBin1"), Exp.val("text")));
- parseExpressionAndCompare("$.stringBin1 >= \"text\"", Exp.ge(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.intBin1 >= 100", Exp.ge(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.stringBin1 >= 'text'", Exp.ge(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.stringBin1 >= \"text\"", Exp.ge(Exp.stringBin("stringBin1"), Exp.val("text")));
}
@Test
void binLT() {
- parseExpressionAndCompare("$.intBin1 < 100", Exp.lt(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.stringBin1 < 'text'", Exp.lt(Exp.stringBin("stringBin1"), Exp.val("text")));
- parseExpressionAndCompare("$.stringBin1 < \"text\"", Exp.lt(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.intBin1 < 100", Exp.lt(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.stringBin1 < 'text'", Exp.lt(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.stringBin1 < \"text\"", Exp.lt(Exp.stringBin("stringBin1"), Exp.val("text")));
}
@Test
void binLE() {
- parseExpressionAndCompare("$.intBin1 <= 100", Exp.le(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.stringBin1 <= 'text'", Exp.le(Exp.stringBin("stringBin1"), Exp.val("text")));
- parseExpressionAndCompare("$.stringBin1 <= \"text\"", Exp.le(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.intBin1 <= 100", Exp.le(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.stringBin1 <= 'text'", Exp.le(Exp.stringBin("stringBin1"), Exp.val("text")));
+ parseExpAndCompare("$.stringBin1 <= \"text\"", Exp.le(Exp.stringBin("stringBin1"), Exp.val("text")));
}
@Test
void binEquals() {
- parseExpressionAndCompare("$.intBin1 == 100", Exp.eq(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.strBin == \"yes\"", Exp.eq(Exp.stringBin("strBin"), Exp.val("yes")));
- parseExpressionAndCompare("$.strBin == 'yes'", Exp.eq(Exp.stringBin("strBin"), Exp.val("yes")));
+ parseExpAndCompare("$.intBin1 == 100", Exp.eq(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.strBin == \"yes\"", Exp.eq(Exp.stringBin("strBin"), Exp.val("yes")));
+ parseExpAndCompare("$.strBin == 'yes'", Exp.eq(Exp.stringBin("strBin"), Exp.val("yes")));
}
@Test
void binNotEquals() {
- parseExpressionAndCompare("$.intBin1 != 100", Exp.ne(Exp.intBin("intBin1"), Exp.val(100)));
- parseExpressionAndCompare("$.strBin != \"yes\"", Exp.ne(Exp.stringBin("strBin"), Exp.val("yes")));
- parseExpressionAndCompare("$.strBin != 'yes'", Exp.ne(Exp.stringBin("strBin"), Exp.val("yes")));
+ parseExpAndCompare("$.intBin1 != 100", Exp.ne(Exp.intBin("intBin1"), Exp.val(100)));
+ parseExpAndCompare("$.strBin != \"yes\"", Exp.ne(Exp.stringBin("strBin"), Exp.val("yes")));
+ parseExpAndCompare("$.strBin != 'yes'", Exp.ne(Exp.stringBin("strBin"), Exp.val("yes")));
}
@Test
void negativeStringBinEquals() {
- assertThatThrownBy(() -> parseExpression("$.strBin == yes"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("$.strBin == yes"))
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse right operand");
}
diff --git a/src/test/java/com/aerospike/dsl/expression/CastingTests.java b/src/test/java/com/aerospike/dsl/expression/CastingTests.java
index c398386..398664e 100644
--- a/src/test/java/com/aerospike/dsl/expression/CastingTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/CastingTests.java
@@ -1,11 +1,11 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class CastingTests {
@@ -14,20 +14,20 @@ public class CastingTests {
void floatToIntComparison() {
Exp expectedExp = Exp.gt(Exp.intBin("intBin1"), Exp.intBin("floatBin1"));
// Int is default
- parseExpressionAndCompare("$.intBin1 > $.floatBin1.asInt()", expectedExp);
- parseExpressionAndCompare("$.intBin1.get(type: INT) > $.floatBin1.asInt()", expectedExp);
+ parseExpAndCompare("$.intBin1 > $.floatBin1.asInt()", expectedExp);
+ parseExpAndCompare("$.intBin1.get(type: INT) > $.floatBin1.asInt()", expectedExp);
}
@Test
void intToFloatComparison() {
- parseExpressionAndCompare("$.intBin1.get(type: INT) > $.intBin2.asFloat()",
+ parseExpAndCompare("$.intBin1.get(type: INT) > $.intBin2.asFloat()",
Exp.gt(Exp.intBin("intBin1"), Exp.floatBin("intBin2")));
}
@Test
void negativeInvalidTypesComparison() {
- assertThatThrownBy(() -> parseExpression("$.stringBin1.get(type: STRING) > $.intBin2.asFloat()"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("$.stringBin1.get(type: STRING) > $.intBin2.asFloat()"))
+ .isInstanceOf(DslParseException.class)
.hasMessageContaining("Cannot compare STRING to FLOAT");
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/ControlStructuresTests.java b/src/test/java/com/aerospike/dsl/expression/ControlStructuresTests.java
index 14b7c94..5f89e1b 100644
--- a/src/test/java/com/aerospike/dsl/expression/ControlStructuresTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/ControlStructuresTests.java
@@ -3,7 +3,7 @@
import com.aerospike.client.exp.Exp;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
public class ControlStructuresTests {
@@ -17,10 +17,10 @@ void whenWithASingleDeclaration() {
Exp.val("other")
);
- parseExpressionAndCompare("when ($.who == 1 => \"bob\", default => \"other\")",
+ parseExpAndCompare("when ($.who == 1 => \"bob\", default => \"other\")",
expected);
// different spacing style
- parseExpressionAndCompare("when($.who == 1 => \"bob\", default => \"other\")",
+ parseExpAndCompare("when($.who == 1 => \"bob\", default => \"other\")",
expected);
}
@@ -40,7 +40,7 @@ void whenUsingTheResult() {
// Implicit detect as String
//translateAndCompare("$.stringBin1 == (when ($.who == 1 => \"bob\", default => \"other\"))",
// expected);
- parseExpressionAndCompare("$.stringBin1.get(type: STRING) == (when ($.who == 1 => \"bob\", default => \"other\"))",
+ parseExpAndCompare("$.stringBin1.get(type: STRING) == (when ($.who == 1 => \"bob\", default => \"other\"))",
expected);
}
@@ -58,7 +58,7 @@ void whenWithMultipleDeclarations() {
Exp.val("other")
);
- parseExpressionAndCompare("when ($.who == 1 => \"bob\", $.who == 2 => \"fred\", default => \"other\")",
+ parseExpAndCompare("when ($.who == 1 => \"bob\", $.who == 2 => \"fred\", default => \"other\")",
expected);
}
@@ -74,10 +74,10 @@ void withMultipleVariablesDefinitionAndUsage() {
Exp.add(Exp.var("x"), Exp.var("y"))
);
- parseExpressionAndCompare("with (x = 1, y = ${x} + 1) do (${x} + ${y})",
+ parseExpAndCompare("with (x = 1, y = ${x} + 1) do (${x} + ${y})",
expected);
// different spacing style
- parseExpressionAndCompare("with(x = 1, y = ${x}+1) do(${x}+${y})",
+ parseExpAndCompare("with(x = 1, y = ${x}+1) do(${x}+${y})",
expected);
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/ExplicitTypesTests.java b/src/test/java/com/aerospike/dsl/expression/ExplicitTypesTests.java
index 7774aa5..d74a480 100644
--- a/src/test/java/com/aerospike/dsl/expression/ExplicitTypesTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/ExplicitTypesTests.java
@@ -1,15 +1,15 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
import java.util.Base64;
import java.util.List;
import java.util.TreeMap;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
// Explicit types tests, list and map explicit types are tested in their own test classes
@@ -17,35 +17,35 @@ public class ExplicitTypesTests {
@Test
void integerComparison() {
- parseExpressionAndCompare("$.intBin1.get(type: INT) > 5",
+ parseExpAndCompare("$.intBin1.get(type: INT) > 5",
Exp.gt(Exp.intBin("intBin1"), Exp.val(5)));
- parseExpressionAndCompare("5 < $.intBin1.get(type: INT)",
+ parseExpAndCompare("5 < $.intBin1.get(type: INT)",
Exp.lt(Exp.val(5), Exp.intBin("intBin1")));
}
@Test
void stringComparison() {
// A String constant must contain quoted Strings
- parseExpressionAndCompare("$.stringBin1.get(type: STRING) == \"yes\"",
+ parseExpAndCompare("$.stringBin1.get(type: STRING) == \"yes\"",
Exp.eq(Exp.stringBin("stringBin1"), Exp.val("yes")));
- parseExpressionAndCompare("$.stringBin1.get(type: STRING) == 'yes'",
+ parseExpAndCompare("$.stringBin1.get(type: STRING) == 'yes'",
Exp.eq(Exp.stringBin("stringBin1"), Exp.val("yes")));
- parseExpressionAndCompare("\"yes\" == $.stringBin1.get(type: STRING)",
+ parseExpAndCompare("\"yes\" == $.stringBin1.get(type: STRING)",
Exp.eq(Exp.val("yes"), Exp.stringBin("stringBin1")));
- parseExpressionAndCompare("'yes' == $.stringBin1.get(type: STRING)",
+ parseExpAndCompare("'yes' == $.stringBin1.get(type: STRING)",
Exp.eq(Exp.val("yes"), Exp.stringBin("stringBin1")));
}
@Test
void stringComparisonNegativeTest() {
// A String constant must be quoted
- assertThatThrownBy(() -> parseExpressionAndCompare("$.stringBin1.get(type: STRING) == yes",
+ assertThatThrownBy(() -> parseExpAndCompare("$.stringBin1.get(type: STRING) == yes",
Exp.eq(Exp.stringBin("stringBin1"), Exp.val("yes"))))
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse right operand");
}
@@ -53,65 +53,65 @@ void stringComparisonNegativeTest() {
void blobComparison() {
byte[] data = new byte[]{1, 2, 3};
String encodedString = Base64.getEncoder().encodeToString(data);
- parseExpressionAndCompare("$.blobBin1.get(type: BLOB) == \"" + encodedString + "\"",
+ parseExpAndCompare("$.blobBin1.get(type: BLOB) == \"" + encodedString + "\"",
Exp.eq(Exp.blobBin("blobBin1"), Exp.val(data)));
// Reverse
- parseExpressionAndCompare("\"" + encodedString + "\"" + " == $.blobBin1.get(type: BLOB)",
+ parseExpAndCompare("\"" + encodedString + "\"" + " == $.blobBin1.get(type: BLOB)",
Exp.eq(Exp.val(data), Exp.blobBin("blobBin1")));
}
@Test
void floatComparison() {
- parseExpressionAndCompare("$.floatBin1.get(type: FLOAT) == 1.5",
+ parseExpAndCompare("$.floatBin1.get(type: FLOAT) == 1.5",
Exp.eq(Exp.floatBin("floatBin1"), Exp.val(1.5)));
- parseExpressionAndCompare("1.5 == $.floatBin1.get(type: FLOAT)",
+ parseExpAndCompare("1.5 == $.floatBin1.get(type: FLOAT)",
Exp.eq(Exp.val(1.5), Exp.floatBin("floatBin1")));
}
@Test
void booleanComparison() {
- parseExpressionAndCompare("$.boolBin1.get(type: BOOL) == true",
+ parseExpAndCompare("$.boolBin1.get(type: BOOL) == true",
Exp.eq(Exp.boolBin("boolBin1"), Exp.val(true)));
- parseExpressionAndCompare("true == $.boolBin1.get(type: BOOL)",
+ parseExpAndCompare("true == $.boolBin1.get(type: BOOL)",
Exp.eq(Exp.val(true), Exp.boolBin("boolBin1")));
}
@Test
void negativeBooleanComparison() {
- assertThatThrownBy(() -> parseExpression("$.boolBin1.get(type: BOOL) == 5"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("$.boolBin1.get(type: BOOL) == 5"))
+ .isInstanceOf(DslParseException.class)
.hasMessageContaining("Cannot compare BOOL to INT");
}
@Test
void listComparison_constantOnRightSide() {
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [100]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [100]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of(100))));
- parseExpressionAndCompare("$.listBin1.[] == [100]",
+ parseExpAndCompare("$.listBin1.[] == [100]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of(100))));
// integer values are read as long
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [100, 200, 300, 400]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [100, 200, 300, 400]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of(100, 200, 300, 400))));
// integer values are read as long
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [100, 200, 300, 400]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [100, 200, 300, 400]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of(100L, 200L, 300L, 400L))));
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == ['yes']",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == ['yes']",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of("yes"))));
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == ['yes', 'of course']",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == ['yes', 'of course']",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of("yes", "of course"))));
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [\"yes\"]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [\"yes\"]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of("yes"))));
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [\"yes\", \"of course\"]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [\"yes\", \"of course\"]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of("yes", "of course"))));
}
@@ -119,39 +119,39 @@ void listComparison_constantOnRightSide() {
void listComparison_constantOnRightSide_NegativeTest() {
// A String constant must be quoted
assertThatThrownBy(() ->
- parseExpressionAndCompare("$.listBin1.get(type: LIST) == [yes, of course]",
+ parseExpAndCompare("$.listBin1.get(type: LIST) == [yes, of course]",
Exp.eq(Exp.listBin("listBin1"), Exp.val(List.of("yes", "of course"))))
)
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse list operand");
}
@Test
void listComparison_constantOnLeftSide() {
- parseExpressionAndCompare("[100] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[100] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of(100)), Exp.listBin("listBin1")));
- parseExpressionAndCompare("[100] == $.listBin1.[]",
+ parseExpAndCompare("[100] == $.listBin1.[]",
Exp.eq(Exp.val(List.of(100)), Exp.listBin("listBin1")));
// integer values are read as long
- parseExpressionAndCompare("[100, 200, 300, 400] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[100, 200, 300, 400] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of(100, 200, 300, 400)), Exp.listBin("listBin1")));
// integer values are read as long
- parseExpressionAndCompare("[100, 200, 300, 400] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[100, 200, 300, 400] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of(100L, 200L, 300L, 400L)), Exp.listBin("listBin1")));
- parseExpressionAndCompare("['yes'] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("['yes'] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of("yes")), Exp.listBin("listBin1")));
- parseExpressionAndCompare("['yes', 'of course'] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("['yes', 'of course'] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of("yes", "of course")), Exp.listBin("listBin1")));
- parseExpressionAndCompare("[\"yes\"] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[\"yes\"] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of("yes")), Exp.listBin("listBin1")));
- parseExpressionAndCompare("[\"yes\", \"of course\"] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[\"yes\", \"of course\"] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of("yes", "of course")), Exp.listBin("listBin1")));
}
@@ -159,11 +159,11 @@ void listComparison_constantOnLeftSide() {
void listComparison_constantOnLeftSide_NegativeTest() {
// A String constant must be quoted
assertThatThrownBy(() ->
- parseExpressionAndCompare("[yes, of course] == $.listBin1.get(type: LIST)",
+ parseExpAndCompare("[yes, of course] == $.listBin1.get(type: LIST)",
Exp.eq(Exp.val(List.of("yes", "of course")), Exp.listBin("listBin1")))
)
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Could not parse given input, wrong syntax");
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Could not parse given DSL expression input");
}
@SuppressWarnings("unchecked")
@@ -185,39 +185,39 @@ public static TreeMap treeMapOf(Object... entries) {
@Test
void mapComparison_constantOnRightSide() {
// Prerequisite for comparing maps: both sides must be ordered maps
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {100:100}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {100:100}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(100, 100))));
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {100 : 100}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {100 : 100}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(100, 100))));
- parseExpressionAndCompare("$.mapBin1.{} == {100:100}",
+ parseExpAndCompare("$.mapBin1.{} == {100:100}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(100, 100))));
byte[] blobKey = new byte[]{1, 2, 3};
String encodedBlobKey = Base64.getEncoder().encodeToString(blobKey);
// encoded blob key must be quoted as it is a String
- parseExpressionAndCompare("$.mapBin1.{} == {'" + encodedBlobKey + "':100}",
+ parseExpAndCompare("$.mapBin1.{} == {'" + encodedBlobKey + "':100}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(encodedBlobKey, 100))));
// integer values are read as long
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {100:200, 300:400}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {100:200, 300:400}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(100L, 200L, 300L, 400L))));
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {100:200, 300:400}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {100:200, 300:400}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf(100, 200, 300, 400))));
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {'yes?':'yes!'}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {'yes?':'yes!'}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("yes?", "yes!"))));
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {\"yes\" : \"yes\"}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {\"yes\" : \"yes\"}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("yes", "yes"))));
- parseExpressionAndCompare(
+ parseExpAndCompare(
"$.mapBin1.get(type: MAP) == {\"yes of course\" : \"yes of course\"}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("yes of course", "yes of course"))));
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {\"yes\" : [\"yes\", \"of course\"]}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {\"yes\" : [\"yes\", \"of course\"]}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("yes", List.of("yes", "of course")))));
}
@@ -225,64 +225,64 @@ void mapComparison_constantOnRightSide() {
void mapComparison_constantOnRightSide_NegativeTest() {
// A String constant must be quoted
assertThatThrownBy(() ->
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {yes, of course}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {yes, of course}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("yes", "of course"))))
)
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse map operand");
assertThatThrownBy(() ->
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == ['yes', 'of course']",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == ['yes', 'of course']",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(List.of("yes", "of course"))))
)
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Cannot compare MAP to LIST");
// Map key can only be Integer or String
assertThatThrownBy(() ->
- parseExpressionAndCompare("$.mapBin1.get(type: MAP) == {[100]:[100]}",
+ parseExpAndCompare("$.mapBin1.get(type: MAP) == {[100]:[100]}",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(List.of("yes", "of course"))))
)
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse map operand");
}
@Test
void mapComparison_constantOnLeftSide() {
// Prerequisite for comparing maps: both sides must be ordered maps
- parseExpressionAndCompare("{100:100} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{100:100} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf(100, 100)), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{100 : 100} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{100 : 100} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf(100, 100)), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{100:100} == $.mapBin1.{}",
+ parseExpAndCompare("{100:100} == $.mapBin1.{}",
Exp.eq(Exp.val(treeMapOf(100, 100)), Exp.mapBin("mapBin1")));
byte[] blobKey = new byte[]{1, 2, 3};
String encodedBlobKey = Base64.getEncoder().encodeToString(blobKey);
// encoded blob key must be quoted as it is a String
- parseExpressionAndCompare("{'" + encodedBlobKey + "':100} == $.mapBin1.{}",
+ parseExpAndCompare("{'" + encodedBlobKey + "':100} == $.mapBin1.{}",
Exp.eq(Exp.val(treeMapOf(encodedBlobKey, 100)), Exp.mapBin("mapBin1")));
// integer values are read as long
- parseExpressionAndCompare("{100:200, 300:400} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{100:200, 300:400} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf(100L, 200L, 300L, 400L)), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{100:200, 300:400} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{100:200, 300:400} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf(100, 200, 300, 400)), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{'yes?':'yes!'} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{'yes?':'yes!'} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf("yes?", "yes!")), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{\"yes\" : \"yes\"} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{\"yes\" : \"yes\"} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf("yes", "yes")), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare(
+ parseExpAndCompare(
"{\"yes of course\" : \"yes of course\"} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf("yes of course", "yes of course")), Exp.mapBin("mapBin1")));
- parseExpressionAndCompare("{\"yes\" : [\"yes\", \"of course\"]} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{\"yes\" : [\"yes\", \"of course\"]} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(treeMapOf("yes", List.of("yes", "of course"))), Exp.mapBin("mapBin1")));
}
@@ -290,68 +290,68 @@ void mapComparison_constantOnLeftSide() {
void mapComparison_constantOnLeftSide_NegativeTest() {
// A String constant must be quoted
assertThatThrownBy(() ->
- parseExpressionAndCompare("{yes, of course} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{yes, of course} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.mapBin("mapBin1"), Exp.val(treeMapOf("of course", "yes"))))
)
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Could not parse given input, wrong syntax");
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Could not parse given DSL expression input");
assertThatThrownBy(() ->
- parseExpressionAndCompare("['yes', 'of course'] == $.mapBin1.get(type: MAP)", // incorrect: must be {}
+ parseExpAndCompare("['yes', 'of course'] == $.mapBin1.get(type: MAP)", // incorrect: must be {}
Exp.eq(Exp.val(List.of("yes", "of course")), Exp.mapBin("mapBin1")))
)
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Cannot compare LIST to MAP");
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Cannot compare MAP to LIST");
// Map key can only be Integer or String
assertThatThrownBy(() ->
- parseExpressionAndCompare("{[100]:[100]} == $.mapBin1.get(type: MAP)",
+ parseExpAndCompare("{[100]:[100]} == $.mapBin1.get(type: MAP)",
Exp.eq(Exp.val(List.of("yes", "of course")), Exp.mapBin("mapBin1")))
)
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Could not parse given input, wrong syntax");
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Could not parse given DSL expression input");
}
@Test
void twoStringBinsComparison() {
- parseExpressionAndCompare("$.stringBin1.get(type: STRING) == $.stringBin2.get(type: STRING)",
+ parseExpAndCompare("$.stringBin1.get(type: STRING) == $.stringBin2.get(type: STRING)",
Exp.eq(Exp.stringBin("stringBin1"), Exp.stringBin("stringBin2")));
}
@Test
void twoIntegerBinsComparison() {
- parseExpressionAndCompare("$.intBin1.get(type: INT) == $.intBin2.get(type: INT)",
+ parseExpAndCompare("$.intBin1.get(type: INT) == $.intBin2.get(type: INT)",
Exp.eq(Exp.intBin("intBin1"), Exp.intBin("intBin2")));
}
@Test
void twoFloatBinsComparison() {
- parseExpressionAndCompare("$.floatBin1.get(type: FLOAT) == $.floatBin2.get(type: FLOAT)",
+ parseExpAndCompare("$.floatBin1.get(type: FLOAT) == $.floatBin2.get(type: FLOAT)",
Exp.eq(Exp.floatBin("floatBin1"), Exp.floatBin("floatBin2")));
}
@Test
void twoBlobBinsComparison() {
- parseExpressionAndCompare("$.blobBin1.get(type: BLOB) == $.blobBin2.get(type: BLOB)",
+ parseExpAndCompare("$.blobBin1.get(type: BLOB) == $.blobBin2.get(type: BLOB)",
Exp.eq(Exp.blobBin("blobBin1"), Exp.blobBin("blobBin2")));
}
@Test
void negativeTwoDifferentBinTypesComparison() {
- assertThatThrownBy(() -> parseExpression("$.stringBin1.get(type: STRING) == $.floatBin2.get(type: FLOAT)"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("$.stringBin1.get(type: STRING) == $.floatBin2.get(type: FLOAT)"))
+ .isInstanceOf(DslParseException.class)
.hasMessageContaining("Cannot compare STRING to FLOAT");
}
@Test
void secondDegreeExplicitFloat() {
- parseExpressionAndCompare("($.apples.get(type: FLOAT) + $.bananas.get(type: FLOAT)) > 10.5",
+ parseExpAndCompare("($.apples.get(type: FLOAT) + $.bananas.get(type: FLOAT)) > 10.5",
Exp.gt(Exp.add(Exp.floatBin("apples"), Exp.floatBin("bananas")), Exp.val(10.5)));
}
@Test
void forthDegreeComplicatedExplicitFloat() {
- parseExpressionAndCompare("(($.apples.get(type: FLOAT) + $.bananas.get(type: FLOAT))" +
+ parseExpAndCompare("(($.apples.get(type: FLOAT) + $.bananas.get(type: FLOAT))" +
" + ($.oranges.get(type: FLOAT) + $.acai.get(type: FLOAT))) > 10.5",
Exp.gt(
Exp.add(
@@ -382,7 +382,7 @@ void complicatedWhenExplicitTypeIntDefault() {
)
);
- parseExpressionAndCompare("$.a.get(type: INT) == " +
+ parseExpAndCompare("$.a.get(type: INT) == " +
"(when($.b.get(type: INT) == 1 => $.a1.get(type: INT)," +
" $.b.get(type: INT) == 2 => $.a2.get(type: INT)," +
" $.b.get(type: INT) == 3 => $.a3.get(type: INT)," +
@@ -411,7 +411,7 @@ void complicatedWhenExplicitTypeString() {
)
);
- parseExpressionAndCompare("$.a.get(type: STRING) == " +
+ parseExpAndCompare("$.a.get(type: STRING) == " +
"(when($.b == 1 => $.a1.get(type: STRING)," +
" $.b == 2 => $.a2.get(type: STRING)," +
" $.b == 3 => $.a3.get(type: STRING)," +
diff --git a/src/test/java/com/aerospike/dsl/expression/ImplicitTypesTests.java b/src/test/java/com/aerospike/dsl/expression/ImplicitTypesTests.java
index 641f6aa..2d657bb 100644
--- a/src/test/java/com/aerospike/dsl/expression/ImplicitTypesTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/ImplicitTypesTests.java
@@ -3,23 +3,23 @@
import com.aerospike.client.exp.Exp;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
public class ImplicitTypesTests {
@Test
void floatComparison() {
- parseExpressionAndCompare("$.floatBin1 >= 100.25",
+ parseExpAndCompare("$.floatBin1 >= 100.25",
Exp.ge(Exp.floatBin("floatBin1"), Exp.val(100.25)));
}
@Test
void booleanComparison() {
- parseExpressionAndCompare("$.boolBin1 == true",
+ parseExpAndCompare("$.boolBin1 == true",
Exp.eq(Exp.boolBin("boolBin1"), Exp.val(true)));
- parseExpressionAndCompare("false == $.boolBin1",
+ parseExpAndCompare("false == $.boolBin1",
Exp.eq(Exp.val(false), Exp.boolBin("boolBin1")));
- parseExpressionAndCompare("$.boolBin1 != false",
+ parseExpAndCompare("$.boolBin1 != false",
Exp.ne(Exp.boolBin("boolBin1"), Exp.val(false)));
}
@@ -27,31 +27,31 @@ void booleanComparison() {
// this can also be an expression that evaluates to a boolean result
@Test
void binBooleanImplicitLogicalComparison() {
- parseExpressionAndCompare("$.boolBin1 and $.boolBin2",
- Exp.and(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
- parseExpressionAndCompare("$.boolBin1 or $.boolBin2",
- Exp.or(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
- parseExpressionAndCompare("not($.boolBin1)",
+// parseFilterExpAndCompare("$.boolBin1 and $.boolBin2",
+// Exp.and(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
+// parseFilterExpAndCompare("$.boolBin1 or $.boolBin2",
+// Exp.or(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
+ parseExpAndCompare("not($.boolBin1)",
Exp.not(Exp.boolBin("boolBin1")));
- parseExpressionAndCompare("exclusive($.boolBin1, $.boolBin2)",
- Exp.exclusive(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
+// parseFilterExpAndCompare("exclusive($.boolBin1, $.boolBin2)",
+// Exp.exclusive(Exp.boolBin("boolBin1"), Exp.boolBin("boolBin2")));
}
@Test
void implicitDefaultIntComparison() {
- parseExpressionAndCompare("$.intBin1 < $.intBin2",
+ parseExpAndCompare("$.intBin1 < $.intBin2",
Exp.lt(Exp.intBin("intBin1"), Exp.intBin("intBin2")));
}
@Test
void secondDegreeImplicitCastingFloat() {
- parseExpressionAndCompare("($.apples + $.bananas) > 10.5",
+ parseExpAndCompare("($.apples + $.bananas) > 10.5",
Exp.gt(Exp.add(Exp.floatBin("apples"), Exp.floatBin("bananas")), Exp.val(10.5)));
}
@Test
void secondDegreeComplicatedFloatFirstImplicitCastingFloat() {
- parseExpressionAndCompare("($.apples + $.bananas) > 10.5 and ($.oranges + $.grapes) <= 5",
+ parseExpAndCompare("($.apples + $.bananas) > 10.5 and ($.oranges + $.grapes) <= 5",
Exp.and(
Exp.gt(Exp.add(Exp.floatBin("apples"), Exp.floatBin("bananas")), Exp.val(10.5)),
Exp.le(Exp.add(Exp.intBin("oranges"), Exp.intBin("grapes")), Exp.val(5)))
@@ -60,7 +60,7 @@ void secondDegreeComplicatedFloatFirstImplicitCastingFloat() {
@Test
void secondDegreeComplicatedIntFirstImplicitCastingFloat() {
- parseExpressionAndCompare("($.apples + $.bananas) > 5 and ($.oranges + $.grapes) <= 10.5",
+ parseExpAndCompare("($.apples + $.bananas) > 5 and ($.oranges + $.grapes) <= 10.5",
Exp.and(
Exp.gt(Exp.add(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.val(5)),
Exp.le(Exp.add(Exp.floatBin("oranges"), Exp.floatBin("grapes")), Exp.val(10.5)))
@@ -69,7 +69,7 @@ void secondDegreeComplicatedIntFirstImplicitCastingFloat() {
@Test
void thirdDegreeComplicatedDefaultInt() {
- parseExpressionAndCompare("(($.apples + $.bananas) + $.oranges) > 10",
+ parseExpAndCompare("(($.apples + $.bananas) + $.oranges) > 10",
Exp.gt(
Exp.add(Exp.add(Exp.intBin("apples"), Exp.intBin("bananas")), Exp.intBin("oranges")),
Exp.val(10))
@@ -78,7 +78,7 @@ void thirdDegreeComplicatedDefaultInt() {
@Test
void thirdDegreeComplicatedImplicitCastingFloat() {
- parseExpressionAndCompare("(($.apples + $.bananas) + $.oranges) > 10.5",
+ parseExpAndCompare("(($.apples + $.bananas) + $.oranges) > 10.5",
Exp.gt(
Exp.add(Exp.add(Exp.floatBin("apples"), Exp.floatBin("bananas")), Exp.floatBin("oranges")),
Exp.val(10.5))
@@ -87,7 +87,7 @@ void thirdDegreeComplicatedImplicitCastingFloat() {
@Test
void forthDegreeComplicatedDefaultInt() {
- parseExpressionAndCompare("(($.apples + $.bananas) + ($.oranges + $.acai)) > 10",
+ parseExpAndCompare("(($.apples + $.bananas) + ($.oranges + $.acai)) > 10",
Exp.gt(
Exp.add(
Exp.add(Exp.intBin("apples"), Exp.intBin("bananas")),
@@ -98,7 +98,7 @@ void forthDegreeComplicatedDefaultInt() {
@Test
void forthDegreeComplicatedImplicitCastingFloat() {
- parseExpressionAndCompare("(($.apples + $.bananas) + ($.oranges + $.acai)) > 10.5",
+ parseExpAndCompare("(($.apples + $.bananas) + ($.oranges + $.acai)) > 10.5",
Exp.gt(
Exp.add(
Exp.add(Exp.floatBin("apples"), Exp.floatBin("bananas")),
@@ -128,7 +128,7 @@ void complicatedWhenImplicitTypeInt() {
)
);
- parseExpressionAndCompare("$.a == (when($.b == 1 => $.a1, $.b == 2 => $.a2, $.b == 3 => $.a3, default => $.a4+1))",
+ parseExpAndCompare("$.a == (when($.b == 1 => $.a1, $.b == 2 => $.a2, $.b == 3 => $.a3, default => $.a4+1))",
expected);
}
@@ -154,7 +154,7 @@ void complicatedWhenImplicitTypeString() {
)
);
- parseExpressionAndCompare("$.a == (when($.b == 1 => $.a1, $.b == 2 => $.a2, $.b == 3 => $.a3, default => \"hello\"))",
+ parseExpAndCompare("$.a == (when($.b == 1 => $.a1, $.b == 2 => $.a2, $.b == 3 => $.a3, default => \"hello\"))",
expected);
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/ListExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/ListExpressionsTests.java
index fa6f36c..1f5d96f 100644
--- a/src/test/java/com/aerospike/dsl/expression/ListExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/ListExpressionsTests.java
@@ -4,13 +4,13 @@
import com.aerospike.client.cdt.ListReturnType;
import com.aerospike.client.exp.Exp;
import com.aerospike.client.exp.ListExp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
import java.util.List;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class ListExpressionsTests {
@@ -26,10 +26,10 @@ void listByIndexInteger() {
),
Exp.val(100));
// Implicit detect as Int
- parseExpressionAndCompare("$.listBin1.[0] == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].asInt() == 100", expected);
+ parseExpAndCompare("$.listBin1.[0] == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: INT) == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].asInt() == 100", expected);
}
@Test
@@ -43,9 +43,9 @@ void listByIndexOtherTypes() {
),
Exp.val("stringVal"));
// Implicit detect as string
- parseExpressionAndCompare("$.listBin1.[0] == \"stringVal\"", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: STRING) == \"stringVal\"", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: STRING, return: VALUE) == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[0] == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: STRING, return: VALUE) == \"stringVal\"", expected);
expected = Exp.eq(
ListExp.getByIndex(
@@ -56,9 +56,9 @@ void listByIndexOtherTypes() {
),
Exp.val(true));
// Implicit detect as boolean
- parseExpressionAndCompare("$.listBin1.[0] == true", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: BOOL) == true", expected);
- parseExpressionAndCompare("$.listBin1.[0].get(type: BOOL, return: VALUE) == true", expected);
+ parseExpAndCompare("$.listBin1.[0] == true", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: BOOL) == true", expected);
+ parseExpAndCompare("$.listBin1.[0].get(type: BOOL, return: VALUE) == true", expected);
}
@Test
@@ -70,10 +70,10 @@ void listByValue() {
Exp.listBin("listBin1")
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[=100] == 100", expected);
- parseExpressionAndCompare("$.listBin1.[=100].get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[=100].get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[=100].asInt() == 100", expected);
+ parseExpAndCompare("$.listBin1.[=100] == 100", expected);
+ parseExpAndCompare("$.listBin1.[=100].get(type: INT) == 100", expected);
+ parseExpAndCompare("$.listBin1.[=100].get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.listBin1.[=100].asInt() == 100", expected);
}
@Test
@@ -84,8 +84,8 @@ void listByValueCount() {
Exp.listBin("listBin1")),
Exp.val(0)
);
- parseExpressionAndCompare("$.listBin1.[=100].count() > 0", expected);
- parseExpressionAndCompare("$.listBin1.[=100].[].count() > 0", expected);
+ parseExpAndCompare("$.listBin1.[=100].count() > 0", expected);
+ parseExpAndCompare("$.listBin1.[=100].[].count() > 0", expected);
}
@Test
@@ -98,10 +98,10 @@ void listByRank() {
Exp.listBin("listBin1")
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[#-1] == 100", expected);
- parseExpressionAndCompare("$.listBin1.[#-1].get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[#-1].get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[#-1].asInt() == 100", expected);
+ parseExpAndCompare("$.listBin1.[#-1] == 100", expected);
+ parseExpAndCompare("$.listBin1.[#-1].get(type: INT) == 100", expected);
+ parseExpAndCompare("$.listBin1.[#-1].get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.listBin1.[#-1].asInt() == 100", expected);
}
@Test
@@ -116,9 +116,9 @@ void listBinElementEquals_Nested() {
CTX.listIndex(0)
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[0].[0].[0] == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].[0].[0].get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].[0].[0].get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].[0].[0] == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].[0].[0].get(type: INT) == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].[0].[0].get(type: INT, return: VALUE) == 100", expected);
}
@Test
@@ -126,10 +126,10 @@ void listSize() {
Exp expected = Exp.eq(
ListExp.size(Exp.listBin("listBin1")),
Exp.val(1));
- parseExpressionAndCompare("$.listBin1.[].count() == 1", expected);
+ parseExpAndCompare("$.listBin1.[].count() == 1", expected);
// the default behaviour for count() without List '[]' or Map '{}' designators is List
- parseExpressionAndCompare("$.listBin1.count() == 1", expected);
+ parseExpAndCompare("$.listBin1.count() == 1", expected);
}
@Test
@@ -143,10 +143,10 @@ void nestedListSize() {
Exp.listBin("listBin1"))
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[1].[].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].[].count() == 100", expected);
// the default behaviour for count() without List '[]' or Map '{}' designators is List
- parseExpressionAndCompare("$.listBin1.[1].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].count() == 100", expected);
}
@@ -162,10 +162,10 @@ void nestedListSizeWithContext() {
CTX.listIndex(1))
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[1].[2].[].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].[2].[].count() == 100", expected);
// the default behaviour for count() without List '[]' or Map '{}' designators is List
- parseExpressionAndCompare("$.listBin1.[1].[2].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].[2].count() == 100", expected);
}
@Test
@@ -179,7 +179,7 @@ void nestedLists() {
CTX.listIndex(5)
),
Exp.val("stringVal"));
- parseExpressionAndCompare("$.listBin1.[5].[1].get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[5].[1].get(type: STRING) == \"stringVal\"", expected);
}
@Test
@@ -195,8 +195,8 @@ void nestedListsWithDifferentContextTypes() {
),
Exp.val("stringVal"));
// Implicit detect as String
- parseExpressionAndCompare("$.listBin1.[5].[#-1] == \"stringVal\"", expected);
- parseExpressionAndCompare("$.listBin1.[5].[#-1].get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[5].[#-1] == \"stringVal\"", expected);
+ parseExpAndCompare("$.listBin1.[5].[#-1].get(type: STRING) == \"stringVal\"", expected);
// Nested List Rank Value
expected = Exp.eq(
@@ -209,7 +209,7 @@ void nestedListsWithDifferentContextTypes() {
),
Exp.val(200));
// Implicit detect as Int
- parseExpressionAndCompare("$.listBin1.[5].[#-1].[=100] == 200", expected);
+ parseExpAndCompare("$.listBin1.[5].[#-1].[=100] == 200", expected);
}
@Test
@@ -223,21 +223,21 @@ void listBinElementCount() {
),
Exp.val(100)
);
- parseExpressionAndCompare("$.listBin1.[0].count() == 100", expected);
- parseExpressionAndCompare("$.listBin1.[0].[].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[0].[].count() == 100", expected);
}
@Test
void negativeSyntaxList() {
// TODO: throw meaningful exception (by ANTLR?)
- assertThatThrownBy(() -> parseExpression("$.listBin1.[stringValue] == 100"))
- .isInstanceOf(AerospikeDSLException.class);
+ assertThatThrownBy(() -> parseExp("$.listBin1.[stringValue] == 100"))
+ .isInstanceOf(DslParseException.class);
}
//@Test
void negativeTypeComparisonList() {
// TODO: should fail? Exp is successfully created but comparing int to a string value (validations on List)
- assertThatThrownBy(() -> parseExpression("$.listBin1.[#-1].get(type: INT) == \"stringValue\""))
+ assertThatThrownBy(() -> parseExp("$.listBin1.[#-1].get(type: INT) == \"stringValue\""))
.isInstanceOf(NullPointerException.class);
}
@@ -248,7 +248,7 @@ void listIndexRange() {
Exp.val(1),
Exp.val(2),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[1:3]", expected);
+ parseExpAndCompare("$.listBin1.[1:3]", expected);
// Negative
expected = ListExp.getByIndexRange(
@@ -256,7 +256,7 @@ void listIndexRange() {
Exp.val(-3),
Exp.val(4),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[-3:1]", expected);
+ parseExpAndCompare("$.listBin1.[-3:1]", expected);
// Inverted
expected = ListExp.getByIndexRange(
@@ -264,14 +264,14 @@ void listIndexRange() {
Exp.val(2),
Exp.val(2),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[!2:4]", expected);
+ parseExpAndCompare("$.listBin1.[!2:4]", expected);
// From start till the end
expected = ListExp.getByIndexRange(
ListReturnType.VALUE,
Exp.val(1),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[1:]", expected);
+ parseExpAndCompare("$.listBin1.[1:]", expected);
}
@Test
@@ -280,23 +280,23 @@ void listValueList() {
ListReturnType.VALUE,
Exp.val(List.of("a", "b", "c")),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[=a,b,c]", expected);
- parseExpressionAndCompare("$.listBin1.[=\"a\",\"b\",\"c\"]", expected);
+ parseExpAndCompare("$.listBin1.[=a,b,c]", expected);
+ parseExpAndCompare("$.listBin1.[=\"a\",\"b\",\"c\"]", expected);
// Integer
expected = ListExp.getByValueList(
ListReturnType.VALUE,
Exp.val(List.of(1, 2, 3)),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[=1,2,3]", expected);
+ parseExpAndCompare("$.listBin1.[=1,2,3]", expected);
// Inverted
expected = ListExp.getByValueList(
ListReturnType.VALUE | ListReturnType.INVERTED,
Exp.val(List.of("a", "b", "c")),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[!=a,b,c]", expected);
- parseExpressionAndCompare("$.listBin1.[!=\"a\",\"b\",\"c\"]", expected);
+ parseExpAndCompare("$.listBin1.[!=a,b,c]", expected);
+ parseExpAndCompare("$.listBin1.[!=\"a\",\"b\",\"c\"]", expected);
}
@Test
@@ -307,7 +307,7 @@ void listValueRange() {
Exp.val(111),
Exp.val(334),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[=111:334]", expected);
+ parseExpAndCompare("$.listBin1.[=111:334]", expected);
// Inverted
expected = ListExp.getByValueRange(
@@ -315,7 +315,7 @@ void listValueRange() {
Exp.val(10),
Exp.val(20),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[!=10:20]", expected);
+ parseExpAndCompare("$.listBin1.[!=10:20]", expected);
// From start till the end
expected = ListExp.getByValueRange(
@@ -323,7 +323,7 @@ void listValueRange() {
Exp.val(111),
null,
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[=111:]", expected);
+ parseExpAndCompare("$.listBin1.[=111:]", expected);
}
@Test
@@ -333,7 +333,7 @@ void listRankRange() {
Exp.val(0),
Exp.val(3),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[#0:3]", expected);
+ parseExpAndCompare("$.listBin1.[#0:3]", expected);
// Inverted
expected = ListExp.getByRankRange(
@@ -341,14 +341,14 @@ void listRankRange() {
Exp.val(0),
Exp.val(3),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[!#0:3]", expected);
+ parseExpAndCompare("$.listBin1.[!#0:3]", expected);
// From start till the end
expected = ListExp.getByRankRange(
ListReturnType.VALUE,
Exp.val(-3),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[#-3:]", expected);
+ parseExpAndCompare("$.listBin1.[#-3:]", expected);
// From start till the end with context
expected = ListExp.getByRankRange(
@@ -356,7 +356,7 @@ void listRankRange() {
Exp.val(-3),
Exp.listBin("listBin1"),
CTX.listIndex(5));
- parseExpressionAndCompare("$.listBin1.[5].[#-3:]", expected);
+ parseExpAndCompare("$.listBin1.[5].[#-3:]", expected);
}
@Test
@@ -367,7 +367,7 @@ void listRankRangeRelative() {
Exp.val("b"),
Exp.val(2),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[#-3:-1~b]", expected);
+ parseExpAndCompare("$.listBin1.[#-3:-1~b]", expected);
// Inverted
expected = ListExp.getByValueRelativeRankRange(
@@ -376,7 +376,7 @@ void listRankRangeRelative() {
Exp.val("b"),
Exp.val(2),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[!#-3:-1~b]", expected);
+ parseExpAndCompare("$.listBin1.[!#-3:-1~b]", expected);
// From start till the end
expected = ListExp.getByValueRelativeRankRange(
@@ -384,7 +384,7 @@ void listRankRangeRelative() {
Exp.val(-3),
Exp.val("b"),
Exp.listBin("listBin1"));
- parseExpressionAndCompare("$.listBin1.[#-3:~b]", expected);
+ parseExpAndCompare("$.listBin1.[#-3:~b]", expected);
}
@Test
@@ -398,7 +398,7 @@ void listReturnTypes() {
),
Exp.val(5));
// Implicit detect as Int
- parseExpressionAndCompare("$.listBin1.[0].get(return: COUNT) == 5", expected);
+ parseExpAndCompare("$.listBin1.[0].get(return: COUNT) == 5", expected);
expected = Exp.eq(
ListExp.getByIndex(
@@ -409,7 +409,7 @@ void listReturnTypes() {
),
Exp.val(true));
// Implicit detect as Int
- parseExpressionAndCompare("$.listBin1.[0].get(return: EXISTS) == true", expected);
+ parseExpAndCompare("$.listBin1.[0].get(return: EXISTS) == true", expected);
expected = Exp.eq(
ListExp.getByIndex(
@@ -420,6 +420,6 @@ void listReturnTypes() {
),
Exp.val(1));
// Implicit detect as Int
- parseExpressionAndCompare("$.listBin1.[0].get(return: INDEX) == 1", expected);
+ parseExpAndCompare("$.listBin1.[0].get(return: INDEX) == 1", expected);
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/LogicalExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/LogicalExpressionsTests.java
index 28a7b86..ff6c344 100644
--- a/src/test/java/com/aerospike/dsl/expression/LogicalExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/LogicalExpressionsTests.java
@@ -1,12 +1,12 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class LogicalExpressionsTests {
@@ -15,7 +15,7 @@ public class LogicalExpressionsTests {
void binLogicalAndOrCombinations() {
Exp expected1 = Exp.and(Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
Exp.gt(Exp.intBin("intBin2"), Exp.val(100)));
- parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100", expected1);
+ parseExpAndCompare("$.intBin1 > 100 and $.intBin2 > 100", expected1);
Exp expected2 = Exp.or(
Exp.and(
@@ -25,8 +25,8 @@ void binLogicalAndOrCombinations() {
Exp.lt(Exp.intBin("intBin3"), Exp.val(100))
);
// TODO: what should be the default behaviour with no parentheses?
- parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 or $.intBin3 < 100", expected2);
- parseExpressionAndCompare("($.intBin1 > 100 and $.intBin2 > 100) or $.intBin3 < 100", expected2);
+ parseExpAndCompare("$.intBin1 > 100 and $.intBin2 > 100 or $.intBin3 < 100", expected2);
+ parseExpAndCompare("($.intBin1 > 100 and $.intBin2 > 100) or $.intBin3 < 100", expected2);
Exp expected3 = Exp.and(
Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
@@ -35,27 +35,27 @@ void binLogicalAndOrCombinations() {
Exp.lt(Exp.intBin("intBin3"), Exp.val(100))
)
);
- parseExpressionAndCompare("($.intBin1 > 100 and ($.intBin2 > 100 or $.intBin3 < 100))", expected3);
+ parseExpAndCompare("($.intBin1 > 100 and ($.intBin2 > 100 or $.intBin3 < 100))", expected3);
// check that parentheses make difference
- assertThatThrownBy(() -> parseExpressionAndCompare("($.intBin1 > 100 and ($.intBin2 > 100 or $.intBin3 < 100))", expected2))
+ assertThatThrownBy(() -> parseExpAndCompare("($.intBin1 > 100 and ($.intBin2 > 100 or $.intBin3 < 100))", expected2))
.isInstanceOf(AssertionFailedError.class);
}
@Test
void logicalNot() {
- parseExpressionAndCompare("not($.keyExists())", Exp.not(Exp.keyExists()));
+ parseExpAndCompare("not($.keyExists())", Exp.not(Exp.keyExists()));
}
@Test
void binLogicalExclusive() {
- parseExpressionAndCompare("exclusive($.hand == \"hook\", $.leg == \"peg\")",
+ parseExpAndCompare("exclusive($.hand == \"hook\", $.leg == \"peg\")",
Exp.exclusive(
Exp.eq(Exp.stringBin("hand"), Exp.val("hook")),
Exp.eq(Exp.stringBin("leg"), Exp.val("peg"))));
// More than 2 expressions exclusive
- parseExpressionAndCompare("exclusive($.a == \"aVal\", $.b == \"bVal\", $.c == \"cVal\", $.d == 4)",
+ parseExpAndCompare("exclusive($.a == \"aVal\", $.b == \"bVal\", $.c == \"cVal\", $.d == 4)",
Exp.exclusive(
Exp.eq(Exp.stringBin("a"), Exp.val("aVal")),
Exp.eq(Exp.stringBin("b"), Exp.val("bVal")),
@@ -66,7 +66,7 @@ void binLogicalExclusive() {
//TODO: FMWK-488
//@Test
void flatHierarchyAnd() {
- parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 < 100",
+ parseExpAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 < 100",
Exp.and(
Exp.gt(
Exp.intBin("intBin1"),
@@ -81,29 +81,29 @@ void flatHierarchyAnd() {
@Test
void negativeSyntaxLogicalOperators() {
- assertThatThrownBy(() -> parseExpression("($.intBin1 > 100 and ($.intBin2 > 100) or"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Could not parse given input");
+ assertThatThrownBy(() -> parseExp("($.intBin1 > 100 and ($.intBin2 > 100) or"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessageContaining("Could not parse given DSL expression input");
- assertThatThrownBy(() -> parseExpression("and ($.intBin1 > 100 and ($.intBin2 > 100)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Could not parse given input");
+ assertThatThrownBy(() -> parseExp("and ($.intBin1 > 100 and ($.intBin2 > 100)"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessageContaining("Could not parse given DSL expression input");
- assertThatThrownBy(() -> parseExpression("($.intBin1 > 100 and ($.intBin2 > 100) not"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Could not parse given input");
+ assertThatThrownBy(() -> parseExp("($.intBin1 > 100 and ($.intBin2 > 100) not"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessageContaining("Could not parse given DSL expression input");
- assertThatThrownBy(() -> parseExpression("($.intBin1 > 100 and ($.intBin2 > 100) exclusive"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Could not parse given input");
+ assertThatThrownBy(() -> parseExp("($.intBin1 > 100 and ($.intBin2 > 100) exclusive"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessageContaining("Could not parse given DSL expression input");
}
@Test
void negativeBinLogicalExclusiveWithOneParam() {
- assertThatThrownBy(() -> parseExpressionAndCompare("exclusive($.hand == \"hook\")",
+ assertThatThrownBy(() -> parseExpAndCompare("exclusive($.hand == \"hook\")",
Exp.exclusive(
Exp.eq(Exp.stringBin("hand"), Exp.val("hook")))))
- .isInstanceOf(AerospikeDSLException.class)
+ .isInstanceOf(DslParseException.class)
.hasMessage("Exclusive logical operator requires 2 or more expressions");
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/MapAndListExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/MapAndListExpressionsTests.java
index 5bff0a5..0c2926d 100644
--- a/src/test/java/com/aerospike/dsl/expression/MapAndListExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/MapAndListExpressionsTests.java
@@ -9,7 +9,7 @@
import com.aerospike.client.exp.MapExp;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
public class MapAndListExpressionsTests {
@@ -24,7 +24,7 @@ void listInsideAMap() {
CTX.mapKey(Value.get("a"))
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.a.[0] == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.[0] == 100", expected);
expected = Exp.gt(
ListExp.getByIndex(
@@ -35,7 +35,7 @@ void listInsideAMap() {
CTX.mapKey(Value.get("a")),
CTX.mapKey(Value.get("cc"))
), Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.a.cc.[2].get(type: INT) > 100", expected);
+ parseExpAndCompare("$.mapBin1.a.cc.[2].get(type: INT) > 100", expected);
}
@Test
@@ -50,7 +50,7 @@ void mapListList() {
CTX.listIndex(0)
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.a.[0].[0] == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.[0].[0] == 100", expected);
}
@Test
@@ -63,7 +63,7 @@ void mapInsideAList() {
Exp.listBin("listBin1"),
CTX.listIndex(2)
), Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[2].cc.get(type: INT) > 100", expected);
+ parseExpAndCompare("$.listBin1.[2].cc.get(type: INT) > 100", expected);
}
@Test
@@ -77,8 +77,8 @@ void listMapMap() {
CTX.listIndex(2),
CTX.mapKey(Value.get("aa"))
), Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[2].aa.cc > 100", expected);
- parseExpressionAndCompare("$.listBin1.[2].aa.cc.get(type: INT) > 100", expected);
+ parseExpAndCompare("$.listBin1.[2].aa.cc > 100", expected);
+ parseExpAndCompare("$.listBin1.[2].aa.cc.get(type: INT) > 100", expected);
}
@Test
@@ -93,7 +93,7 @@ void listMapList() {
CTX.mapKey(Value.get("a"))
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[1].a.[0] == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].a.[0] == 100", expected);
}
@Test
@@ -110,8 +110,8 @@ void listMapListSize() {
)
),
Exp.val(100));
- parseExpressionAndCompare("$.listBin1.[1].a.[0].count() == 100", expected);
- parseExpressionAndCompare("$.listBin1.[1].a.[0].[].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].a.[0].count() == 100", expected);
+ parseExpAndCompare("$.listBin1.[1].a.[0].[].count() == 100", expected);
}
@Test
@@ -125,8 +125,8 @@ void mapListMap() {
CTX.mapKey(Value.get("a")),
CTX.listIndex(0)
), Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.a.[0].cc > 100", expected);
- parseExpressionAndCompare("$.mapBin1.a.[0].cc.get(type: INT) > 100", expected);
+ parseExpAndCompare("$.mapBin1.a.[0].cc > 100", expected);
+ parseExpAndCompare("$.mapBin1.a.[0].cc.get(type: INT) > 100", expected);
}
//@Test
diff --git a/src/test/java/com/aerospike/dsl/expression/MapExpressionsTests.java b/src/test/java/com/aerospike/dsl/expression/MapExpressionsTests.java
index 68f36fb..806f5eb 100644
--- a/src/test/java/com/aerospike/dsl/expression/MapExpressionsTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/MapExpressionsTests.java
@@ -11,7 +11,7 @@
import java.util.List;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
public class MapExpressionsTests {
@@ -27,10 +27,10 @@ void mapOneLevelExpressions() {
),
Exp.val(200));
// Implicit detect as Int
- parseExpressionAndCompare("$.mapBin1.a == 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.get(type: INT) == 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.get(type: INT, return: VALUE) == 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.asInt() == 200", expected);
+ parseExpAndCompare("$.mapBin1.a == 200", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: INT) == 200", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: INT, return: VALUE) == 200", expected);
+ parseExpAndCompare("$.mapBin1.a.asInt() == 200", expected);
// String
expected = Exp.eq(
@@ -42,9 +42,9 @@ void mapOneLevelExpressions() {
),
Exp.val("stringVal"));
// Implicit detect as String
- parseExpressionAndCompare("$.mapBin1.a == \"stringVal\"", expected);
- parseExpressionAndCompare("$.mapBin1.a.get(type: STRING) == \"stringVal\"", expected);
- parseExpressionAndCompare("$.mapBin1.a.get(type: STRING, return: VALUE) == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: STRING, return: VALUE) == \"stringVal\"", expected);
}
@Test
@@ -58,9 +58,9 @@ void mapNestedLevelExpressions() {
CTX.mapKey(Value.get("a")), CTX.mapKey(Value.get("bb"))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc > 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc.get(type: INT) > 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc.get(type: INT, return: VALUE) > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc.get(type: INT, return: VALUE) > 200", expected);
// String
expected = Exp.eq(
@@ -73,9 +73,9 @@ void mapNestedLevelExpressions() {
),
Exp.val("stringVal"));
// Implicit detect as String
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc == \"stringVal\"", expected);
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc.get(type: STRING) == \"stringVal\"", expected);
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc.get(type: STRING, return: VALUE) == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc.get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc.get(type: STRING, return: VALUE) == \"stringVal\"", expected);
}
@Test
@@ -89,9 +89,9 @@ void quotedStringInExpressionPath() {
CTX.mapKey(Value.get("a")), CTX.mapKey(Value.get("bb"))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.bb.bcc.get(type: INT) > 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.\"bb\".bcc.get(type: INT) > 200", expected);
- parseExpressionAndCompare("$.mapBin1.a.'bb'.bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.bb.bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.\"bb\".bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.a.'bb'.bcc.get(type: INT) > 200", expected);
expected = Exp.gt(
MapExp.getByKey(
@@ -102,8 +102,8 @@ void quotedStringInExpressionPath() {
CTX.mapKey(Value.get("127.0.0.1"))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.\"127.0.0.1\".bcc.get(type: INT) > 200", expected);
- parseExpressionAndCompare("$.mapBin1.'127.0.0.1'.bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.\"127.0.0.1\".bcc.get(type: INT) > 200", expected);
+ parseExpAndCompare("$.mapBin1.'127.0.0.1'.bcc.get(type: INT) > 200", expected);
}
@Test
@@ -113,7 +113,7 @@ void mapSize() {
Exp.mapBin("mapBin1")
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.{}.count() > 200", expected);
+ parseExpAndCompare("$.mapBin1.{}.count() > 200", expected);
// the default behaviour for count() without List '[]' or Map '{}' designators is List
Exp expected2 = Exp.gt(
@@ -121,7 +121,7 @@ void mapSize() {
Exp.listBin("mapBin1")
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.count() > 200", expected2);
+ parseExpAndCompare("$.mapBin1.count() > 200", expected2);
}
@Test
@@ -135,7 +135,7 @@ void nestedMapSize() {
Exp.mapBin("mapBin1"))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.{}.count() == 200", expected);
+ parseExpAndCompare("$.mapBin1.a.{}.count() == 200", expected);
// the default behaviour for count() without Map '{}' or List '[]' designators is List
Exp expected2 = Exp.eq(
@@ -146,7 +146,7 @@ void nestedMapSize() {
Exp.mapBin("mapBin1"))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.count() == 200", expected2);
+ parseExpAndCompare("$.mapBin1.a.count() == 200", expected2);
}
@Test
@@ -161,7 +161,7 @@ void nestedMapSizeWithContext() {
CTX.mapKey(Value.get("a")))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.b.{}.count() == 200", expected);
+ parseExpAndCompare("$.mapBin1.a.b.{}.count() == 200", expected);
// the default behaviour for count() without Map '{}' or List '[]' designators is List
Exp expected2 = Exp.eq(
@@ -173,7 +173,7 @@ void nestedMapSizeWithContext() {
CTX.mapKey(Value.get("a")))
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.a.b.count() == 200", expected2);
+ parseExpAndCompare("$.mapBin1.a.b.count() == 200", expected2);
}
@Test
@@ -186,10 +186,10 @@ void mapByIndex() {
Exp.mapBin("mapBin1")
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.{0} == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{0}.get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{0}.get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{0}.asInt() == 100", expected);
+ parseExpAndCompare("$.mapBin1.{0} == 100", expected);
+ parseExpAndCompare("$.mapBin1.{0}.get(type: INT) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{0}.get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{0}.asInt() == 100", expected);
}
@Test
@@ -201,10 +201,10 @@ void mapByValue() {
Exp.mapBin("mapBin1")
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.{=100} == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{=100}.get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{=100}.get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{=100}.asInt() == 100", expected);
+ parseExpAndCompare("$.mapBin1.{=100} == 100", expected);
+ parseExpAndCompare("$.mapBin1.{=100}.get(type: INT) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{=100}.get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{=100}.asInt() == 100", expected);
}
@Test
@@ -215,8 +215,8 @@ void mapByValueCount() {
Exp.mapBin("mapBin1")),
Exp.val(0)
);
- parseExpressionAndCompare("$.mapBin1.{=100}.count() > 0", expected);
- parseExpressionAndCompare("$.mapBin1.{=100}.{}.count() > 0", expected);
+ parseExpAndCompare("$.mapBin1.{=100}.count() > 0", expected);
+ parseExpAndCompare("$.mapBin1.{=100}.{}.count() > 0", expected);
}
@Test
@@ -229,10 +229,10 @@ void mapByRank() {
Exp.mapBin("mapBin1")
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.{#-1} == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{#-1}.get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{#-1}.get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.{#-1}.asInt() == 100", expected);
+ parseExpAndCompare("$.mapBin1.{#-1} == 100", expected);
+ parseExpAndCompare("$.mapBin1.{#-1}.get(type: INT) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{#-1}.get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.mapBin1.{#-1}.asInt() == 100", expected);
}
@Test
@@ -246,10 +246,10 @@ void mapByRankWithNesting() {
CTX.mapKey(Value.get("a"))
),
Exp.val(100));
- parseExpressionAndCompare("$.mapBin1.a.{#-1} == 100", expected);
- parseExpressionAndCompare("$.mapBin1.a.{#-1}.get(type: INT) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.a.{#-1}.get(type: INT, return: VALUE) == 100", expected);
- parseExpressionAndCompare("$.mapBin1.a.{#-1}.asInt() == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.{#-1} == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.{#-1}.get(type: INT) == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.{#-1}.get(type: INT, return: VALUE) == 100", expected);
+ parseExpAndCompare("$.mapBin1.a.{#-1}.asInt() == 100", expected);
}
@Test
@@ -265,8 +265,8 @@ void nestedListsWithDifferentContextTypes() {
),
Exp.val("stringVal"));
// Implicit detect as String
- parseExpressionAndCompare("$.mapBin1.{5}.{#-1} == \"stringVal\"", expected);
- parseExpressionAndCompare("$.mapBin1.{5}.{#-1}.get(type: STRING) == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.{5}.{#-1} == \"stringVal\"", expected);
+ parseExpAndCompare("$.mapBin1.{5}.{#-1}.get(type: STRING) == \"stringVal\"", expected);
// Nested List Rank Value
expected = Exp.eq(
@@ -278,7 +278,7 @@ void nestedListsWithDifferentContextTypes() {
CTX.mapRank(-1)
),
Exp.val(200));
- parseExpressionAndCompare("$.mapBin1.{5}.{#-1}.{=100} == 200", expected);
+ parseExpAndCompare("$.mapBin1.{5}.{#-1}.{=100} == 200", expected);
}
@Test
@@ -288,8 +288,8 @@ void mapKeyRange() {
Exp.val("a"),
Exp.val("c"),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{a-c}", expected);
- parseExpressionAndCompare("$.mapBin1.{\"a\"-\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{a-c}", expected);
+ parseExpAndCompare("$.mapBin1.{\"a\"-\"c\"}", expected);
// Inverted
expected = MapExp.getByKeyRange(
@@ -297,8 +297,8 @@ void mapKeyRange() {
Exp.val("a"),
Exp.val("c"),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!a-c}", expected);
- parseExpressionAndCompare("$.mapBin1.{!\"a\"-\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{!a-c}", expected);
+ parseExpAndCompare("$.mapBin1.{!\"a\"-\"c\"}", expected);
// From start till the end
expected = MapExp.getByKeyRange(
@@ -306,8 +306,8 @@ void mapKeyRange() {
Exp.val("a"),
null,
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{a-}", expected);
- parseExpressionAndCompare("$.mapBin1.{\"a\"-}", expected);
+ parseExpAndCompare("$.mapBin1.{a-}", expected);
+ parseExpAndCompare("$.mapBin1.{\"a\"-}", expected);
}
@Test
@@ -316,16 +316,16 @@ void mapKeyList() {
MapReturnType.VALUE,
Exp.val(List.of("a", "b", "c")),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{a,b,c}", expected);
- parseExpressionAndCompare("$.mapBin1.{\"a\",\"b\",\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{a,b,c}", expected);
+ parseExpAndCompare("$.mapBin1.{\"a\",\"b\",\"c\"}", expected);
// Inverted
expected = MapExp.getByKeyList(
MapReturnType.VALUE | MapReturnType.INVERTED,
Exp.val(List.of("a", "b", "c")),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!a,b,c}", expected);
- parseExpressionAndCompare("$.mapBin1.{!\"a\",\"b\",\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{!a,b,c}", expected);
+ parseExpAndCompare("$.mapBin1.{!\"a\",\"b\",\"c\"}", expected);
}
@Test
@@ -335,7 +335,7 @@ void mapIndexRange() {
Exp.val(1),
Exp.val(2),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{1:3}", expected);
+ parseExpAndCompare("$.mapBin1.{1:3}", expected);
// Negative
expected = MapExp.getByIndexRange(
@@ -343,7 +343,7 @@ void mapIndexRange() {
Exp.val(-3),
Exp.val(4),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{-3:1}", expected);
+ parseExpAndCompare("$.mapBin1.{-3:1}", expected);
// Inverted
expected = MapExp.getByIndexRange(
@@ -351,14 +351,14 @@ void mapIndexRange() {
Exp.val(2),
Exp.val(2),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!2:4}", expected);
+ parseExpAndCompare("$.mapBin1.{!2:4}", expected);
// From start till the end
expected = MapExp.getByIndexRange(
MapReturnType.VALUE,
Exp.val(1),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{1:}", expected);
+ parseExpAndCompare("$.mapBin1.{1:}", expected);
}
@Test
@@ -367,23 +367,23 @@ void mapValueList() {
MapReturnType.VALUE,
Exp.val(List.of("a", "b", "c")),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{=a,b,c}", expected);
- parseExpressionAndCompare("$.mapBin1.{=\"a\",\"b\",\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{=a,b,c}", expected);
+ parseExpAndCompare("$.mapBin1.{=\"a\",\"b\",\"c\"}", expected);
// Integer
expected = MapExp.getByValueList(
MapReturnType.VALUE,
Exp.val(List.of(1, 2, 3)),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{=1,2,3}", expected);
+ parseExpAndCompare("$.mapBin1.{=1,2,3}", expected);
// Inverted
expected = MapExp.getByValueList(
MapReturnType.VALUE | MapReturnType.INVERTED,
Exp.val(List.of("a", "b", "c")),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!=a,b,c}", expected);
- parseExpressionAndCompare("$.mapBin1.{!=\"a\",\"b\",\"c\"}", expected);
+ parseExpAndCompare("$.mapBin1.{!=a,b,c}", expected);
+ parseExpAndCompare("$.mapBin1.{!=\"a\",\"b\",\"c\"}", expected);
}
@Test
@@ -393,7 +393,7 @@ void mapValueRange() {
Exp.val(111),
Exp.val(334),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{=111:334}", expected);
+ parseExpAndCompare("$.mapBin1.{=111:334}", expected);
// Inverted
expected = MapExp.getByValueRange(
@@ -401,7 +401,7 @@ void mapValueRange() {
Exp.val(10),
Exp.val(20),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!=10:20}", expected);
+ parseExpAndCompare("$.mapBin1.{!=10:20}", expected);
// From start till the end
expected = MapExp.getByValueRange(
@@ -409,7 +409,7 @@ void mapValueRange() {
Exp.val(111),
null,
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{=111:}", expected);
+ parseExpAndCompare("$.mapBin1.{=111:}", expected);
}
@Test
@@ -419,7 +419,7 @@ void mapRankRange() {
Exp.val(0),
Exp.val(3),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{#0:3}", expected);
+ parseExpAndCompare("$.mapBin1.{#0:3}", expected);
// Inverted
expected = MapExp.getByRankRange(
@@ -427,14 +427,14 @@ void mapRankRange() {
Exp.val(0),
Exp.val(3),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!#0:3}", expected);
+ parseExpAndCompare("$.mapBin1.{!#0:3}", expected);
// From start till the end
expected = MapExp.getByRankRange(
MapReturnType.VALUE,
Exp.val(-3),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{#-3:}", expected);
+ parseExpAndCompare("$.mapBin1.{#-3:}", expected);
// From start till the end with context
expected = MapExp.getByRankRange(
@@ -442,7 +442,7 @@ void mapRankRange() {
Exp.val(-3),
Exp.mapBin("mapBin1"),
CTX.mapIndex(5));
- parseExpressionAndCompare("$.mapBin1.{5}.{#-3:}", expected);
+ parseExpAndCompare("$.mapBin1.{5}.{#-3:}", expected);
}
@Test
@@ -453,7 +453,7 @@ void mapRankRangeRelative() {
Exp.val(10),
Exp.val(2),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{#-1:1~10}", expected);
+ parseExpAndCompare("$.mapBin1.{#-1:1~10}", expected);
// Inverted
expected = MapExp.getByValueRelativeRankRange(
@@ -462,7 +462,7 @@ void mapRankRangeRelative() {
Exp.val(10),
Exp.val(2),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!#-1:1~10}", expected);
+ parseExpAndCompare("$.mapBin1.{!#-1:1~10}", expected);
// From start till the end
expected = MapExp.getByValueRelativeRankRange(
@@ -470,7 +470,7 @@ void mapRankRangeRelative() {
Exp.val(-2),
Exp.val(10),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{#-2:~10}", expected);
+ parseExpAndCompare("$.mapBin1.{#-2:~10}", expected);
}
@Test
@@ -481,7 +481,7 @@ void mapIndexRangeRelative() {
Exp.val(0),
Exp.val(1),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{0:1~a}", expected);
+ parseExpAndCompare("$.mapBin1.{0:1~a}", expected);
// Inverted
expected = MapExp.getByKeyRelativeIndexRange(
@@ -490,7 +490,7 @@ void mapIndexRangeRelative() {
Exp.val(0),
Exp.val(1),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{!0:1~a}", expected);
+ parseExpAndCompare("$.mapBin1.{!0:1~a}", expected);
// From start till the end
expected = MapExp.getByKeyRelativeIndexRange(
@@ -498,7 +498,7 @@ void mapIndexRangeRelative() {
Exp.val("a"),
Exp.val(0),
Exp.mapBin("mapBin1"));
- parseExpressionAndCompare("$.mapBin1.{0:~a}", expected);
+ parseExpAndCompare("$.mapBin1.{0:~a}", expected);
}
@Test
@@ -512,7 +512,7 @@ void mapReturnTypes() {
),
Exp.val(5));
// Implicit detect as Int
- parseExpressionAndCompare("$.mapBin1.a.get(type: INT, return: COUNT) == 5", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: INT, return: COUNT) == 5", expected);
expected = MapExp.getByKey(
MapReturnType.ORDERED_MAP,
@@ -521,7 +521,7 @@ void mapReturnTypes() {
Exp.mapBin("mapBin1")
);
// Implicit detect as Int
- parseExpressionAndCompare("$.mapBin1.a.get(return: ORDERED_MAP)", expected);
+ parseExpAndCompare("$.mapBin1.a.get(return: ORDERED_MAP)", expected);
expected = Exp.eq(
MapExp.getByKey(
@@ -532,6 +532,6 @@ void mapReturnTypes() {
),
Exp.val(5));
// Implicit detect as Int
- parseExpressionAndCompare("$.mapBin1.a.get(type: INT, return: RANK) == 5", expected);
+ parseExpAndCompare("$.mapBin1.a.get(type: INT, return: RANK) == 5", expected);
}
}
diff --git a/src/test/java/com/aerospike/dsl/expression/RecordMetadataTests.java b/src/test/java/com/aerospike/dsl/expression/RecordMetadataTests.java
index ca59c28..5f7557e 100644
--- a/src/test/java/com/aerospike/dsl/expression/RecordMetadataTests.java
+++ b/src/test/java/com/aerospike/dsl/expression/RecordMetadataTests.java
@@ -1,11 +1,11 @@
package com.aerospike.dsl.expression;
import com.aerospike.client.exp.Exp;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseExpression;
-import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseExp;
+import static com.aerospike.dsl.util.TestUtils.parseExpAndCompare;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class RecordMetadataTests {
@@ -15,7 +15,7 @@ void deviceSize() {
// Expression to find records that occupy more than 1 MiB of storage space
String input = "$.deviceSize() > 1048576";
Exp expected = Exp.gt(Exp.deviceSize(), Exp.val(1024 * 1024));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -23,7 +23,7 @@ void memorySize() {
// Expression to find records that occupy more than 1 MiB of memory
String input = "$.memorySize() > 1048576";
Exp expected = Exp.gt(Exp.memorySize(), Exp.val(1024 * 1024));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -31,7 +31,7 @@ void recordSize() {
// Expression to find records that occupy more than 1 MiB of memory
String input = "$.recordSize() > 1048576";
Exp expected = Exp.gt(Exp.recordSize(), Exp.val(1024 * 1024));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -39,12 +39,12 @@ void digestModulo() {
// Expression to find records where digest mod 3 equals 0
String input = "$.digestModulo(3) == 0";
Exp expected = Exp.eq(Exp.digestModulo(3), Exp.val(0));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
// Expression to find records where digest mod 3 equals the value stored in the bin called "digestModulo"
String input2 = "$.digestModulo(3) == $.digestModulo";
Exp expected2 = Exp.eq(Exp.digestModulo(3), Exp.intBin("digestModulo"));
- parseExpressionAndCompare(input2, expected2);
+ parseExpAndCompare(input2, expected2);
}
@Test
@@ -52,7 +52,7 @@ void isTombstone() {
// Expression to find records that are tombstones
String input = "$.isTombstone()";
Exp expected = Exp.isTombstone();
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -60,7 +60,7 @@ void keyExists() {
// Expression to find records that has a stored key
String input = "$.keyExists()";
Exp expected = Exp.keyExists();
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
// Comparing Metadata to a Bin
@@ -69,12 +69,12 @@ void lastUpdate() {
// Expression to find records where the last-update-time is less than bin 'updateBy'
String inputMetadataLeft = "$.lastUpdate() < $.updateBy";
Exp expectedLeft = Exp.lt(Exp.lastUpdate(), Exp.intBin("updateBy"));
- parseExpressionAndCompare(inputMetadataLeft, expectedLeft);
+ parseExpAndCompare(inputMetadataLeft, expectedLeft);
// Expression to find records where the last-update-time is less than bin 'updateBy'
String inputMetadataRight = "$.updateBy > $.lastUpdate()";
Exp expectedRight = Exp.gt(Exp.intBin("updateBy"), Exp.lastUpdate());
- parseExpressionAndCompare(inputMetadataRight, expectedRight);
+ parseExpAndCompare(inputMetadataRight, expectedRight);
}
@Test
@@ -82,22 +82,22 @@ void sinceUpdate() {
// Expression to find records that were updated within the last 2 hours
String input = "$.sinceUpdate() < 7200000";
Exp expected = Exp.lt(Exp.sinceUpdate(), Exp.val(2 * 60 * 60 * 1000));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
// Expression to find records that were update within the value stored in the bin called "intBin"
String input2 = "$.sinceUpdate() < $.intBin";
Exp expected2 = Exp.lt(Exp.sinceUpdate(), Exp.intBin("intBin"));
- parseExpressionAndCompare(input2, expected2);
+ parseExpAndCompare(input2, expected2);
// Expression to find records that were updated within the value stored in the bin called "sinceUpdate"
String input3 = "$.sinceUpdate() < $.sinceUpdate";
Exp expected3 = Exp.lt(Exp.sinceUpdate(), Exp.intBin("sinceUpdate"));
- parseExpressionAndCompare(input3, expected3);
+ parseExpAndCompare(input3, expected3);
// Expression to find records that were updated within the value stored in the bin called "sinceUpdate"
String input4 = "$.sinceUpdate > $.sinceUpdate()";
Exp expected4 = Exp.gt(Exp.intBin("sinceUpdate"), Exp.sinceUpdate());
- parseExpressionAndCompare(input4, expected4);
+ parseExpAndCompare(input4, expected4);
}
@Test
@@ -108,12 +108,12 @@ void setName() {
Exp.eq(Exp.setName(), Exp.val("groupA")),
Exp.eq(Exp.setName(), Exp.val("groupB"))
);
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
// set name compared with String Bin
input = "$.mySetBin == $.setName()";
expected = Exp.eq(Exp.stringBin("mySetBin"), Exp.setName());
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -121,14 +121,14 @@ void ttl() {
// Expression to find records that will expire within 24 hours
String input = "$.ttl() <= 86400";
Exp expected = Exp.le(Exp.ttl(), Exp.val(24 * 60 * 60));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
//@Test
void negativeTtlAsDifferentType() {
// TODO: should be supported when adding operator + metadata validations (requires a refactor)
- assertThatThrownBy(() -> parseExpression("$.ttl() == true"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseExp("$.ttl() == true"))
+ .isInstanceOf(DslParseException.class)
.hasMessageContaining("Expecting non-bin operand, got BOOL_OPERAND");
}
@@ -137,7 +137,7 @@ void voidTime() {
// Expression to find records where the void-time is set to 'never expire'
String input = "$.voidTime() == -1";
Exp expected = Exp.eq(Exp.voidTime(), Exp.val(-1));
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
@Test
@@ -148,7 +148,7 @@ void metadataWithLogicalOperatorsExpressions() {
Exp.gt(Exp.deviceSize(), Exp.val(1024)),
Exp.lt(Exp.ttl(), Exp.val(300))
);
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
// test OR
String input2 = "$.deviceSize() > 1024 or $.ttl() < 300";
@@ -156,7 +156,7 @@ void metadataWithLogicalOperatorsExpressions() {
Exp.gt(Exp.deviceSize(), Exp.val(1024)),
Exp.lt(Exp.ttl(), Exp.val(300))
);
- parseExpressionAndCompare(input2, expected2);
+ parseExpAndCompare(input2, expected2);
}
@Test
@@ -166,13 +166,13 @@ void metadataAsExpressionWithLogicalOperator() {
Exp.isTombstone(),
Exp.lt(Exp.ttl(), Exp.val(300))
);
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
input = "$.ttl() < 300 or $.keyExists()";
expected = Exp.or(
Exp.lt(Exp.ttl(), Exp.val(300)),
Exp.keyExists()
);
- parseExpressionAndCompare(input, expected);
+ parseExpAndCompare(input, expected);
}
}
diff --git a/src/test/java/com/aerospike/dsl/filter/ArithmeticFiltersTests.java b/src/test/java/com/aerospike/dsl/filter/ArithmeticFiltersTests.java
index c5e3cef..f2aa56d 100644
--- a/src/test/java/com/aerospike/dsl/filter/ArithmeticFiltersTests.java
+++ b/src/test/java/com/aerospike/dsl/filter/ArithmeticFiltersTests.java
@@ -1,376 +1,319 @@
package com.aerospike.dsl.filter;
import com.aerospike.client.query.Filter;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.client.query.IndexType;
+import com.aerospike.dsl.Index;
+import com.aerospike.dsl.IndexContext;
+import com.aerospike.dsl.DslParseException;
import org.junit.jupiter.api.Test;
+import java.util.Collection;
import java.util.List;
-import static com.aerospike.dsl.util.TestUtils.parseFilters;
-import static com.aerospike.dsl.util.TestUtils.parseFiltersAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseFilter;
+import static com.aerospike.dsl.util.TestUtils.parseFilterAndCompare;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class ArithmeticFiltersTests {
+ String NAMESPACE = "test1";
+ Collection INDEXES = List.of(
+ Index.builder().namespace("test1").bin("apples").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("bananas").indexType(IndexType.NUMERIC).binValuesRatio(1).build()
+ );
+ IndexContext INDEX_FILTER_INPUT = IndexContext.of(NAMESPACE, INDEXES);
+
@Test
void add() {
- assertThatThrownBy(() -> parseFilters("($.apples + $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- parseFiltersAndCompare("($.apples + 5) > 10",
- List.of(Filter.range("apples", 10 - 5 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples + 5) >= 10",
- List.of(Filter.range("apples", 10 - 5, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples + 5) < 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 - 5 - 1)));
- parseFiltersAndCompare("($.apples + 5) <= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 - 5)));
-
- parseFiltersAndCompare("(9 + $.bananas) > 10",
- List.of(Filter.range("bananas", 10 - 9 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("(9 + $.bananas) >= 10",
- List.of(Filter.range("bananas", 10 - 9, Long.MAX_VALUE)));
- parseFiltersAndCompare("(9 + $.bananas) < 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 10 - 9 - 1)));
- parseFiltersAndCompare("(9 + $.bananas) <= 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 10 - 9)));
-
- assertThatThrownBy(() -> parseFilters("(5.2 + $.bananas) > 10.2"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("($.apples + $.bananas + 5) > 10"))
- .isInstanceOf(AerospikeDSLException.class) // not supported by the current grammar
- .hasMessageContaining("Could not parse given input, wrong syntax");
+ // not supported by secondary index filter
+ assertThat(parseFilter("($.apples + $.bananas) > 10", INDEX_FILTER_INPUT)).isNull();
+
+ parseFilterAndCompare("($.apples + 5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 - 5 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples + 5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 - 5, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples + 5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 - 5 - 1));
+ parseFilterAndCompare("($.apples + 5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 - 5));
+
+ parseFilterAndCompare("(9 + $.bananas) > 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 10 - 9 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("(9 + $.bananas) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 10 - 9, Long.MAX_VALUE));
+ parseFilterAndCompare("(9 + $.bananas) < 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 10 - 9 - 1));
+ parseFilterAndCompare("(9 + $.bananas) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 10 - 9));
+
+ assertThat(parseFilter("(5.2 + $.bananas) > 10.2")).isNull(); // not supported by secondary index filter
+ assertThatThrownBy(() -> parseFilter("($.apples + $.bananas + 5) > 10"))
+ .isInstanceOf(DslParseException.class) // not supported by the current grammar
+ .hasMessageContaining("Could not parse given DSL expression input");
}
@Test
void sub() {
- assertThatThrownBy(() -> parseFilters("($.apples - $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- parseFiltersAndCompare("($.apples - 5) > 10",
- List.of(Filter.range("apples", 10 + 5 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples - 5) >= 10",
- List.of(Filter.range("apples", 10 + 5, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples - 5) < 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 + 5 - 1)));
- parseFiltersAndCompare("($.apples - 5) <= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 + 5)));
-
- parseFiltersAndCompare("($.apples - 5) > -10",
- List.of(Filter.range("apples", -10 + 5 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples - 5) >= -10",
- List.of(Filter.range("apples", -10 + 5, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples - 5) < -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -10 + 5 - 1)));
- parseFiltersAndCompare("($.apples - 5) <= -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -10 + 5)));
-
- parseFiltersAndCompare("(9 - $.bananas) > 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 9 - 10 - 1)));
- parseFiltersAndCompare("(9 - $.bananas) >= 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 9 - 10)));
- parseFiltersAndCompare("(9 - $.bananas) < 10",
- List.of(Filter.range("bananas", 9 - 10 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("(9 - $.bananas) <= 10",
- List.of(Filter.range("bananas", 9 - 10, Long.MAX_VALUE)));
-
- assertThatThrownBy(() -> parseFilters("($.apples - $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("($.apples - $.bananas - 5) > 10"))
- .isInstanceOf(AerospikeDSLException.class) // not supported by the current grammar
- .hasMessageContaining("Could not parse given input, wrong syntax");
+ assertThat(parseFilter("($.apples - $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // not supported by secondary index filter
+
+ parseFilterAndCompare("($.apples - 5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 + 5 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples - 5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 + 5, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples - 5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 + 5 - 1));
+ parseFilterAndCompare("($.apples - 5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 + 5));
+
+ parseFilterAndCompare("($.apples - 5) > -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 + 5 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples - 5) >= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 + 5, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples - 5) < -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -10 + 5 - 1));
+ parseFilterAndCompare("($.apples - 5) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -10 + 5));
+
+ parseFilterAndCompare("(9 - $.bananas) > 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 9 - 10 - 1));
+ parseFilterAndCompare("(9 - $.bananas) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 9 - 10));
+ parseFilterAndCompare("(9 - $.bananas) < 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 9 - 10 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("(9 - $.bananas) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 9 - 10, Long.MAX_VALUE));
+
+ assertThat(parseFilter("($.apples - $.bananas) > 10")).isNull(); // not supported by secondary index filter
+ assertThatThrownBy(() -> parseFilter("($.apples - $.bananas - 5) > 10"))
+ .isInstanceOf(DslParseException.class) // not supported by the current grammar
+ .hasMessageContaining("Could not parse given DSL expression input");
}
@Test
void mul() {
- assertThatThrownBy(() -> parseFilters("($.apples * $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- parseFiltersAndCompare("($.apples * 5) > 10",
- List.of(Filter.range("apples", 10 / 5 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples * 5) >= 10",
- List.of(Filter.range("apples", 10 / 5, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples * 5) < 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 / 5 - 1)));
- parseFiltersAndCompare("($.apples * 5) <= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 / 5)));
-
- parseFiltersAndCompare("(9 * $.bananas) > 10",
- List.of(Filter.range("bananas", 10 / 9 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("(9 * $.bananas) >= 10",
- List.of(Filter.range("bananas", 10 / 9, Long.MAX_VALUE)));
- parseFiltersAndCompare("(9 * $.bananas) < 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 10 / 9)));
- parseFiltersAndCompare("(9 * $.bananas) <= 10",
- List.of(Filter.range("bananas", Long.MIN_VALUE, 10 / 9)));
-
- parseFiltersAndCompare("($.apples * -5) > 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 / -5 - 1)));
- parseFiltersAndCompare("($.apples * -5) >= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 10 / -5)));
- parseFiltersAndCompare("($.apples * -5) < 10",
- List.of(Filter.range("apples", 10 / -5 + 1, Long.MAX_VALUE)));
- parseFiltersAndCompare("($.apples * -5) <= 10",
- List.of(Filter.range("apples", 10 / -5, Long.MAX_VALUE)));
-
- assertThatThrownBy(() -> parseFilters("(0 * $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class) // not supported by the current grammar
- .hasMessageContaining("Cannot divide by zero");
-
- parseFiltersAndCompare("(9 * $.bananas) > 0",
- List.of(Filter.range("bananas", 0 / 9 + 1, Long.MAX_VALUE)));
-
- assertThatThrownBy(() -> parseFilters("($.apples * $.bananas - 5) > 10"))
- .isInstanceOf(AerospikeDSLException.class) // not supported by the current grammar
- .hasMessageContaining("Could not parse given input, wrong syntax");
+ assertThat(parseFilter("($.apples * $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // not supported by secondary index filter
+
+ parseFilterAndCompare("($.apples * 5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 / 5 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples * 5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 / 5, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples * 5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 / 5 - 1));
+ parseFilterAndCompare("($.apples * 5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 / 5));
+
+ parseFilterAndCompare("(9 * $.bananas) > 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 10 / 9 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("(9 * $.bananas) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 10 / 9, Long.MAX_VALUE));
+ parseFilterAndCompare("(9 * $.bananas) < 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 10 / 9));
+ parseFilterAndCompare("(9 * $.bananas) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", Long.MIN_VALUE, 10 / 9));
+
+ parseFilterAndCompare("($.apples * -5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 / -5 - 1));
+ parseFilterAndCompare("($.apples * -5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 10 / -5));
+ parseFilterAndCompare("($.apples * -5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 / -5 + 1, Long.MAX_VALUE));
+ parseFilterAndCompare("($.apples * -5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 10 / -5, Long.MAX_VALUE));
+
+ assertThat(parseFilter("(0 * $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // Cannot divide by zero
+
+ parseFilterAndCompare("(9 * $.bananas) > 0", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 0 / 9 + 1, Long.MAX_VALUE));
+
+ assertThatThrownBy(() -> parseFilter("($.apples * $.bananas - 5) > 10"))
+ .isInstanceOf(DslParseException.class) // not supported by the current grammar
+ .hasMessageContaining("Could not parse given DSL expression input");
}
@Test
void div_twoBins() {
- assertThatThrownBy(() -> parseFilters("($.apples / $.bananas) <= 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
+ assertThat(parseFilter("($.apples / $.bananas) <= 10", INDEX_FILTER_INPUT)).isNull(); // not supported by secondary index filter
}
@Test
void div_binIsDivided_leftNumberIsLarger() {
- parseFiltersAndCompare("($.apples / 50) > 10",
- List.of(Filter.range("apples", 50 * 10 + 1, Long.MAX_VALUE))); // [501, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 50) >= 10",
- List.of(Filter.range("apples", 50 * 10, Long.MAX_VALUE))); // [500, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 50) < 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 50 * 10 - 1))); // [-2^63, 499]
- parseFiltersAndCompare("($.apples / 50) <= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 50 * 10))); // [-2^63, 500]
-
- parseFiltersAndCompare("($.apples / -50) > 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -50 * 10 - 1))); // [-2^63, -501]
- parseFiltersAndCompare("($.apples / -50) >= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -50 * 10))); // [-2^63, -500]
- parseFiltersAndCompare("($.apples / -50) < 10",
- List.of(Filter.range("apples", -50 * 10 + 1, Long.MAX_VALUE))); // [-499, 2^63 - 1]
- parseFiltersAndCompare("($.apples / -50) <= 10",
- List.of(Filter.range("apples", -50 * 10, Long.MAX_VALUE))); // [-500, 2^63 - 1]
-
- parseFiltersAndCompare("($.apples / 50) > -10",
- List.of(Filter.range("apples", 50 * -10 + 1, Long.MAX_VALUE))); // [-499, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 50) >= -10",
- List.of(Filter.range("apples", 50 * -10, Long.MAX_VALUE))); // [-500, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 50) < -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 50 * -10 - 1))); // [-2^63, -501]
- parseFiltersAndCompare("($.apples / 50) <= -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 50 * -10))); // [-2^63, -500]
-
- parseFiltersAndCompare("($.apples / -50) > -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -50 * -10 - 1))); // [-2^63, 499]
- parseFiltersAndCompare("($.apples / -50) >= -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -10 * -50))); // [-2^63, 500]
- parseFiltersAndCompare("($.apples / -50) < -10",
- List.of(Filter.range("apples", -10 * -50 + 1, Long.MAX_VALUE))); // [501, 2^63 - 1]
- parseFiltersAndCompare("($.apples / -50) <= -10",
- List.of(Filter.range("apples", -10 * -50, Long.MAX_VALUE))); // [500, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 50) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 50 * 10 + 1, Long.MAX_VALUE)); // [501, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 50) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 50 * 10, Long.MAX_VALUE)); // [500, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 50) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 50 * 10 - 1)); // [-2^63, 499]
+ parseFilterAndCompare("($.apples / 50) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 50 * 10)); // [-2^63, 500]
+
+ parseFilterAndCompare("($.apples / -50) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -50 * 10 - 1)); // [-2^63, -501]
+ parseFilterAndCompare("($.apples / -50) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -50 * 10)); // [-2^63, -500]
+ parseFilterAndCompare("($.apples / -50) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -50 * 10 + 1, Long.MAX_VALUE)); // [-499, 2^63 - 1]
+ parseFilterAndCompare("($.apples / -50) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -50 * 10, Long.MAX_VALUE)); // [-500, 2^63 - 1]
+
+ parseFilterAndCompare("($.apples / 50) > -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 50 * -10 + 1, Long.MAX_VALUE)); // [-499, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 50) >= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 50 * -10, Long.MAX_VALUE)); // [-500, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 50) < -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 50 * -10 - 1)); // [-2^63, -501]
+ parseFilterAndCompare("($.apples / 50) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 50 * -10)); // [-2^63, -500]
+
+ parseFilterAndCompare("($.apples / -50) > -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -50 * -10 - 1)); // [-2^63, 499]
+ parseFilterAndCompare("($.apples / -50) >= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -10 * -50)); // [-2^63, 500]
+ parseFilterAndCompare("($.apples / -50) < -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 * -50 + 1, Long.MAX_VALUE)); // [501, 2^63 - 1]
+ parseFilterAndCompare("($.apples / -50) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 * -50, Long.MAX_VALUE)); // [500, 2^63 - 1]
}
@Test
void div_binIsDivided_leftNumberIsSmaller() {
- parseFiltersAndCompare("($.apples / 5) > 10",
- List.of(Filter.range("apples", 5 * 10 + 1, Long.MAX_VALUE))); // [51, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) >= 10",
- List.of(Filter.range("apples", 5 * 10, Long.MAX_VALUE))); // [50, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) < 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * 10 - 1))); // [-2^63, 49]
- parseFiltersAndCompare("($.apples / 5) <= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * 10))); // [-2^63, 50]
-
- parseFiltersAndCompare("($.apples / -5) > 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -5 * 10 - 1))); // [-2^63, -51]
- parseFiltersAndCompare("($.apples / -5) >= 10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -5 * 10))); // [-2^63, -50]
- parseFiltersAndCompare("($.apples / -5) < 10",
- List.of(Filter.range("apples", -5 * 10 + 1, Long.MAX_VALUE))); // [-49, 2^63 - 1]
- parseFiltersAndCompare("($.apples / -5) <= 10",
- List.of(Filter.range("apples", -5 * 10, Long.MAX_VALUE))); // [-50, 2^63 - 1]
-
- parseFiltersAndCompare("($.apples / 5) > -10",
- List.of(Filter.range("apples", 5 * -10 + 1, Long.MAX_VALUE))); // [-49, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) >= -10",
- List.of(Filter.range("apples", 5 * -10, Long.MAX_VALUE))); // [-50, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) < -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * -10 - 1))); // [-2^63, -51]
- parseFiltersAndCompare("($.apples / 5) <= -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * -10))); // [-2^63, -50]
-
- parseFiltersAndCompare("($.apples / -5) > -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -5 * -10 - 1))); // [-2^63, 49]
- parseFiltersAndCompare("($.apples / -5) >= -10",
- List.of(Filter.range("apples", Long.MIN_VALUE, -10 * -5))); // [-2^63, 50]
- parseFiltersAndCompare("($.apples / -5) < -10",
- List.of(Filter.range("apples", -10 * -5 + 1, Long.MAX_VALUE))); // [51, 2^63 - 1]
- parseFiltersAndCompare("($.apples / -5) <= -10",
- List.of(Filter.range("apples", -10 * -5, Long.MAX_VALUE))); // [50, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * 10 + 1, Long.MAX_VALUE)); // [51, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * 10, Long.MAX_VALUE)); // [50, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * 10 - 1)); // [-2^63, 49]
+ parseFilterAndCompare("($.apples / 5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * 10)); // [-2^63, 50]
+
+ parseFilterAndCompare("($.apples / -5) > 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -5 * 10 - 1)); // [-2^63, -51]
+ parseFilterAndCompare("($.apples / -5) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -5 * 10)); // [-2^63, -50]
+ parseFilterAndCompare("($.apples / -5) < 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -5 * 10 + 1, Long.MAX_VALUE)); // [-49, 2^63 - 1]
+ parseFilterAndCompare("($.apples / -5) <= 10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -5 * 10, Long.MAX_VALUE)); // [-50, 2^63 - 1]
+
+ parseFilterAndCompare("($.apples / 5) > -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * -10 + 1, Long.MAX_VALUE)); // [-49, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) >= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * -10, Long.MAX_VALUE)); // [-50, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) < -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * -10 - 1)); // [-2^63, -51]
+ parseFilterAndCompare("($.apples / 5) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * -10)); // [-2^63, -50]
+
+ parseFilterAndCompare("($.apples / -5) > -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -5 * -10 - 1)); // [-2^63, 49]
+ parseFilterAndCompare("($.apples / -5) >= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -10 * -5)); // [-2^63, 50]
+ parseFilterAndCompare("($.apples / -5) < -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 * -5 + 1, Long.MAX_VALUE)); // [51, 2^63 - 1]
+ parseFilterAndCompare("($.apples / -5) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("apples", -10 * -5, Long.MAX_VALUE)); // [50, 2^63 - 1]
}
@Test
void div_binIsDivided_leftNumberEqualsRight() {
- parseFiltersAndCompare("($.apples / 5) > 5",
- List.of(Filter.range("apples", 5 * 5 + 1, Long.MAX_VALUE))); // [26, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) >= 5",
- List.of(Filter.range("apples", 5 * 5, Long.MAX_VALUE))); // [25, 2^63 - 1]
- parseFiltersAndCompare("($.apples / 5) < 5",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * 5 - 1))); // [-2^63, 24]
- parseFiltersAndCompare("($.apples / 5) <= 5",
- List.of(Filter.range("apples", Long.MIN_VALUE, 5 * 5))); // [-2^63, 25]
-
- parseFiltersAndCompare("($.apples / -5) > -5",
- List.of(Filter.range("apples", Long.MIN_VALUE, -5 * -5 - 1))); // [-2^63, 24]
- parseFiltersAndCompare("($.apples / -5) >= -5",
- List.of(Filter.range("apples", Long.MIN_VALUE, -5 * -5))); // [-2^63, 25]
- parseFiltersAndCompare("($.apples / -5) < -5",
- List.of(Filter.range("apples", -5 * -5 + 1, Long.MAX_VALUE))); // [26, 2^63 - 1]
- parseFiltersAndCompare("($.apples / -5) <= -5",
- List.of(Filter.range("apples", -5 * -5, Long.MAX_VALUE))); // [25, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) > 5", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * 5 + 1, Long.MAX_VALUE)); // [26, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) >= 5", INDEX_FILTER_INPUT,
+ Filter.range("apples", 5 * 5, Long.MAX_VALUE)); // [25, 2^63 - 1]
+ parseFilterAndCompare("($.apples / 5) < 5", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * 5 - 1)); // [-2^63, 24]
+ parseFilterAndCompare("($.apples / 5) <= 5", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, 5 * 5)); // [-2^63, 25]
+
+ parseFilterAndCompare("($.apples / -5) > -5", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -5 * -5 - 1)); // [-2^63, 24]
+ parseFilterAndCompare("($.apples / -5) >= -5", INDEX_FILTER_INPUT,
+ Filter.range("apples", Long.MIN_VALUE, -5 * -5)); // [-2^63, 25]
+ parseFilterAndCompare("($.apples / -5) < -5", INDEX_FILTER_INPUT,
+ Filter.range("apples", -5 * -5 + 1, Long.MAX_VALUE)); // [26, 2^63 - 1]
+ parseFilterAndCompare("($.apples / -5) <= -5", INDEX_FILTER_INPUT,
+ Filter.range("apples", -5 * -5, Long.MAX_VALUE)); // [25, 2^63 - 1]
}
@Test
void div_binIsDivisor_leftNumberIsLarger() {
- parseFiltersAndCompare("(90 / $.bananas) > 10",
- List.of(Filter.range("bananas", 1, 90 / 10 - 1))); // [1,8]
- parseFiltersAndCompare("(90 / $.bananas) >= 10",
- List.of(Filter.range("bananas", 1, 90 / 10))); // [1,9]
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) < 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) <= 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) > -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) >= -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- parseFiltersAndCompare("(90 / $.bananas) < -10",
- List.of(Filter.range("bananas", 90 / -10 + 1, -1))); // [-8, -1]
- parseFiltersAndCompare("(90 / $.bananas) <= -10",
- List.of(Filter.range("bananas", 90 / -10, -1))); // [-8, -1]
-
- parseFiltersAndCompare("(-90 / $.bananas) > 10",
- List.of(Filter.range("bananas", -90 / 10 + 1, -1))); // [-8, -1]
- parseFiltersAndCompare("(90 / $.bananas) >= 10",
- List.of(Filter.range("bananas", 1, 90 / 10))); // [1,9]
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) < 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) <= 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) > -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) >= -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- parseFiltersAndCompare("(-90 / $.bananas) < -10",
- List.of(Filter.range("bananas", 1L, -90 / -10 - 1))); // [1, 8]
- parseFiltersAndCompare("(-90 / $.bananas) <= -10",
- List.of(Filter.range("bananas", 1L, -90 / -10))); // [1, 9]
+ parseFilterAndCompare("(90 / $.bananas) > 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1, 90 / 10 - 1)); // [1,8]
+ parseFilterAndCompare("(90 / $.bananas) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1, 90 / 10)); // [1,9]
+
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(90 / $.bananas) < 10", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("(90 / $.bananas) <= 10", INDEX_FILTER_INPUT)).isNull();
+
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(90 / $.bananas) > -10", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("(90 / $.bananas) >= -10", INDEX_FILTER_INPUT)).isNull();
+ parseFilterAndCompare("(90 / $.bananas) < -10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 90 / -10 + 1, -1)); // [-8, -1]
+ parseFilterAndCompare("(90 / $.bananas) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 90 / -10, -1)); // [-8, -1]
+
+ parseFilterAndCompare("(-90 / $.bananas) > 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", -90 / 10 + 1, -1)); // [-8, -1]
+ parseFilterAndCompare("(90 / $.bananas) >= 10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1, 90 / 10)); // [1,9]
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(-90 / $.bananas) < 10", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("(-90 / $.bananas) <= 10", INDEX_FILTER_INPUT)).isNull();
+
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(-90 / $.bananas) > -10", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("(-90 / $.bananas) >= -10", INDEX_FILTER_INPUT)).isNull();
+ parseFilterAndCompare("(-90 / $.bananas) < -10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1L, -90 / -10 - 1)); // [1, 8]
+ parseFilterAndCompare("(-90 / $.bananas) <= -10", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1L, -90 / -10)); // [1, 9]
}
@Test
void div_binIsDivisor_leftNumberIsSmaller() {
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) > 10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) >= 10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) < 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) <= 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) > -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) >= -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) < -10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) <= -10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) > 10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) >= 10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) < 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) <= 10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) > -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) >= -10")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) < -10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-9 / $.bananas) <= -10")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(0 / $.bananas) > 10"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(9 / $.bananas) > 0"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Cannot divide by zero");
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(9 / $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(9 / $.bananas) >= 10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(9 / $.bananas) < 10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(9 / $.bananas) <= 10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+
+ assertThat(parseFilter("(9 / $.bananas) > -10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(9 / $.bananas) >= -10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(9 / $.bananas) < -10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(9 / $.bananas) <= -10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+
+ assertThat(parseFilter("(-9 / $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(-9 / $.bananas) >= 10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(-9 / $.bananas) < 10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(-9 / $.bananas) <= 10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+
+ assertThat(parseFilter("(-9 / $.bananas) > -10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(-9 / $.bananas) >= -10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(-9 / $.bananas) < -10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ assertThat(parseFilter("(-9 / $.bananas) <= -10", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+
+ // Not supported by secondary index Filter
+ assertThat(parseFilter("(0 / $.bananas) > 10", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+
+ // Not supported by secondary index Filter, cannot divide by zero
+ assertThat(parseFilter("(9 / $.bananas) > 0", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
}
@Test
void div_binIsDivisor_leftNumberEqualsRight() {
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) > 90")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- parseFiltersAndCompare("(90 / $.bananas) >= 90",
- List.of(Filter.range("bananas", 90 / 90, 90 / 90))); // [1, 1]
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) < 90")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(90 / $.bananas) <= 90")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) > -90")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) >= -90")) // maximal range is all numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("(-90 / $.bananas) < -90")) // no integer numbers
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- parseFiltersAndCompare("(-90 / $.bananas) <= -90",
- List.of(Filter.range("bananas", 1L, 90 / 90))); // [1, 1]
+ // Not supported by secondary index filter
+ assertThat(parseFilter("(90 / $.bananas) > 90", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ parseFilterAndCompare("(90 / $.bananas) >= 90", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 90 / 90, 90 / 90)); // [1, 1]
+ assertThat(parseFilter("(90 / $.bananas) < 90", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(90 / $.bananas) <= 90", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+
+ assertThat(parseFilter("(-90 / $.bananas) > -90", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(-90 / $.bananas) >= -90", INDEX_FILTER_INPUT)).isNull(); // maximal range is all numbers
+ assertThat(parseFilter("(-90 / $.bananas) < -90", INDEX_FILTER_INPUT)).isNull(); // no integer numbers
+ parseFilterAndCompare("(-90 / $.bananas) <= -90", INDEX_FILTER_INPUT,
+ Filter.range("bananas", 1L, 90 / 90)); // [1, 1]
}
}
diff --git a/src/test/java/com/aerospike/dsl/filter/BinFiltersTests.java b/src/test/java/com/aerospike/dsl/filter/BinFiltersTests.java
index 1161383..091cc94 100644
--- a/src/test/java/com/aerospike/dsl/filter/BinFiltersTests.java
+++ b/src/test/java/com/aerospike/dsl/filter/BinFiltersTests.java
@@ -1,105 +1,109 @@
package com.aerospike.dsl.filter;
import com.aerospike.client.query.Filter;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.client.query.IndexType;
+import com.aerospike.dsl.Index;
+import com.aerospike.dsl.IndexContext;
import org.junit.jupiter.api.Test;
import java.util.List;
-import static com.aerospike.dsl.util.TestUtils.parseFilters;
-import static com.aerospike.dsl.util.TestUtils.parseFiltersAndCompare;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static com.aerospike.dsl.util.TestUtils.parseFilter;
+import static com.aerospike.dsl.util.TestUtils.parseFilterAndCompare;
+import static org.assertj.core.api.Assertions.assertThat;
class BinFiltersTests {
+ String NAMESPACE = "test1";
+ List INDEXES = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("stringBin1").indexType(IndexType.STRING).binValuesRatio(1).build()
+ );
+ IndexContext INDEX_FILTER_INPUT = IndexContext.of(NAMESPACE, INDEXES);
+
@Test
void binGT() {
- parseFiltersAndCompare("$.intBin1 > 100",
- List.of(Filter.range("intBin1", 101, Long.MAX_VALUE)));
- parseFiltersAndCompare("$.intBin1 > -100",
- List.of(Filter.range("intBin1", -99, Long.MAX_VALUE)));
-
- assertThatThrownBy(() -> parseFilters("$.stringBin1 > 'text'"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Operand type not supported");
- assertThatThrownBy(() -> parseFilters("$.stringBin1 > \"text\""))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Operand type not supported");
+ parseFilterAndCompare("$.intBin1 > 100", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 101, Long.MAX_VALUE));
+ parseFilterAndCompare("$.intBin1 > -100", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", -99, Long.MAX_VALUE));
+
+ // Comparing Strings is not supported by secondary index Filters
+ assertThat(parseFilter("$.stringBin1 > 'text'", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("$.stringBin1 > \"text\"", INDEX_FILTER_INPUT)).isNull();
// "$.intBin1 > 100" and "100 < $.intBin1" represent identical Filters
- parseFiltersAndCompare("100 < $.intBin1",
- List.of(Filter.range("intBin1", 101, Long.MAX_VALUE)));
-
- assertThatThrownBy(() -> parseFilters("'text' > $.stringBin1"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Operand type not supported");
- assertThatThrownBy(() -> parseFilters("\"text\" > $.stringBin1"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("Operand type not supported");
+ parseFilterAndCompare("100 < $.intBin1", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 101, Long.MAX_VALUE));
+
+ // Comparing Strings is not supported by secondary index Filters
+ assertThat(parseFilter("'text' > $.stringBin1", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("\"text\" > $.stringBin1", INDEX_FILTER_INPUT)).isNull();
+ }
+
+ @Test
+ void binGT_logical_combinations() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build()
+ );
+ parseFilterAndCompare("$.intBin1 > 100 and $.intBin2 < 1000", IndexContext.of(NAMESPACE, indexes),
+ Filter.range("intBin2", Long.MIN_VALUE, 999));
+
+ parseFilterAndCompare("$.intBin1 > 100 and $.intBin2 < 1000",
+ null);
}
@Test
void binGE() {
- parseFiltersAndCompare("$.intBin1 >= 100",
- List.of(Filter.range("intBin1", 100, Long.MAX_VALUE)));
+ parseFilterAndCompare("$.intBin1 >= 100", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 100, Long.MAX_VALUE));
// "$.intBin1 >= 100" and "100 <= $.intBin1" represent identical Filters
- parseFiltersAndCompare("100 <= $.intBin1",
- List.of(Filter.range("intBin1", 100, Long.MAX_VALUE)));
+ parseFilterAndCompare("100 <= $.intBin1", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 100, Long.MAX_VALUE));
}
@Test
void binLT() {
- parseFiltersAndCompare("$.intBin1 < 100",
- List.of(Filter.range("intBin1", Long.MIN_VALUE, 99)));
+ parseFilterAndCompare("$.intBin1 < 100", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", Long.MIN_VALUE, 99));
- parseFiltersAndCompare("100 > $.intBin1",
- List.of(Filter.range("intBin1", Long.MIN_VALUE, 99)));
+ parseFilterAndCompare("100 > $.intBin1", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", Long.MIN_VALUE, 99));
}
@Test
void binLE() {
- parseFiltersAndCompare("$.intBin1 <= 100",
- List.of(Filter.range("intBin1", Long.MIN_VALUE, 100)));
+ parseFilterAndCompare("$.intBin1 <= 100", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", Long.MIN_VALUE, 100));
- parseFiltersAndCompare("100 >= $.intBin1",
- List.of(Filter.range("intBin1", Long.MIN_VALUE, 100)));
+ parseFilterAndCompare("100 >= $.intBin1", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", Long.MIN_VALUE, 100));
}
@Test
void binEQ() {
- parseFiltersAndCompare("$.intBin1 == 100",
- List.of(Filter.equal("intBin1", 100)));
- parseFiltersAndCompare("100 == $.intBin1",
- List.of(Filter.equal("intBin1", 100)));
-
- parseFiltersAndCompare("$.stringBin1 == 'text'",
- List.of(Filter.equal("stringBin1", "text")));
- parseFiltersAndCompare("$.stringBin1 == \"text\"",
- List.of(Filter.equal("stringBin1", "text")));
+ parseFilterAndCompare("$.intBin1 == 100", INDEX_FILTER_INPUT,
+ Filter.equal("intBin1", 100));
+ parseFilterAndCompare("100 == $.intBin1", INDEX_FILTER_INPUT,
+ Filter.equal("intBin1", 100));
+
+ parseFilterAndCompare("$.stringBin1 == 'text'", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "text"));
+ parseFilterAndCompare("$.stringBin1 == \"text\"", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "text"));
}
@Test
void binNOTEQ() {
// NOT EQUAL is not supported by secondary index filter
- assertThatThrownBy(() -> parseFilters("$.intBin1 != 100"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("$.stringBin1 != 'text'"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("$.stringBin1 != \"text\""))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
-
- assertThatThrownBy(() -> parseFilters("100 != $.intBin1"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("100 != 'text'"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
- assertThatThrownBy(() -> parseFilters("100 != \"text\""))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessageContaining("The operation is not supported by secondary index filter");
+ assertThat(parseFilter("$.intBin1 != 100", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("$.stringBin1 != 'text'", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("$.stringBin1 != \"text\"", INDEX_FILTER_INPUT)).isNull();
+
+ assertThat(parseFilter("100 != $.intBin1", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("100 != 'text'", INDEX_FILTER_INPUT)).isNull();
+ assertThat(parseFilter("100 != \"text\"", INDEX_FILTER_INPUT)).isNull();
}
}
diff --git a/src/test/java/com/aerospike/dsl/filter/ExplicitTypesFiltersTests.java b/src/test/java/com/aerospike/dsl/filter/ExplicitTypesFiltersTests.java
index 8fcf9db..f46d98e 100644
--- a/src/test/java/com/aerospike/dsl/filter/ExplicitTypesFiltersTests.java
+++ b/src/test/java/com/aerospike/dsl/filter/ExplicitTypesFiltersTests.java
@@ -1,47 +1,62 @@
package com.aerospike.dsl.filter;
import com.aerospike.client.query.Filter;
-import com.aerospike.dsl.exception.AerospikeDSLException;
+import com.aerospike.client.query.IndexType;
+import com.aerospike.dsl.Index;
+import com.aerospike.dsl.IndexContext;
+import com.aerospike.dsl.DslParseException;
+import com.aerospike.dsl.util.TestUtils;
import org.junit.jupiter.api.Test;
import java.util.Base64;
import java.util.List;
-import static com.aerospike.dsl.util.TestUtils.parseFilters;
-import static com.aerospike.dsl.util.TestUtils.parseFiltersAndCompare;
+import static com.aerospike.dsl.util.TestUtils.parseFilter;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class ExplicitTypesFiltersTests {
+ String NAMESPACE = "test1";
+ List INDEXES = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("stringBin1").indexType(IndexType.STRING).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("blobBin1").indexType(IndexType.BLOB).binValuesRatio(1).build()
+ );
+ IndexContext INDEX_FILTER_INPUT = IndexContext.of(NAMESPACE, INDEXES);
+
@Test
void integerComparison() {
- parseFiltersAndCompare("$.intBin1.get(type: INT) > 5",
- List.of(Filter.range("intBin1", 6, Long.MAX_VALUE)));
+ // Namespace and indexes must be given to create a Filter
+ TestUtils.parseFilterAndCompare("$.intBin1.get(type: INT) > 5", null);
+
+ TestUtils.parseFilterAndCompare("$.intBin1.get(type: INT) > 5", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 6, Long.MAX_VALUE));
- parseFiltersAndCompare("5 < $.intBin1.get(type: INT)",
- List.of(Filter.range("intBin1", 6, Long.MAX_VALUE)));
+ TestUtils.parseFilterAndCompare("5 < $.intBin1.get(type: INT)", INDEX_FILTER_INPUT,
+ Filter.range("intBin1", 6, Long.MAX_VALUE));
}
@Test
void stringComparison() {
- parseFiltersAndCompare("$.stringBin1.get(type: STRING) == \"yes\"",
- List.of(Filter.equal("stringBin1", "yes")));
+ TestUtils.parseFilterAndCompare("$.stringBin1.get(type: STRING) == \"yes\"", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "yes"));
- parseFiltersAndCompare("$.stringBin1.get(type: STRING) == 'yes'",
- List.of(Filter.equal("stringBin1", "yes")));
+ TestUtils.parseFilterAndCompare("$.stringBin1.get(type: STRING) == 'yes'", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "yes"));
- parseFiltersAndCompare("\"yes\" == $.stringBin1.get(type: STRING)",
- List.of(Filter.equal("stringBin1", "yes")));
+ TestUtils.parseFilterAndCompare("\"yes\" == $.stringBin1.get(type: STRING)", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "yes"));
- parseFiltersAndCompare("'yes' == $.stringBin1.get(type: STRING)",
- List.of(Filter.equal("stringBin1", "yes")));
+ TestUtils.parseFilterAndCompare("'yes' == $.stringBin1.get(type: STRING)", INDEX_FILTER_INPUT,
+ Filter.equal("stringBin1", "yes"));
}
@Test
void stringComparisonNegativeTest() {
// A String constant must be quoted
- assertThatThrownBy(() -> parseFilters("$.stringBin1.get(type: STRING) == yes"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseFilter("$.stringBin1.get(type: STRING) == yes"))
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse right operand");
}
@@ -49,133 +64,108 @@ void stringComparisonNegativeTest() {
void blobComparison() {
byte[] data = new byte[]{1, 2, 3};
String encodedString = Base64.getEncoder().encodeToString(data);
- parseFiltersAndCompare("$.blobBin1.get(type: BLOB) == \"" + encodedString + "\"",
- List.of(Filter.equal("blobBin1", data)));
+ TestUtils.parseFilterAndCompare("$.blobBin1.get(type: BLOB) == \"" + encodedString + "\"", INDEX_FILTER_INPUT,
+ Filter.equal("blobBin1", data));
// Reverse
- parseFiltersAndCompare("\"" + encodedString + "\" == $.blobBin1.get(type: BLOB)",
- List.of(Filter.equal("blobBin1", data)));
+ TestUtils.parseFilterAndCompare("\"" + encodedString + "\" == $.blobBin1.get(type: BLOB)", INDEX_FILTER_INPUT,
+ Filter.equal("blobBin1", data));
}
@Test
void floatComparison() {
// No float support in secondary index filter
- assertThatThrownBy(() -> parseFilters("$.floatBin1.get(type: FLOAT) == 1.5"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: FLOAT_OPERAND");
-
- assertThatThrownBy(() -> parseFilters("1.5 == $.floatBin1.get(type: FLOAT)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: FLOAT_OPERAND");
+ assertThat(parseFilter("$.floatBin1.get(type: FLOAT) == 1.5")).isNull();
+ assertThat(parseFilter("1.5 == $.floatBin1.get(type: FLOAT)")).isNull();
}
@Test
void booleanComparison() {
// No boolean support in secondary index filter
- assertThatThrownBy(() -> parseFilters("$.boolBin1.get(type: BOOL) == true"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BOOL_OPERAND");
-
- assertThatThrownBy(() -> parseFilters("true == $.boolBin1.get(type: BOOL)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BOOL_OPERAND");
+ assertThat(parseFilter("$.boolBin1.get(type: BOOL) == true")).isNull();
+ assertThat(parseFilter("true == $.boolBin1.get(type: BOOL)")).isNull();
}
@Test
void negativeBooleanComparison() {
- assertThatThrownBy(() -> parseFilters("$.boolBin1.get(type: BOOL) == 5"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseFilter("$.boolBin1.get(type: BOOL) == 5"))
+ .isInstanceOf(DslParseException.class)
.hasMessage("Cannot compare BOOL to INT");
}
@Test
void listComparison_constantOnRightSide() {
- assertThatThrownBy(() -> parseFilters("$.listBin1.get(type: LIST) == [100]"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: LIST_OPERAND");
+ // Not supported by secondary index filter
+ assertThat(parseFilter("$.listBin1.get(type: LIST) == [100]")).isNull();
}
@Test
void listComparison_constantOnRightSide_NegativeTest() {
- assertThatThrownBy(() -> parseFilters("$.listBin1.get(type: LIST) == [yes, of course]"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseFilter("$.listBin1.get(type: LIST) == [yes, of course]"))
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse list operand");
}
@Test
void listComparison_constantOnLeftSide() {
- assertThatThrownBy(() -> parseFilters("[100] == $.listBin1.get(type: LIST)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: LIST_OPERAND");
+ assertThat(parseFilter("[100] == $.listBin1.get(type: LIST)")).isNull();
}
@Test
void listComparison_constantOnLeftSide_NegativeTest() {
- assertThatThrownBy(() -> parseFilters("[yes, of course] == $.listBin1.get(type: LIST)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Could not parse given input, wrong syntax");
+ assertThatThrownBy(() -> parseFilter("[yes, of course] == $.listBin1.get(type: LIST)"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Could not parse given DSL expression input");
}
@Test
void mapComparison_constantOnRightSide() {
- assertThatThrownBy(() -> parseFilters("$.mapBin1.get(type: MAP) == {100:100}"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: MAP_OPERAND");
+ assertThat(parseFilter("$.mapBin1.get(type: MAP) == {100:100}")).isNull();
}
@Test
void mapComparison_constantOnRightSide_NegativeTest() {
- assertThatThrownBy(() -> parseFilters("$.mapBin1.get(type: MAP) == {yes, of course}"))
- .isInstanceOf(AerospikeDSLException.class)
+ assertThatThrownBy(() -> parseFilter("$.mapBin1.get(type: MAP) == {yes, of course}"))
+ .isInstanceOf(DslParseException.class)
.hasMessage("Unable to parse map operand");
}
@Test
void mapComparison_constantOnLeftSide() {
- assertThatThrownBy(() -> parseFilters("{100:100} == $.mapBin1.get(type: MAP)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: MAP_OPERAND");
+ assertThat(parseFilter("{100:100} == $.mapBin1.get(type: MAP)")).isNull();
}
@Test
void mapComparison_constantOnLeftSide_NegativeTest() {
- assertThatThrownBy(() -> parseFilters("{yes, of course} == $.mapBin1.get(type: MAP)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Could not parse given input, wrong syntax");
+ assertThatThrownBy(() -> parseFilter("{yes, of course} == $.mapBin1.get(type: MAP)"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Could not parse given DSL expression input");
}
@Test
void twoStringBinsComparison() {
- assertThatThrownBy(() -> parseFilters("$.stringBin1.get(type: STRING) == $.stringBin2.get(type: STRING)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThat(parseFilter("$.stringBin1.get(type: STRING) == $.stringBin2.get(type: STRING)")).isNull();
}
@Test
void twoIntegerBinsComparison() {
- assertThatThrownBy(() -> parseFilters("$.intBin1.get(type: INT) == $.intBin2.get(type: INT)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThat(parseFilter("$.intBin1.get(type: INT) == $.intBin2.get(type: INT)")).isNull();
}
@Test
void twoFloatBinsComparison() {
- assertThatThrownBy(() -> parseFilters("$.floatBin1.get(type: FLOAT) == $.floatBin2.get(type: FLOAT)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThat(parseFilter("$.floatBin1.get(type: FLOAT) == $.floatBin2.get(type: FLOAT)")).isNull();
}
@Test
void twoBlobBinsComparison() {
- assertThatThrownBy(() -> parseFilters("$.blobBin1.get(type: BLOB) == $.blobBin2.get(type: BLOB)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThat(parseFilter("$.blobBin1.get(type: BLOB) == $.blobBin2.get(type: BLOB)")).isNull();
}
@Test
void negativeTwoDifferentBinTypesComparison() {
- assertThatThrownBy(() -> parseFilters("$.stringBin1.get(type: STRING) == $.floatBin2.get(type: FLOAT)"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThatThrownBy(() -> parseFilter("$.stringBin1.get(type: STRING) == $.floatBin2.get(type: FLOAT)"))
+ .isInstanceOf(DslParseException.class)
+ .hasMessage("Cannot compare STRING to FLOAT");
}
}
diff --git a/src/test/java/com/aerospike/dsl/filter/ImplicitTypesFiltersTests.java b/src/test/java/com/aerospike/dsl/filter/ImplicitTypesFiltersTests.java
index 15f4cb5..79690f8 100644
--- a/src/test/java/com/aerospike/dsl/filter/ImplicitTypesFiltersTests.java
+++ b/src/test/java/com/aerospike/dsl/filter/ImplicitTypesFiltersTests.java
@@ -1,31 +1,24 @@
package com.aerospike.dsl.filter;
-import com.aerospike.dsl.exception.AerospikeDSLException;
import org.junit.jupiter.api.Test;
-import static com.aerospike.dsl.util.TestUtils.parseFilters;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static com.aerospike.dsl.util.TestUtils.parseFilter;
+import static org.assertj.core.api.Assertions.assertThat;
public class ImplicitTypesFiltersTests {
@Test
void implicitDefaultIntComparison() {
- assertThatThrownBy(() -> parseFilters("$.intBin1 < $.intBin2"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BIN_PART");
+ assertThat(parseFilter("$.intBin1 < $.intBin2")).isNull();
}
@Test
void floatComparison() {
- assertThatThrownBy(() -> parseFilters("$.floatBin1 >= 100.25"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: FLOAT_OPERAND");
+ assertThat(parseFilter("$.floatBin1 >= 100.25")).isNull();
}
@Test
void booleanComparison() {
- assertThatThrownBy(() -> parseFilters("$.boolBin1 == true"))
- .isInstanceOf(AerospikeDSLException.class)
- .hasMessage("Operand type not supported: BOOL_OPERAND");
+ assertThat(parseFilter("$.boolBin1 == true")).isNull();
}
}
diff --git a/src/test/java/com/aerospike/dsl/parsedExpression/LogicalParsedExpressionTests.java b/src/test/java/com/aerospike/dsl/parsedExpression/LogicalParsedExpressionTests.java
new file mode 100644
index 0000000..9b545df
--- /dev/null
+++ b/src/test/java/com/aerospike/dsl/parsedExpression/LogicalParsedExpressionTests.java
@@ -0,0 +1,253 @@
+package com.aerospike.dsl.parsedExpression;
+
+import com.aerospike.client.exp.Exp;
+import com.aerospike.client.query.Filter;
+import com.aerospike.client.query.IndexType;
+import com.aerospike.dsl.Index;
+import com.aerospike.dsl.IndexContext;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static com.aerospike.dsl.util.TestUtils.parseExpressionAndCompare;
+
+public class LogicalParsedExpressionTests {
+
+ @Test
+ void binLogical_AND_2_no_indexes() {
+ Filter filter = null;
+ Exp exp = Exp.and(Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100)));
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100", filter, exp);
+ }
+
+ @Test
+ void binLogical_AND_2_all_indexes() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build()
+ );
+ String namespace = "test1";
+ Filter filter = Filter.range("intBin2", 101, Long.MAX_VALUE);
+ Exp exp = Exp.gt(Exp.intBin("intBin1"), Exp.val(100));
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_2_all_indexes_no_cardinality() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).build()
+ );
+ String namespace = "test1";
+ // Filter is chosen alphabetically because no cardinality is given
+ Filter filter = Filter.range("intBin1", 101, Long.MAX_VALUE);
+ Exp exp = Exp.gt(Exp.intBin("intBin2"), Exp.val(100));
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_2_one_index() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build());
+ String namespace = "test1";
+ Filter filter = Filter.range("intBin1", 101, Long.MAX_VALUE);
+ Exp exp = Exp.gt(Exp.intBin("intBin2"), Exp.val(100));
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_3_all_indexes() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ Filter filter = Filter.range("intBin2", 101, Long.MAX_VALUE);
+ Exp exp = Exp.and(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_3_all_indexes_same_cardinality() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(100).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(100).build(),
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(100).build()
+ );
+ String namespace = "test1";
+ // Filter is chosen alphabetically because the same cardinality is given
+ Filter filter = Filter.range("intBin1", 101, Long.MAX_VALUE);
+ Exp exp = Exp.and(
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_3_all_indexes_no_cardinality() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).build(),
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).build()
+ );
+ String namespace = "test1";
+ // Filter is chosen alphabetically because no cardinality is given
+ Filter filter = Filter.range("intBin1", 101, Long.MAX_VALUE);
+ Exp exp = Exp.and(
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_3_all_indexes_partial_data() {
+ List indexes = List.of(
+ Index.builder().bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.STRING).binValuesRatio(0).build(),
+ // The only matching index with full data
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ // The only matching index with full data is for intBin3
+ Filter filter = Filter.range("intBin3", 101, Long.MAX_VALUE);
+ Exp exp = Exp.and(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_AND_3_two_indexes() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ Filter filter = Filter.range("intBin2", 101, Long.MAX_VALUE);
+ Exp exp = Exp.and(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 and $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_OR_2_no_indexes() {
+ Filter filter = null;
+ Exp exp = Exp.or(Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100)));
+ parseExpressionAndCompare("$.intBin1 > 100 or $.intBin2 > 100", filter, exp);
+ }
+
+ @Test
+ void binLogical_OR_2_all_indexes() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build()
+ );
+ String namespace = "test1";
+ Filter filter = null;
+ Exp exp = Exp.or(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 or $.intBin2 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_OR_2_one_index() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ Filter filter = null;
+ Exp exp = Exp.or(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 or $.intBin2 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_OR_3_all_indexes() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(1).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ Filter filter = null;
+ Exp exp = Exp.or(
+ Exp.or(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ ),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 or $.intBin2 > 100 or $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Test
+ void binLogical_prioritizedAND_OR_indexed() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(1).build()
+ );
+ String namespace = "test1";
+ Filter filter = null;
+ Exp exp = Exp.or(
+ Exp.and(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ ),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and $.intBin2 > 100 or $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ parseExpressionAndCompare("($.intBin1 > 100 and $.intBin2 > 100) or $.intBin3 > 100", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+
+ @Disabled // TODO: complex logical structures, different grouping
+ @Test
+ void binLogical_AND_prioritizedOR_indexed() {
+ List indexes = List.of(
+ Index.builder().namespace("test1").bin("intBin1").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin2").indexType(IndexType.NUMERIC).binValuesRatio(0).build(),
+ Index.builder().namespace("test1").bin("intBin3").indexType(IndexType.NUMERIC).binValuesRatio(0).build()
+ );
+ String namespace = "test1";
+ Filter filter = Filter.range("intBin1", 101, Long.MAX_VALUE);
+ Exp exp = Exp.or(
+ Exp.and(
+ Exp.gt(Exp.intBin("intBin1"), Exp.val(100)),
+ Exp.gt(Exp.intBin("intBin2"), Exp.val(100))
+ ),
+ Exp.gt(Exp.intBin("intBin3"), Exp.val(100))
+ );
+ parseExpressionAndCompare("$.intBin1 > 100 and ($.intBin2 > 100 or $.intBin3 > 100)", filter, exp,
+ IndexContext.of(namespace, indexes));
+ }
+}
diff --git a/src/test/java/com/aerospike/dsl/util/TestUtils.java b/src/test/java/com/aerospike/dsl/util/TestUtils.java
index b85a950..75fd3e1 100644
--- a/src/test/java/com/aerospike/dsl/util/TestUtils.java
+++ b/src/test/java/com/aerospike/dsl/util/TestUtils.java
@@ -4,33 +4,56 @@
import com.aerospike.client.exp.Expression;
import com.aerospike.client.query.Filter;
import com.aerospike.dsl.DSLParserImpl;
+import com.aerospike.dsl.IndexContext;
+import com.aerospike.dsl.ParsedExpression;
import lombok.experimental.UtilityClass;
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
@UtilityClass
public class TestUtils {
private final DSLParserImpl parser = new DSLParserImpl();
-
- public static void parseExpression(String input) {
- parser.parseExpression(input);
+
+ public static Expression parseExp(String input) {
+ return Exp.build(parser.parseExpression(input).getResult().getExp());
}
- public static void parseExpressionAndCompare(String input, Exp expected) {
- Expression actualExpression = parser.parseExpression(input);
+ public static void parseExpAndCompare(String input, Exp expected) {
+ Expression actualExpression = Exp.build(parser.parseExpression(input).getResult().getExp());
Expression expectedExpression = Exp.build(expected);
assertEquals(actualExpression, expectedExpression);
}
- public static void parseFilters(String input) {
- parser.parseFilters(input);
+ public static Filter parseFilter(String input) {
+ return parser.parseExpression(input).getResult().getFilter();
+ }
+
+ public static Filter parseFilter(String input, IndexContext indexContext) {
+ return parser.parseExpression(input, indexContext).getResult().getFilter();
}
- public static void parseFiltersAndCompare(String input, List expected) {
- List actualFilter = parser.parseFilters(input);
+ public static void parseFilterAndCompare(String input, Filter expected) {
+ Filter actualFilter = parseFilter(input);
assertEquals(actualFilter, expected);
}
+
+ public static void parseFilterAndCompare(String input, IndexContext indexContext, Filter expected) {
+ Filter actualFilter = parseFilter(input, indexContext);
+ assertEquals(actualFilter, expected);
+ }
+
+ public static void parseExpressionAndCompare(String input, Filter filter, Exp exp) {
+ ParsedExpression actualExpression = parser.parseExpression(input);
+ assertEquals(actualExpression.getResult().getFilter(), filter);
+ Exp actualExp = actualExpression.getResult().getExp();
+ assertEquals(actualExp == null ? null : Exp.build(actualExp), exp == null ? null : Exp.build(exp));
+ }
+
+ public static void parseExpressionAndCompare(String input, Filter filter, Exp exp, IndexContext indexContext) {
+ ParsedExpression actualExpression = parser.parseExpression(input, indexContext);
+ assertEquals(actualExpression.getResult().getFilter(), filter);
+ Exp actualExp = actualExpression.getResult().getExp();
+ assertEquals(actualExp == null ? null : Exp.build(actualExp), exp == null ? null : Exp.build(exp));
+ }
}