Skip to content

Commit

Permalink
Merge pull request #44 from sidhant92/type_conversion
Browse files Browse the repository at this point in the history
Handle Implicit Data Type Conversion
  • Loading branch information
sidhant92 authored Aug 26, 2024
2 parents 86fb416 + 4cc2de6 commit 135bf05
Show file tree
Hide file tree
Showing 18 changed files with 230 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.github.sidhant92.boolparser.application;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
Expand Down Expand Up @@ -77,27 +79,32 @@ private boolean evaluateComparisonToken(final ComparisonNode comparisonToken, fi
() -> new DataNotFoundException(comparisonToken.getField()));
final Object value = comparisonToken.isNullCheck() ? "null" : comparisonToken.getValue() instanceof ArithmeticBaseNode ? arithmeticExpressionEvaluator.evaluate(
comparisonToken.getValue(), data) : comparisonToken.getValue();
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, comparisonToken.getDataType(),
fieldData, value);
final DataType dataType = ValueUtils.getDataType(value);
final DataType fieldDataType = ValueUtils.getDataType(fieldData);
return operatorService.evaluateLogicalOperator(comparisonToken.getOperator(), ContainerDataType.PRIMITIVE, fieldData,
fieldDataType, Collections.singletonList(Pair.of(value, dataType)));
}

private boolean evaluateNumericRangeToken(final NumericRangeNode numericRangeToken, final Map<String, Object> data) {
final Object fieldData = ValueUtils.getValueFromMap(numericRangeToken.getField(), data)
.orElseThrow(() -> new DataNotFoundException(numericRangeToken.getField()));
return operatorService.evaluateLogicalOperator(Operator.GREATER_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getFromDataType(),
fieldData, numericRangeToken.getFromValue()) && operatorService.evaluateLogicalOperator(
Operator.LESS_THAN_EQUAL, ContainerDataType.PRIMITIVE, numericRangeToken.getToDataType(), fieldData, numericRangeToken.getToValue());
return operatorService.evaluateLogicalOperator(Operator.GREATER_THAN_EQUAL, ContainerDataType.PRIMITIVE, fieldData,
numericRangeToken.getFromDataType(), Collections.singletonList(
Pair.of(numericRangeToken.getFromValue(), numericRangeToken.getFromDataType()))) && operatorService.evaluateLogicalOperator(
Operator.LESS_THAN_EQUAL, ContainerDataType.PRIMITIVE, fieldData, numericRangeToken.getToDataType(),
Collections.singletonList(Pair.of(numericRangeToken.getToValue(), numericRangeToken.getToDataType())));
}

private boolean evaluateInToken(final InNode inToken, final Map<String, Object> data) {
final Object fieldData = ValueUtils.getValueFromMap(inToken.getField(), data)
.orElseThrow(() -> new DataNotFoundException(inToken.getField()));
final List<EvaluatedNode> items = resolveArrayElements(inToken.getItems(), data);
final DataType dataType = ValueUtils.getDataType(fieldData);
final Object[] values = items
final List<Pair<Object, DataType>> values = items
.stream()
.map(EvaluatedNode::getValue).toArray();
return operatorService.evaluateLogicalOperator(Operator.IN, ContainerDataType.PRIMITIVE, dataType, fieldData, values);
.map(item -> Pair.of(item.getValue(), item.getDataType()))
.collect(Collectors.toList());
return operatorService.evaluateLogicalOperator(Operator.IN, ContainerDataType.PRIMITIVE, fieldData, dataType, values);
}

private List<EvaluatedNode> resolveArrayElements(final List<Node> items, final Map<String, Object> data) {
Expand All @@ -123,10 +130,11 @@ private boolean evaluateArrayToken(final ArrayNode arrayNode, final Map<String,
throw new HeterogeneousArrayException();
}
final DataType dataType = items.get(0).getDataType();
final Object[] values = items
final List<Pair<Object, DataType>> values = items
.stream()
.map(EvaluatedNode::getValue).toArray();
return operatorService.evaluateLogicalOperator(arrayNode.getOperator(), ContainerDataType.LIST, dataType, fieldData, values);
.map(item -> Pair.of(item.getValue(), item.getDataType()))
.collect(Collectors.toList());
return operatorService.evaluateLogicalOperator(arrayNode.getOperator(), ContainerDataType.LIST, fieldData, dataType, values);
}

private boolean evaluateUnaryToken(final UnaryNode unaryToken, final Map<String, Object> data) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package com.github.sidhant92.boolparser.constant;

import lombok.AllArgsConstructor;

/**
* @author sidhant.aggarwal
* @since 05/03/2023
*/
@AllArgsConstructor
public enum DataType {
STRING,
INTEGER,
LONG,
DECIMAL,
VERSION,
BOOLEAN
STRING(6, false),
INTEGER(3, true),
LONG(4, true),
DECIMAL(5, true),
VERSION(2, true),
BOOLEAN(1, false);

public final int priority;

public final boolean numeric;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import com.github.sidhant92.boolparser.operator.logical.AbstractOperator;
import com.github.sidhant92.boolparser.operator.comparison.AbstractOperator;
import com.github.sidhant92.boolparser.operator.OperatorFactory;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
import com.github.sidhant92.boolparser.operator.arithmetic.MultiplyOperator;
import com.github.sidhant92.boolparser.operator.arithmetic.SubtractOperator;
import com.github.sidhant92.boolparser.operator.arithmetic.UnaryOperator;
import com.github.sidhant92.boolparser.operator.logical.AbstractOperator;
import com.github.sidhant92.boolparser.operator.logical.ContainsAllOperator;
import com.github.sidhant92.boolparser.operator.logical.ContainsAnyOperator;
import com.github.sidhant92.boolparser.operator.logical.EqualsOperator;
import com.github.sidhant92.boolparser.operator.logical.GreaterThanEqualOperator;
import com.github.sidhant92.boolparser.operator.logical.GreaterThanOperator;
import com.github.sidhant92.boolparser.operator.logical.InOperator;
import com.github.sidhant92.boolparser.operator.logical.LessThanEqualOperator;
import com.github.sidhant92.boolparser.operator.logical.LessThanOperator;
import com.github.sidhant92.boolparser.operator.logical.NotEqualsOperator;
import com.github.sidhant92.boolparser.operator.comparison.AbstractOperator;
import com.github.sidhant92.boolparser.operator.comparison.ContainsAllOperator;
import com.github.sidhant92.boolparser.operator.comparison.ContainsAnyOperator;
import com.github.sidhant92.boolparser.operator.comparison.EqualsOperator;
import com.github.sidhant92.boolparser.operator.comparison.GreaterThanEqualOperator;
import com.github.sidhant92.boolparser.operator.comparison.GreaterThanOperator;
import com.github.sidhant92.boolparser.operator.comparison.InOperator;
import com.github.sidhant92.boolparser.operator.comparison.LessThanEqualOperator;
import com.github.sidhant92.boolparser.operator.comparison.LessThanOperator;
import com.github.sidhant92.boolparser.operator.comparison.NotEqualsOperator;

/**
* @author sidhant.aggarwal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.github.sidhant92.boolparser.operator;

import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
import com.github.sidhant92.boolparser.datatype.DataTypeFactory;
import com.github.sidhant92.boolparser.exception.InvalidContainerTypeException;
import com.github.sidhant92.boolparser.exception.InvalidDataType;
import com.github.sidhant92.boolparser.operator.logical.AbstractOperator;
import com.github.sidhant92.boolparser.operator.comparison.AbstractOperator;

/**
* @author sidhant.aggarwal
Expand All @@ -19,19 +21,24 @@ public OperatorService() {
OperatorFactory.initialize();
}

public boolean evaluateLogicalOperator(final Operator operator, final ContainerDataType containerDataType, final DataType dataType,
final Object leftOperand, final Object... rightOperands) {
public boolean evaluateLogicalOperator(final Operator operator, final ContainerDataType containerDataType, final Object leftOperand,
final DataType leftOperandDataType, final List<Pair<Object, DataType>> rightOperands) {
final AbstractOperator abstractOperator = OperatorFactory.getLogicalOperator(operator);
if (!abstractOperator.getAllowedContainerTypes().contains(containerDataType)) {
throw new InvalidContainerTypeException(String.format("Invalid left container type %s for operator %s", containerDataType, operator));
}
if (!abstractOperator.getAllowedDataTypes().contains(dataType)) {
throw new InvalidDataType(String.format("Invalid left operand data type %s for operator %s", dataType, operator));
if (!abstractOperator.getAllowedDataTypes().contains(leftOperandDataType)) {
throw new InvalidDataType(String.format("Invalid left operand data type %s for operator %s", leftOperandDataType, operator));
}
if (!containerDataType.isValid(dataType, leftOperand)) {
if (!containerDataType.isValid(leftOperandDataType, leftOperand)) {
throw new InvalidDataType(String.format("Validation failed for the operator %s for the operand %s", operator, leftOperand));
}
return OperatorFactory.getLogicalOperator(operator).evaluate(containerDataType, dataType, leftOperand, rightOperands);
rightOperands.forEach(rightOperand -> {
if (!abstractOperator.getAllowedDataTypes().contains(rightOperand.getRight())) {
throw new InvalidDataType(String.format("Invalid right operand data type %s for operator %s", rightOperand.getRight(), operator));
}
});
return OperatorFactory.getLogicalOperator(operator).evaluate(containerDataType, leftOperand, leftOperandDataType, rightOperands);
}

public Object evaluateArithmeticOperator(final Object leftOperand, final DataType leftDataType, final Object rightOperand,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.sidhant92.boolparser.operator.logical;
package com.github.sidhant92.boolparser.operator.comparison;

import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
Expand All @@ -10,8 +11,9 @@
* @since 05/03/2023
*/
public abstract class AbstractOperator {
public abstract <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final DataType dataType,
final Object leftOperand, final Object... rightOperands);
public abstract <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final Object leftOperand,
final DataType leftOperandDataType,
final List<Pair<Object, DataType>> rightOperands);

public abstract Operator getOperator();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.github.sidhant92.boolparser.operator.logical;
package com.github.sidhant92.boolparser.operator.comparison;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
Expand All @@ -13,15 +15,18 @@ public class ContainsAllOperator extends AbstractOperator {
private final InOperator inOperator;

@Override
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final DataType dataType,
final Object leftOperand, final Object... rightOperands) {
if (!containerDataType.isValid(dataType, leftOperand)) {
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final Object leftOperand,
final DataType leftOperandDataType, final List<Pair<Object, DataType>> rightOperands) {
if (!containerDataType.isValid(leftOperandDataType, leftOperand)) {
return false;
}
final Object[] leftOperandArray = ((List<?>) leftOperand).toArray();
return Arrays
.stream(rightOperands)
.allMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, dataType, rightOperand, leftOperandArray));
final List<Pair<Object, DataType>> leftOperandArray = Arrays
.stream(((List<?>) leftOperand).toArray())
.map(a -> Pair.of(a, leftOperandDataType))
.collect(Collectors.toList());
return rightOperands
.stream().allMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, rightOperand.getLeft(), rightOperand.getRight(),
leftOperandArray));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.github.sidhant92.boolparser.operator.logical;
package com.github.sidhant92.boolparser.operator.comparison;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
Expand All @@ -13,15 +15,18 @@ public class ContainsAnyOperator extends AbstractOperator {
private final InOperator inOperator;

@Override
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final DataType dataType,
final Object leftOperand, final Object... rightOperands) {
if (!containerDataType.isValid(dataType, leftOperand)) {
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final Object leftOperand,
final DataType leftOperandDataType, final List<Pair<Object, DataType>> rightOperands) {
if (!containerDataType.isValid(leftOperandDataType, leftOperand)) {
return false;
}
final Object[] leftOperandArray = ((List<?>) leftOperand).toArray();
return Arrays
.stream(rightOperands)
.anyMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, dataType, rightOperand, leftOperandArray));
final List<Pair<Object, DataType>> leftOperandArray = Arrays
.stream(((List<?>) leftOperand).toArray())
.map(a -> Pair.of(a, leftOperandDataType))
.collect(Collectors.toList());
return rightOperands
.stream().anyMatch(rightOperand -> inOperator.evaluate(ContainerDataType.PRIMITIVE, rightOperand.getLeft(), rightOperand.getRight(),
leftOperandArray));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.github.sidhant92.boolparser.operator.logical;
package com.github.sidhant92.boolparser.operator.comparison;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.tuple.Pair;
import com.github.sidhant92.boolparser.constant.ContainerDataType;
import com.github.sidhant92.boolparser.constant.DataType;
import com.github.sidhant92.boolparser.constant.Operator;
Expand All @@ -14,11 +15,22 @@
*/
public class EqualsOperator extends AbstractOperator {
@Override
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final DataType dataType,
final Object leftOperand, final Object... rightOperands) {
final Optional<T> leftValueOptional = containerDataType.getValue(dataType, leftOperand);
final Optional<T> rightValueOptional = containerDataType.getValue(dataType, rightOperands[0]);
return leftValueOptional.flatMap(leftValue -> rightValueOptional.map(leftValue::compareTo).map(a -> a == 0)).orElse(false);
public <T extends Comparable<? super T>> boolean evaluate(final ContainerDataType containerDataType, final Object leftOperand,
final DataType leftOperandDataType, final List<Pair<Object, DataType>> rightOperands) {
final DataType comparisonType = getComparableDataType(leftOperandDataType, rightOperands.get(0).getRight());
final Optional<T> leftValueOptional = containerDataType.getValue(comparisonType, leftOperand);
final Optional<T> rightValueOptional = containerDataType.getValue(comparisonType, rightOperands.get(0).getLeft());
return leftValueOptional
.flatMap(leftValue -> rightValueOptional
.map(leftValue::compareTo)
.map(a -> a == 0)).orElse(false);
}

private DataType getComparableDataType(final DataType leftOperandDataType, final DataType rightOperandDataType) {
if (leftOperandDataType.priority > rightOperandDataType.priority) {
return leftOperandDataType;
}
return rightOperandDataType;
}

@Override
Expand Down
Loading

0 comments on commit 135bf05

Please sign in to comment.