forked from hadrienk/java-vtl
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 in CORE/java-vtl from feature/boolean-expressio…
…ns to develop * commit '5407e4d27523f79cdfaa6d8515d3d15a66507b0c': Generalize boolean comparision operation to handle a mix of component and scalar operands Impement boolean comparison operators Boolean expression with equal to for join
- Loading branch information
Showing
7 changed files
with
329 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
java-vtl-script/src/main/java/no/ssb/vtl/script/visitors/BooleanExpressionVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package no.ssb.vtl.script.visitors; | ||
|
||
import com.google.common.collect.Iterables; | ||
import no.ssb.vtl.model.Component; | ||
import no.ssb.vtl.model.DataPoint; | ||
import no.ssb.vtl.model.Dataset; | ||
import no.ssb.vtl.parser.VTLBaseVisitor; | ||
import no.ssb.vtl.parser.VTLParser; | ||
import org.antlr.v4.runtime.Token; | ||
import org.antlr.v4.runtime.misc.ParseCancellationException; | ||
|
||
import java.lang.String; | ||
import java.util.function.BiPredicate; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
|
||
import static java.lang.String.*; | ||
|
||
public class BooleanExpressionVisitor extends VTLBaseVisitor<Predicate<Dataset.Tuple>> { | ||
|
||
private final ReferenceVisitor referenceVisitor; | ||
|
||
public BooleanExpressionVisitor(ReferenceVisitor referenceVisitor) { | ||
this.referenceVisitor = referenceVisitor; | ||
} | ||
|
||
@Override | ||
public Predicate<Dataset.Tuple> visitBooleanExpression(VTLParser.BooleanExpressionContext ctx) { | ||
if (ctx.BOOLEAN_CONSTANT() != null) { | ||
Boolean booleanConstant = Boolean.valueOf(ctx.BOOLEAN_CONSTANT().getText()); | ||
return dataPoints -> booleanConstant; | ||
}else if (ctx.op != null) { | ||
Predicate<Dataset.Tuple> left = visit(ctx.booleanExpression(0)); | ||
Predicate<Dataset.Tuple> right = visit(ctx.booleanExpression(1)); | ||
switch (ctx.op.getType()) { | ||
case VTLParser.AND: | ||
return left.and(right); | ||
case VTLParser.OR: | ||
return left.or(right); | ||
case VTLParser.XOR: | ||
return left.or(right).and(left.and(right).negate()); | ||
default: | ||
throw new ParseCancellationException("Unsupported boolean operation: " + ctx.op.getText()); | ||
} | ||
} else if (ctx.booleanEquality() != null) { | ||
return visit(ctx.booleanEquality()); | ||
} else { | ||
return super.visit(ctx); | ||
} | ||
} | ||
|
||
@Override | ||
public Predicate<Dataset.Tuple> visitBooleanEquality(VTLParser.BooleanEqualityContext ctx) { | ||
ParamVisitor paramVisitor = new ParamVisitor(referenceVisitor); | ||
Object left = paramVisitor.visit(ctx.left); | ||
Object right = paramVisitor.visit(ctx.right); | ||
|
||
BiPredicate<Object, Object> booleanOperation = getBooleanOperation(ctx.op); | ||
|
||
if (isComp(left) && !isComp(right)) { | ||
return tuple -> tuple.stream() | ||
.filter(dataPoint -> left.equals(dataPoint.getComponent())) | ||
.anyMatch(dataPoint -> booleanOperation.test(dataPoint.get(), right)); | ||
} else if (!isComp(left) && isComp(right)){ | ||
return tuple -> tuple.stream() | ||
.filter(dataPoint -> right.equals(dataPoint.getComponent())) | ||
.anyMatch(dataPoint -> booleanOperation.test(left, dataPoint.get())); | ||
} else if (isComp(left) && isComp(right)) { | ||
return tuple -> { | ||
DataPoint rightDataPoint = getOnlyElement(right, tuple); | ||
DataPoint leftDataPoint = getOnlyElement(left, tuple); | ||
return booleanOperation.test(leftDataPoint.get(), rightDataPoint.get()); | ||
}; | ||
} else { | ||
return tuple -> booleanOperation.test(left, right); | ||
} | ||
} | ||
|
||
private BiPredicate<Object, Object> getBooleanOperation(Token op) { | ||
switch (op.getType()) { | ||
case VTLParser.EQ: | ||
return Object::equals; | ||
case VTLParser.NE: | ||
return (l, r) -> !l.equals(r); | ||
case VTLParser.LE: | ||
return (l, r) -> compare(l, r) <= 0; | ||
case VTLParser.LT: | ||
return (l, r) -> compare(l, r) < 0; | ||
case VTLParser.GE: | ||
return (l, r) -> compare(l, r) >= 0; | ||
case VTLParser.GT: | ||
return (l, r) -> compare(l, r) > 0; | ||
default: | ||
throw new ParseCancellationException("Unsupported boolean equality operator " + op); | ||
} | ||
} | ||
|
||
private DataPoint getOnlyElement(Object component, Dataset.Tuple tuple) { | ||
return Iterables.getOnlyElement(tuple.stream() | ||
.filter(dataPoint -> component.equals(dataPoint.getComponent())) | ||
.collect(Collectors.toList())); | ||
} | ||
|
||
private boolean isComp(Object o) { | ||
return o instanceof Component; | ||
} | ||
|
||
private int compare(Object value, Object scalar) { | ||
if (value instanceof Integer && scalar instanceof Integer) { | ||
return ((Integer) value).compareTo((Integer) scalar); | ||
} else if (value instanceof Float && scalar instanceof Float) { | ||
return ((Float) value).compareTo((Float) scalar); | ||
} else if (value instanceof Boolean && scalar instanceof Boolean) { | ||
return ((Boolean) value).compareTo((Boolean) scalar); | ||
} else if (value instanceof String && scalar instanceof String) { | ||
return ((String) value).compareTo((String) scalar); | ||
} | ||
throw new ParseCancellationException( | ||
format("Cannot compare %s of type %s with %s of type %s", | ||
value, value.getClass(), scalar, scalar.getClass()) | ||
); | ||
} | ||
|
||
} |
35 changes: 35 additions & 0 deletions
35
java-vtl-script/src/main/java/no/ssb/vtl/script/visitors/ParamVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package no.ssb.vtl.script.visitors; | ||
|
||
import no.ssb.vtl.parser.VTLBaseVisitor; | ||
import no.ssb.vtl.parser.VTLParser; | ||
|
||
public class ParamVisitor extends VTLBaseVisitor<Object> { | ||
|
||
private final ReferenceVisitor referenceVisitor; | ||
|
||
public ParamVisitor(ReferenceVisitor referenceVisitor) { | ||
this.referenceVisitor = referenceVisitor; | ||
} | ||
|
||
@Override | ||
public Object visitComponentRef(VTLParser.ComponentRefContext ctx) { | ||
return referenceVisitor.visit(ctx); | ||
} | ||
|
||
@Override | ||
public Object visitConstant(VTLParser.ConstantContext ctx) { | ||
String constant = ctx.getText(); | ||
if (ctx.BOOLEAN_CONSTANT() != null) { | ||
return Boolean.valueOf(constant); | ||
} else if (ctx.FLOAT_CONSTANT() != null) { | ||
return Float.valueOf(constant); | ||
} else if (ctx.INTEGER_CONSTANT() != null) { | ||
return Integer.valueOf(constant); | ||
} else if (ctx.NULL_CONSTANT() != null) { | ||
return null; | ||
} else { //String | ||
return constant.replace("\"", ""); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.