This is an automated email from the ASF dual-hosted git repository. sunlan pushed a commit to branch GROOVY-8258 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e8e95d8274ba43c943df8e2fe73bb86ffb84b04d Author: Daniel Sun <[email protected]> AuthorDate: Tue Oct 6 02:21:19 2020 +0800 GROOVY-8258: Implement inner join --- .../org/apache/groovy/linq/dsl/GinqAstBuilder.java | 46 +++++-- .../org/apache/groovy/linq/dsl/GinqBuilder.groovy | 135 +++++++++++++++++++-- .../org/apache/groovy/linq/dsl/GinqVisitor.java | 6 +- ...{WhereExpression.java => FilterExpression.java} | 18 ++- .../linq/dsl/expression/FilterableExpression.java | 10 +- .../groovy/linq/dsl/expression/FromExpression.java | 2 +- ...ereExpression.java => InnerJoinExpression.java} | 15 +-- .../{FromExpression.java => JoinExpression.java} | 30 ++--- .../{WhereExpression.java => OnExpression.java} | 16 +-- .../linq/dsl/expression/SimpleGinqExpression.java | 9 ++ .../linq/dsl/expression/WhereExpression.java | 10 +- .../groovy/org/apache/groovy/linq/GinqTest.groovy | 14 +++ 12 files changed, 227 insertions(+), 84 deletions(-) diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java index c80e347..4905871 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java @@ -18,9 +18,12 @@ */ package org.apache.groovy.linq.dsl; +import org.apache.groovy.linq.dsl.expression.FilterExpression; import org.apache.groovy.linq.dsl.expression.FilterableExpression; import org.apache.groovy.linq.dsl.expression.FromExpression; import org.apache.groovy.linq.dsl.expression.GinqExpression; +import org.apache.groovy.linq.dsl.expression.InnerJoinExpression; +import org.apache.groovy.linq.dsl.expression.OnExpression; import org.apache.groovy.linq.dsl.expression.SelectExpression; import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression; import org.apache.groovy.linq.dsl.expression.WhereExpression; @@ -57,14 +60,13 @@ public class GinqAstBuilder extends CodeVisitorSupport { public void visitMethodCallExpression(MethodCallExpression call) { super.visitMethodCallExpression(call); final String methodName = call.getMethodAsString(); - System.out.println(methodName + " : " + call); - if ("from".equals(methodName)) { + if ("from".equals(methodName) || "innerJoin".equals(methodName)) { ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments(); if (arguments.getExpressions().size() != 1) { this.collectSyntaxError( new GinqSyntaxError( - "Only 1 argument expected for `from`, e.g. `from n in nums`", + "Only 1 argument expected for `" + methodName + "`, e.g. `" + methodName + " n in nums`", call.getLineNumber(), call.getColumnNumber() ) ); @@ -74,7 +76,7 @@ public class GinqAstBuilder extends CodeVisitorSupport { && ((BinaryExpression) expression).getOperation().getType() == Types.KEYWORD_IN)) { this.collectSyntaxError( new GinqSyntaxError( - "`in` is expected for `from`, e.g. `from n in nums`", + "`in` is expected for `" + methodName + "`, e.g. `" + methodName + " n in nums`", call.getLineNumber(), call.getColumnNumber() ) ); @@ -83,21 +85,39 @@ public class GinqAstBuilder extends CodeVisitorSupport { Expression aliasExpr = binaryExpression.getLeftExpression(); Expression dataSourceExpr = binaryExpression.getRightExpression(); - FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr); - fromExpression.setSourcePosition(call); + if ("from".equals(methodName)) { + FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr); + fromExpression.setSourcePosition(call); + simpleGinqExpression.addFromExpression(fromExpression); + ginqExpression = fromExpression; + } else if ("innerJoin".equals(methodName)) { + InnerJoinExpression innerJoinExpression = new InnerJoinExpression(aliasExpr, dataSourceExpr); + innerJoinExpression.setSourcePosition(call); + simpleGinqExpression.addJoinExpression(innerJoinExpression); + ginqExpression = innerJoinExpression; + } - simpleGinqExpression.addFromExpression(fromExpression); - ginqExpression = fromExpression; return; } - if ("where".equals(methodName)) { + if ("where".equals(methodName) || "on".equals(methodName)) { Expression filterExpr = ((ArgumentListExpression) call.getArguments()).getExpression(0); - WhereExpression whereExpression = new WhereExpression(filterExpr); - whereExpression.setSourcePosition(call); - if (ginqExpression instanceof FilterableExpression) { - ((FilterableExpression) ginqExpression).setWhereExpression(whereExpression); + FilterExpression filterExpression = null; + if ("where".equals(methodName)) { + filterExpression = new WhereExpression(filterExpr); + } else if ("on".equals(methodName)) { + filterExpression = new OnExpression(filterExpr); + } + + if (null == filterExpression) { + throw new GroovyBugError("Unknown method: " + methodName); + } + + filterExpression.setSourcePosition(call); + + if (ginqExpression instanceof FilterableExpression) { // TODO more strict check + ((FilterableExpression) ginqExpression).setFilterExpression(filterExpression); } else { throw new GroovyBugError("The preceding expression is not a FilterableExpression: " + ginqExpression); } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy index 098bd41..bbfe3cb 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy @@ -22,13 +22,19 @@ import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.apache.groovy.linq.dsl.expression.FromExpression import org.apache.groovy.linq.dsl.expression.GinqExpression -import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression +import org.apache.groovy.linq.dsl.expression.InnerJoinExpression +import org.apache.groovy.linq.dsl.expression.JoinExpression +import org.apache.groovy.linq.dsl.expression.OnExpression import org.apache.groovy.linq.dsl.expression.SelectExpression +import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression import org.apache.groovy.linq.dsl.expression.WhereExpression import org.codehaus.groovy.ast.ClassHelper import org.codehaus.groovy.ast.expr.ArgumentListExpression import org.codehaus.groovy.ast.expr.Expression +import org.codehaus.groovy.ast.expr.ExpressionTransformer +import org.codehaus.groovy.ast.expr.ListExpression import org.codehaus.groovy.ast.expr.MethodCallExpression +import org.codehaus.groovy.ast.expr.VariableExpression import static org.codehaus.groovy.ast.tools.GeneralUtils.callX import static org.codehaus.groovy.ast.tools.GeneralUtils.lambdaX @@ -43,20 +49,50 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt */ @CompileStatic class GinqBuilder implements GinqVisitor<Object> { + + public static final String __RECEIVER_ALIAS_EXPR = "__receiverAliasExpr" + public static final String __INNER_JOIN_METHOD_RECEIVER = "__inner_join_method_receiver" + public static final String __T = "__t" + public static final String __FIRST_ALIAS_EXPR = "__first_alias_expr" + public static final String __SECOND_ALIAS_EXPR = "__second_alias_expr" + @Override MethodCallExpression visitSimpleGinqExpression(SimpleGinqExpression simpleGinqExpression) { List<MethodCallExpression> fromMethodCallExpressionList = new LinkedList<>() List<FromExpression> fromExpressionList = simpleGinqExpression.getFromExpressionList() - for (FromExpression fromExpression : (fromExpressionList)) { + for (FromExpression fromExpression : fromExpressionList) { MethodCallExpression methodCallExpression = this.visitFromExpression(fromExpression) fromMethodCallExpressionList.add(methodCallExpression) } MethodCallExpression selectMethodReceiver = fromMethodCallExpressionList.getLast() + List<MethodCallExpression> innerJoinMethodCallExpressionList = new LinkedList<>() + List<JoinExpression> joinExpressionList = simpleGinqExpression.getJoinExpressionList() + for (JoinExpression joinExpression : joinExpressionList) { + joinExpression.putNodeMetaData(__INNER_JOIN_METHOD_RECEIVER, fromMethodCallExpressionList.getLast()) + joinExpression.putNodeMetaData(__RECEIVER_ALIAS_EXPR, fromExpressionList.get(fromExpressionList.size() - 1).aliasExpr) + MethodCallExpression methodCallExpression = this.visitInnerJoinExpression((InnerJoinExpression) joinExpression) + innerJoinMethodCallExpressionList.add(methodCallExpression); + } + + if (innerJoinMethodCallExpressionList) { + selectMethodReceiver = innerJoinMethodCallExpressionList.getLast() + } + SelectExpression selectExpression = simpleGinqExpression.getSelectExpression() selectExpression.putNodeMetaData(__SELECT_METHOD_RECEIVER, selectMethodReceiver) - selectExpression.putNodeMetaData(__ALIAS_EXPR, fromExpressionList.get(fromExpressionList.size() - 1).aliasExpr) + + if (joinExpressionList) { + JoinExpression lastJoinExpression = joinExpressionList.get(joinExpressionList.size() - 1) + selectExpression.putNodeMetaData(__FIRST_ALIAS_EXPR, lastJoinExpression.getNodeMetaData(__RECEIVER_ALIAS_EXPR)) + selectExpression.putNodeMetaData(__SECOND_ALIAS_EXPR, lastJoinExpression.aliasExpr) + + selectExpression.putNodeMetaData(__ALIAS_EXPR, new VariableExpression(__T)) + } else { + selectExpression.putNodeMetaData(__ALIAS_EXPR, fromExpressionList.get(fromExpressionList.size() - 1).aliasExpr) + } + MethodCallExpression selectMethodCallExpression = this.visitSelectExpression(selectExpression) @@ -67,7 +103,7 @@ class GinqBuilder implements GinqVisitor<Object> { MethodCallExpression visitFromExpression(FromExpression fromExpression) { MethodCallExpression fromMethodCallExpression = constructFromMethodCallExpression(fromExpression) - WhereExpression whereExpression = fromExpression.getWhereExpression() + WhereExpression whereExpression = (WhereExpression) fromExpression.getFilterExpression() if (whereExpression) { whereExpression.putNodeMetaData(__FROM_EXPRESSION, fromExpression) whereExpression.putNodeMetaData(__FROM_METHOD_CALL_EXPRESSION, fromMethodCallExpression) @@ -78,14 +114,47 @@ class GinqBuilder implements GinqVisitor<Object> { return fromMethodCallExpression } + @Override + MethodCallExpression visitInnerJoinExpression(InnerJoinExpression innerJoinExpression) { + Expression receiver = innerJoinExpression.getNodeMetaData(__INNER_JOIN_METHOD_RECEIVER) + Expression receiverAliasExpr = innerJoinExpression.getNodeMetaData(__RECEIVER_ALIAS_EXPR) + OnExpression onExpression = (OnExpression) innerJoinExpression.getFilterExpression() + MethodCallExpression innerJoinMethodCallExpression = constructInnerJoinMethodCallExpression(receiver, receiverAliasExpr, innerJoinExpression, onExpression) + + return innerJoinMethodCallExpression + } + + @Override + MethodCallExpression visitOnExpression(OnExpression onExpression) { + return null // do nothing + } + @CompileDynamic private MethodCallExpression constructFromMethodCallExpression(FromExpression fromExpression) { macro { - org.apache.groovy.linq.provider.QueryableCollection - .from($v { fromExpression.dataSourceExpr }) + org.apache.groovy.linq.provider.QueryableCollection.from($v { fromExpression.dataSourceExpr }) } } + @CompileDynamic + private MethodCallExpression constructInnerJoinMethodCallExpression(Expression receiver, Expression receiverAliasExpr, InnerJoinExpression innerJoinExpression, OnExpression onExpression) { + MethodCallExpression innerJoinMethodCallExpression = macro { + $v{receiver}.innerJoin(org.apache.groovy.linq.provider.QueryableCollection.from($v { innerJoinExpression.dataSourceExpr })) + } + + ((ArgumentListExpression) innerJoinMethodCallExpression.getArguments()).getExpressions().add( + lambdaX( + params( + param(ClassHelper.DYNAMIC_TYPE, receiverAliasExpr.text), + param(ClassHelper.DYNAMIC_TYPE, innerJoinExpression.aliasExpr.text) + ), + stmt(onExpression.getFilterExpr()) + ) + ) + + return innerJoinMethodCallExpression + } + @Override MethodCallExpression visitWhereExpression(WhereExpression whereExpression) { FromExpression fromExpression = whereExpression.getNodeMetaData(__FROM_EXPRESSION) @@ -97,7 +166,59 @@ class GinqBuilder implements GinqVisitor<Object> { MethodCallExpression visitSelectExpression(SelectExpression selectExpression) { Expression selectMethodReceiver = selectExpression.getNodeMetaData(__SELECT_METHOD_RECEIVER) Expression aliasExpr = selectExpression.getNodeMetaData(__ALIAS_EXPR) - return callXWithLambda(selectMethodReceiver, "select", aliasExpr.text, ((ArgumentListExpression) selectExpression.getProjectionExpr()).getExpression(0)) + Expression projectionExpr = selectExpression.getProjectionExpr() + + if (__T.equals(aliasExpr.text)) { + projectionExpr = correctVariablesOfProjectExpression(selectExpression, projectionExpr) + } + + List<Expression> expressionList = ((ArgumentListExpression) projectionExpr).getExpressions() + Expression lambdaCode + if (expressionList.size() > 1) { + lambdaCode = new ListExpression(expressionList) + } else { + lambdaCode = expressionList.get(0) + } + + return callXWithLambda(selectMethodReceiver, "select", aliasExpr.text, lambdaCode) + } + + private Expression correctVariablesOfProjectExpression(SelectExpression selectExpression, Expression projectionExpr) { + final Expression firstAliasExpr = selectExpression.getNodeMetaData(__FIRST_ALIAS_EXPR) + final Expression secondAliasExpr = selectExpression.getNodeMetaData(__SECOND_ALIAS_EXPR) + + projectionExpr = projectionExpr.transformExpression(new ExpressionTransformer() { + @Override + Expression transform(Expression expression) { + if (expression instanceof VariableExpression) { + Expression transformedExpression = null + if (firstAliasExpr.text == expression.text) { + // replace `n1` with `__t.v1` + transformedExpression = constructFirstAliasVariableAccess() + } else if (secondAliasExpr.text == expression.text) { + // replace `n2` with `__t.v2` + transformedExpression = constructSecondAliasVariableAccess() + } + + if (null != transformedExpression) { + return transformedExpression + } + } + + return expression.transformExpression(this) + } + }) + return projectionExpr + } + + @CompileDynamic + private Expression constructFirstAliasVariableAccess() { + macro { __t.v1 } + } + + @CompileDynamic + private Expression constructSecondAliasVariableAccess() { + macro { __t.v2 } } @Override diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java index 3ee3f4f..3e5f27e 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java @@ -20,8 +20,10 @@ package org.apache.groovy.linq.dsl; import org.apache.groovy.linq.dsl.expression.FromExpression; import org.apache.groovy.linq.dsl.expression.GinqExpression; -import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression; +import org.apache.groovy.linq.dsl.expression.InnerJoinExpression; +import org.apache.groovy.linq.dsl.expression.OnExpression; import org.apache.groovy.linq.dsl.expression.SelectExpression; +import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression; import org.apache.groovy.linq.dsl.expression.WhereExpression; /** @@ -33,6 +35,8 @@ import org.apache.groovy.linq.dsl.expression.WhereExpression; public interface GinqVisitor<R> { R visitSimpleGinqExpression(SimpleGinqExpression simpleGinqExpression); R visitFromExpression(FromExpression fromExpression); + R visitInnerJoinExpression(InnerJoinExpression innerJoinExpression); + R visitOnExpression(OnExpression onExpression); R visitWhereExpression(WhereExpression whereExpression); R visitSelectExpression(SelectExpression selectExpression); R visit(GinqExpression expression); diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterExpression.java similarity index 75% copy from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterExpression.java index 052347d..0fb4dde 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterExpression.java @@ -18,27 +18,25 @@ */ package org.apache.groovy.linq.dsl.expression; -import org.apache.groovy.linq.dsl.GinqVisitor; import org.codehaus.groovy.ast.expr.Expression; /** - * Represent the where expression + * Represents filter expression * * @since 4.0.0 */ -public class WhereExpression extends AbstractGinqExpression { - private final Expression filterExpr; +public abstract class FilterExpression extends AbstractGinqExpression { + protected Expression filterExpr; - public WhereExpression(Expression filterExpr) { + public FilterExpression(Expression filterExpr) { this.filterExpr = filterExpr; } - @Override - public <R> R accept(GinqVisitor<R> visitor) { - return visitor.visitWhereExpression(this); - } - public Expression getFilterExpr() { return filterExpr; } + + public void setFilterExpr(Expression filterExpr) { + this.filterExpr = filterExpr; + } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterableExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterableExpression.java index c0c1e8f..3ce3523 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterableExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterableExpression.java @@ -24,13 +24,13 @@ package org.apache.groovy.linq.dsl.expression; * @since 4.0.0 */ public abstract class FilterableExpression extends AbstractGinqExpression { - protected WhereExpression whereExpression; + protected FilterExpression filterExpression; - public WhereExpression getWhereExpression() { - return whereExpression; + public FilterExpression getFilterExpression() { + return filterExpression; } - public void setWhereExpression(WhereExpression whereExpression) { - this.whereExpression = whereExpression; + public void setFilterExpression(FilterExpression filterExpression) { + this.filterExpression = filterExpression; } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java index 248e9c0..b880cf8 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java @@ -53,7 +53,7 @@ public class FromExpression extends FilterableExpression { return "FromExpression{" + "aliasExpr=" + aliasExpr + ", dataSourceExpr=" + dataSourceExpr + - ", whereExpression=" + whereExpression + + ", whereExpression=" + filterExpression + '}'; } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/InnerJoinExpression.java similarity index 75% copy from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/InnerJoinExpression.java index 052347d..8df0377 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/InnerJoinExpression.java @@ -22,23 +22,18 @@ import org.apache.groovy.linq.dsl.GinqVisitor; import org.codehaus.groovy.ast.expr.Expression; /** - * Represent the where expression + * Represents inner join expression * * @since 4.0.0 */ -public class WhereExpression extends AbstractGinqExpression { - private final Expression filterExpr; +public class InnerJoinExpression extends JoinExpression { - public WhereExpression(Expression filterExpr) { - this.filterExpr = filterExpr; + public InnerJoinExpression(Expression aliasExpr, Expression dataSourceExpr) { + super(aliasExpr, dataSourceExpr); } @Override public <R> R accept(GinqVisitor<R> visitor) { - return visitor.visitWhereExpression(this); - } - - public Expression getFilterExpr() { - return filterExpr; + return visitor.visitInnerJoinExpression(this); } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/JoinExpression.java similarity index 64% copy from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/JoinExpression.java index 248e9c0..85debc4 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/JoinExpression.java @@ -18,26 +18,29 @@ */ package org.apache.groovy.linq.dsl.expression; -import org.apache.groovy.linq.dsl.GinqVisitor; import org.codehaus.groovy.ast.expr.Expression; /** - * Represents the from expression + * Represents join expression * * @since 4.0.0 */ -public class FromExpression extends FilterableExpression { - private final Expression aliasExpr; - private final Expression dataSourceExpr; +public abstract class JoinExpression extends FilterableExpression { + protected OnExpression onExpression; + protected Expression aliasExpr; + protected Expression dataSourceExpr; - public FromExpression(Expression aliasExpr, Expression dataSourceExpr) { + public JoinExpression(Expression aliasExpr, Expression dataSourceExpr) { this.aliasExpr = aliasExpr; this.dataSourceExpr = dataSourceExpr; } - @Override - public <R> R accept(GinqVisitor<R> visitor) { - return visitor.visitFromExpression(this); + public OnExpression getOnExpression() { + return onExpression; + } + + public void setOnExpression(OnExpression onExpression) { + this.onExpression = onExpression; } public Expression getAliasExpr() { @@ -47,13 +50,4 @@ public class FromExpression extends FilterableExpression { public Expression getDataSourceExpr() { return dataSourceExpr; } - - @Override - public String toString() { - return "FromExpression{" + - "aliasExpr=" + aliasExpr + - ", dataSourceExpr=" + dataSourceExpr + - ", whereExpression=" + whereExpression + - '}'; - } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/OnExpression.java similarity index 75% copy from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/OnExpression.java index 052347d..98394d7 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/OnExpression.java @@ -22,23 +22,17 @@ import org.apache.groovy.linq.dsl.GinqVisitor; import org.codehaus.groovy.ast.expr.Expression; /** - * Represent the where expression + * Represents on expression * * @since 4.0.0 */ -public class WhereExpression extends AbstractGinqExpression { - private final Expression filterExpr; - - public WhereExpression(Expression filterExpr) { - this.filterExpr = filterExpr; +public class OnExpression extends FilterExpression { + public OnExpression(Expression filterExpr) { + super(filterExpr); } @Override public <R> R accept(GinqVisitor<R> visitor) { - return visitor.visitWhereExpression(this); - } - - public Expression getFilterExpr() { - return filterExpr; + return visitor.visitOnExpression(this); } } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java index 21c00f4..23d59ed 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java @@ -30,6 +30,7 @@ import java.util.List; */ public class SimpleGinqExpression extends AbstractGinqExpression { private final List<FromExpression> fromExpressionList = new ArrayList<>(); + private final List<JoinExpression> joinExpressionList = new ArrayList<>(); private SelectExpression selectExpression; @Override @@ -45,6 +46,14 @@ public class SimpleGinqExpression extends AbstractGinqExpression { this.fromExpressionList.add(fromExpression); } + public List<JoinExpression> getJoinExpressionList() { + return joinExpressionList; + } + + public void addJoinExpression(JoinExpression joinExpression) { + joinExpressionList.add(joinExpression); + } + public SelectExpression getSelectExpression() { return selectExpression; } diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java index 052347d..66bde4f 100644 --- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java +++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java @@ -26,19 +26,13 @@ import org.codehaus.groovy.ast.expr.Expression; * * @since 4.0.0 */ -public class WhereExpression extends AbstractGinqExpression { - private final Expression filterExpr; - +public class WhereExpression extends FilterExpression { public WhereExpression(Expression filterExpr) { - this.filterExpr = filterExpr; + super(filterExpr); } @Override public <R> R accept(GinqVisitor<R> visitor) { return visitor.visitWhereExpression(this); } - - public Expression getFilterExpr() { - return filterExpr; - } } diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy index 1cdb0ef..96d04cb 100644 --- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy +++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy @@ -60,4 +60,18 @@ class GinqTest { }.toList() ''' } + + @Test + void "testGinq - from innerJoin select"() { + assertScript ''' + def nums1 = [1, 2, 3] + def nums2 = [1, 2, 3] + assert [[1, 1], [2, 2], [3, 3]] == GINQ { + from n1 in nums1 + innerJoin n2 in nums2 + on n1 == n2 + select n1, n2 + }.toList() + ''' + } }
