You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/10/06 13:36:25 UTC

[groovy] branch GROOVY-8258 updated (189c37e -> fd4169e)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY-8258
in repository https://gitbox.apache.org/repos/asf/groovy.git.


 discard 189c37e  GROOVY-8258: add more test cases
 discard 7debbb0  GROOVY-8258: trivial refactoring
 discard eaf593b  GROOVY-8258: Implement inner join
 discard 2e38c1e  GROOVY-8258: Add 1 more error test
 discard b1650bb  GROOVY-8258: Add node positions and error tests
 discard 2dc31d2  GROOVY-8258: Use `in` instead of `of` for better readability
 discard 3cd8edd  GROOVY-8258: make field `final`
 discard 0b14276  GROOVY-8258: Rename class name
 discard aa0f0b1  GROOVY-8258: add javadoc and rename linq to ginq
 discard a6d4c4e  GROOVY-8258: build AST for ginq and generate target method calls
 discard 843a0e2  GROOVY-8258: rename linq to ginq
 discard 4095e46  GROOVY-8258: enable STC
 discard 84c51fc  GROOVY-8258: use lambda instead
 discard 3d37138  GROOVY-8258: rename test names
 discard 606c5d9  GROOVY-8258: Add 2 test cases
 discard 9d300b1  GROOVY-8258: minor refactor
 discard fcb8590  GROOVY-8258: Implement the very basic LINQ
 discard a950f51  GROOVY-8258: mark backend classes as internal
 discard 85879be  GROOVY-8258: test `stream` method and tweak tests
 discard 4e488cb  GROOVY-8258: Add macro method LINQ
 discard 40c6f79  GROOVY-8258: Add macro method LINQ entry
 discard fed55e0  GROOVY-8258: Implement the built-in collection LINQ provider
     add 7cf8724  GROOVY-9769: avoid unnecessary creation of UnionTypeClassNode (closes #1394)
     new ac92248  GROOVY-8258: Implement the built-in collection LINQ provider
     new 3e39e70  GROOVY-8258: Add macro method LINQ entry
     new e233f34  GROOVY-8258: Add macro method LINQ
     new ffde533  GROOVY-8258: test `stream` method and tweak tests
     new 2610bac  GROOVY-8258: mark backend classes as internal
     new 1ab90b5  GROOVY-8258: Implement the very basic LINQ
     new 174b227  GROOVY-8258: minor refactor
     new 9ff78df  GROOVY-8258: Add 2 test cases
     new 581ee95  GROOVY-8258: rename test names
     new 0c7a6fe  GROOVY-8258: use lambda instead
     new 189c49d  GROOVY-8258: enable STC
     new d355e9c  GROOVY-8258: rename linq to ginq
     new 7273eed  GROOVY-8258: build AST for ginq and generate target method calls
     new d413188  GROOVY-8258: add javadoc and rename linq to ginq
     new 9f92fc8  GROOVY-8258: Rename class name
     new b69bf21  GROOVY-8258: make field `final`
     new 2318b69  GROOVY-8258: Use `in` instead of `of` for better readability
     new b94d20f  GROOVY-8258: Add node positions and error tests
     new 0707349  GROOVY-8258: Add 1 more error test
     new e8e95d8  GROOVY-8258: Implement inner join
     new c7f0f4d  GROOVY-8258: trivial refactoring
     new fd4169e  GROOVY-8258: add more test cases

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (189c37e)
            \
             N -- N -- N   refs/heads/GROOVY-8258 (fd4169e)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 22 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transform/stc/StaticTypeCheckingVisitor.java   | 27 +++++++-------
 .../classgen/asm/sc/bugs/Groovy7333Bug.groovy      | 43 +++++++++++++++++++---
 2 files changed, 51 insertions(+), 19 deletions(-)


[groovy] 13/22: GROOVY-8258: build AST for ginq and generate target method calls

Posted by su...@apache.org.
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 7273eed4ed4a4f0a90ce517b78748c6721b65c18
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 20:47:43 2020 +0800

    GROOVY-8258: build AST for ginq and generate target method calls
---
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 116 ++------------------
 .../org/apache/groovy/linq/dsl/GinqAstBuilder.java |  67 ++++++++++++
 .../org/apache/groovy/linq/dsl/GinqBuilder.groovy  | 118 +++++++++++++++++++++
 .../org/apache/groovy/linq/dsl/GinqVisitor.java    |  33 ++++++
 .../dsl/expression/AbstractGinqExpression.java     |  20 ++++
 .../linq/dsl/expression/FilterableExpression.java  |  31 ++++++
 .../groovy/linq/dsl/expression/FromExpression.java |  54 ++++++++++
 .../groovy/linq/dsl/expression/GinqExpression.java |  25 +++++
 .../groovy/linq/dsl/expression/RootExpression.java |  58 ++++++++++
 .../linq/dsl/expression/SelectExpression.java      |  46 ++++++++
 .../linq/dsl/expression/WhereExpression.java       |  39 +++++++
 11 files changed, 501 insertions(+), 106 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index 70a9596..4d9af35 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -18,126 +18,30 @@
  */
 package org.apache.groovy.linq
 
-import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
-import groovy.transform.ToString
-import org.codehaus.groovy.ast.ClassHelper
-import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.apache.groovy.linq.dsl.GinqAstBuilder
+import org.apache.groovy.linq.dsl.GinqBuilder
+import org.apache.groovy.linq.dsl.expression.RootExpression
 import org.codehaus.groovy.ast.expr.ClosureExpression
 import org.codehaus.groovy.ast.expr.Expression
 import org.codehaus.groovy.ast.expr.MethodCallExpression
-import org.codehaus.groovy.ast.expr.VariableExpression
-import org.codehaus.groovy.ast.stmt.BlockStatement
-import org.codehaus.groovy.ast.stmt.ExpressionStatement
 import org.codehaus.groovy.ast.stmt.Statement
 import org.codehaus.groovy.macro.runtime.Macro
 import org.codehaus.groovy.macro.runtime.MacroContext
 
-import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.lambdaX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.param
-import static org.codehaus.groovy.ast.tools.GeneralUtils.params
-import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
-
 @CompileStatic
 class LinqGroovyMethods {
     @Macro
     static Expression GINQ(MacroContext ctx, final ClosureExpression closureExpression) {
-        BlockStatement code = (BlockStatement) closureExpression.getCode()
-        List<Statement> statementList = code.getStatements()
-
-        LinqContext linqContext = new LinqContext()
-        for (Statement statement : statementList) {
-            ExpressionStatement expressionStatement = (ExpressionStatement) statement
-            MethodCallExpression methodCallExpression = (MethodCallExpression) expressionStatement.getExpression()
-
-            String methodName = methodCallExpression.getMethodAsString()
-            switch (methodName) {
-                case 'from': {
-                    break
-                }
-                case 'of': {
-                    MethodCallExpression fromMethodCallExpression = (MethodCallExpression) methodCallExpression.getObjectExpression()
-                    VariableExpression aliasVariable = (VariableExpression) ((ArgumentListExpression) fromMethodCallExpression.getArguments()).getExpression(0)
-                    Expression dataSourceExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
-                    linqContext.addFrom(aliasVariable, dataSourceExpression)
-                    break
-                }
-                case 'where': {
-                    Expression conditionExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
-                    linqContext.addWhere(conditionExpression)
-                    break
-                }
-                case 'select': {
-                    Expression selectExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
-                    linqContext.addSelect(selectExpression)
-                    break
-                }
-                default: {
-                    break
-                }
-            }
-        }
-
-        constructLinqMethodCalls(linqContext)
-    }
+        Statement code = closureExpression.getCode()
 
-    private static Expression constructLinqMethodCalls(LinqContext linqContext) {
-        Map.Entry<VariableExpression, Expression> fromEntry = linqContext.fromMap.entrySet().toList().get(0)
-        VariableExpression aliasVariable = fromEntry.key
+        GinqAstBuilder ginqAstBuilder = new GinqAstBuilder()
+        code.visit(ginqAstBuilder)
+        RootExpression rootExpression = ginqAstBuilder.getRootExpression()
 
-        Expression selectMethodReceiver = null
+        GinqBuilder ginqBuilder = new GinqBuilder()
+        MethodCallExpression selectMethodCallExpression = ginqBuilder.visitRootExpression(rootExpression)
 
-        MethodCallExpression from = constructFromMethodCall(fromEntry)
-
-        selectMethodReceiver = from
-
-        if (linqContext.whereList.size() > 0) {
-            MethodCallExpression where = callXWithLambda(from, "where", aliasVariable.name, linqContext.whereList[0])
-            selectMethodReceiver = where
-        }
-
-        MethodCallExpression select = callXWithLambda(selectMethodReceiver, "select", aliasVariable.name, linqContext.selectList[0])
-
-        return select
-    }
-
-    @CompileDynamic
-    private static MethodCallExpression constructFromMethodCall(fromEntry) {
-        macro {
-            org.apache.groovy.linq.provider.QueryableCollection
-                    .from($v { fromEntry.value })
-        }
-    }
-
-    private static MethodCallExpression callXWithLambda(Expression receiver, String methodName, String lambdaParamName, Expression lambdaCode) {
-        callX(
-                receiver,
-                methodName,
-                lambdaX(
-                        params(param(ClassHelper.DYNAMIC_TYPE, lambdaParamName)),
-                        stmt(lambdaCode)
-                )
-        )
-    }
-
-    @ToString(includeNames=true)
-    static class LinqContext {
-        Map<VariableExpression, Expression> fromMap = new LinkedHashMap<>()
-        List<Expression> whereList = new ArrayList<>()
-        List<Expression> selectList = new ArrayList<>()
-
-        void addFrom(VariableExpression aliasVariable, Expression dataSourceExpression) {
-            fromMap.put(aliasVariable, dataSourceExpression)
-        }
-
-        void addWhere(Expression... conditionExpressions) {
-            whereList.addAll(conditionExpressions)
-        }
-
-        void addSelect(Expression... selectExpressions) {
-            selectList.addAll(selectExpressions)
-        }
+        return selectMethodCallExpression
     }
 }
-
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
new file mode 100644
index 0000000..e2bec3f
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java
@@ -0,0 +1,67 @@
+package org.apache.groovy.linq.dsl;
+
+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.RootExpression;
+import org.apache.groovy.linq.dsl.expression.SelectExpression;
+import org.apache.groovy.linq.dsl.expression.WhereExpression;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+
+public class GinqAstBuilder extends CodeVisitorSupport {
+    private RootExpression rootExpression = new RootExpression(); // store the result
+    private GinqExpression ginqExpression; // store the return value
+
+    public RootExpression getRootExpression() {
+        return rootExpression;
+    }
+
+    @Override
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        super.visitMethodCallExpression(call);
+        final String methodName = call.getMethodAsString();
+        System.out.println(methodName + " : " + call);
+
+        if ("from".equals(methodName)) {
+            return;
+        }
+
+        if ("of".equals(methodName)) {
+            MethodCallExpression fromMethodCallExpression = (MethodCallExpression) call.getObjectExpression();
+            Expression aliasExpr = ((ArgumentListExpression) fromMethodCallExpression.getArguments()).getExpression(0);
+            Expression dataSourceExpr = ((ArgumentListExpression) call.getArguments()).getExpression(0);
+
+            FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr);
+            rootExpression.addFromExpression(fromExpression);
+
+            ginqExpression = fromExpression;
+            return;
+        }
+
+        if ("where".equals(methodName)) {
+            Expression filterExpr = ((ArgumentListExpression) call.getArguments()).getExpression(0);
+            WhereExpression whereExpression = new WhereExpression(filterExpr);
+
+            if (ginqExpression instanceof FilterableExpression) {
+                ((FilterableExpression) ginqExpression).setWhereExpression(whereExpression);
+            } else {
+                throw new GroovyBugError("The preceding expression is not a FilterableExpression: " + ginqExpression);
+            }
+
+            return;
+        }
+
+        if ("select".equals(methodName)) {
+            SelectExpression selectExpression = new SelectExpression(call.getArguments());
+            rootExpression.setSelectExpression(selectExpression);
+
+            ginqExpression = selectExpression;
+
+            return;
+        }
+    }
+}
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
new file mode 100644
index 0000000..8cbb86b
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl
+
+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.RootExpression
+import org.apache.groovy.linq.dsl.expression.SelectExpression
+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.MethodCallExpression
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.lambdaX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
+
+@CompileStatic
+class GinqBuilder implements GinqVisitor<Object> {
+    @Override
+    MethodCallExpression visitRootExpression(RootExpression rootExpression) {
+        List<MethodCallExpression> fromMethodCallExpressionList = new LinkedList<>()
+        List<FromExpression> fromExpressionList = rootExpression.getFromExpressionList()
+        for (FromExpression fromExpression : (fromExpressionList)) {
+            MethodCallExpression methodCallExpression = this.visitFromExpression(fromExpression)
+            fromMethodCallExpressionList.add(methodCallExpression)
+        }
+
+        MethodCallExpression selectMethodReceiver = fromMethodCallExpressionList.getLast()
+
+        SelectExpression selectExpression = rootExpression.getSelectExpression()
+        selectExpression.putNodeMetaData(__SELECT_METHOD_RECEIVER, selectMethodReceiver)
+        selectExpression.putNodeMetaData(__ALIAS_EXPR, fromExpressionList.get(fromExpressionList.size() - 1).aliasExpr)
+        MethodCallExpression selectMethodCallExpression = this.visitSelectExpression(selectExpression)
+
+
+        return selectMethodCallExpression
+    }
+
+    @Override
+    MethodCallExpression visitFromExpression(FromExpression fromExpression) {
+        MethodCallExpression fromMethodCallExpression = constructFromMethodCallExpression(fromExpression)
+
+        WhereExpression whereExpression = fromExpression.getWhereExpression()
+        if (whereExpression) {
+            whereExpression.putNodeMetaData(__FROM_EXPRESSION, fromExpression)
+            whereExpression.putNodeMetaData(__FROM_METHOD_CALL_EXPRESSION, fromMethodCallExpression)
+
+            return visitWhereExpression(whereExpression)
+        }
+
+        return fromMethodCallExpression
+    }
+
+    @CompileDynamic
+    private MethodCallExpression constructFromMethodCallExpression(FromExpression fromExpression) {
+        macro {
+            org.apache.groovy.linq.provider.QueryableCollection
+                    .from($v { fromExpression.dataSourceExpr })
+        }
+    }
+
+    @Override
+    MethodCallExpression visitWhereExpression(WhereExpression whereExpression) {
+        FromExpression fromExpression = whereExpression.getNodeMetaData(__FROM_EXPRESSION)
+        Expression fromMethodCallExpression = whereExpression.getNodeMetaData(__FROM_METHOD_CALL_EXPRESSION)
+        return callXWithLambda(fromMethodCallExpression, "where", fromExpression.aliasExpr.text, whereExpression.getFilterExpr())
+    }
+
+    @Override
+    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))
+    }
+
+    @Override
+    Object visit(GinqExpression expression) {
+        return expression.accept(this)
+    }
+
+    private static MethodCallExpression callXWithLambda(Expression receiver, String methodName, String lambdaParamName, Expression lambdaCode) {
+        callX(
+                receiver,
+                methodName,
+                lambdaX(
+                        params(param(ClassHelper.DYNAMIC_TYPE, lambdaParamName)),
+                        stmt(lambdaCode)
+                )
+        )
+    }
+
+    private static final String __FROM_EXPRESSION = "__fromExpression"
+    private static final String __FROM_METHOD_CALL_EXPRESSION = "__fromMethodCallExpression"
+    private static final String __SELECT_METHOD_RECEIVER = "__selectMethodReceiver"
+    private static final String __ALIAS_EXPR = "__aliasExpr"
+}
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
new file mode 100644
index 0000000..4e7c242
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package 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.RootExpression;
+import org.apache.groovy.linq.dsl.expression.SelectExpression;
+import org.apache.groovy.linq.dsl.expression.WhereExpression;
+
+public interface GinqVisitor<R> {
+    R visitRootExpression(RootExpression rootExpression);
+    R visitFromExpression(FromExpression fromExpression);
+    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/AbstractGinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
new file mode 100644
index 0000000..25e4e84
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
@@ -0,0 +1,20 @@
+package org.apache.groovy.linq.dsl.expression;
+
+import org.codehaus.groovy.ast.NodeMetaDataHandler;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public abstract class AbstractGinqExpression implements GinqExpression, NodeMetaDataHandler {
+    private Map<?, ?> metaDataMap = new LinkedHashMap<>();
+
+    @Override
+    public Map<?, ?> getMetaDataMap() {
+        return metaDataMap;
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        this.metaDataMap = metaDataMap;
+    }
+}
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
new file mode 100644
index 0000000..d739e21
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FilterableExpression.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+public abstract class FilterableExpression extends AbstractGinqExpression {
+    protected WhereExpression whereExpression;
+
+    public WhereExpression getWhereExpression() {
+        return whereExpression;
+    }
+
+    public void setWhereExpression(WhereExpression whereExpression) {
+        this.whereExpression = whereExpression;
+    }
+}
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
new file mode 100644
index 0000000..4c212e4
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/FromExpression.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+import org.apache.groovy.linq.dsl.GinqVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+public class FromExpression extends FilterableExpression {
+    private final Expression aliasExpr;
+    private final Expression dataSourceExpr;
+
+    public FromExpression(Expression aliasExpr, Expression dataSourceExpr) {
+        this.aliasExpr = aliasExpr;
+        this.dataSourceExpr = dataSourceExpr;
+    }
+
+    @Override
+    public <R> R accept(GinqVisitor<R> visitor) {
+        return visitor.visitFromExpression(this);
+    }
+
+    public Expression getAliasExpr() {
+        return aliasExpr;
+    }
+
+    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/GinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java
new file mode 100644
index 0000000..22ef3ff
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java
@@ -0,0 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+import org.apache.groovy.linq.dsl.GinqVisitor;
+
+public interface GinqExpression {
+    <R> R accept(GinqVisitor<R> visitor);
+}
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
new file mode 100644
index 0000000..d4ddf0c
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+import org.apache.groovy.linq.dsl.GinqVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RootExpression extends AbstractGinqExpression {
+    private List<FromExpression> fromExpressionList = new ArrayList<>();
+    private SelectExpression selectExpression;
+
+    @Override
+    public <R> R accept(GinqVisitor<R> visitor) {
+        return visitor.visitRootExpression(this);
+    }
+
+    public List<FromExpression> getFromExpressionList() {
+        return fromExpressionList;
+    }
+
+    public void addFromExpression(FromExpression fromExpression) {
+        this.fromExpressionList.add(fromExpression);
+    }
+
+    public SelectExpression getSelectExpression() {
+        return selectExpression;
+    }
+
+    public void setSelectExpression(SelectExpression selectExpression) {
+        this.selectExpression = selectExpression;
+    }
+
+    @Override
+    public String toString() {
+        return "RootExpression{" +
+                "fromExpressionList=" + fromExpressionList +
+                ", selectExpression=" + selectExpression +
+                '}';
+    }
+}
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java
new file mode 100644
index 0000000..0cd3429
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+import org.apache.groovy.linq.dsl.GinqVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+public class SelectExpression extends AbstractGinqExpression {
+    private final Expression projectionExpr;
+
+    public SelectExpression(Expression projectionExpr) {
+        this.projectionExpr = projectionExpr;
+    }
+
+    @Override
+    public <R> R accept(GinqVisitor<R> visitor) {
+        return visitor.visitSelectExpression(this);
+    }
+
+    public Expression getProjectionExpr() {
+        return projectionExpr;
+    }
+
+    @Override
+    public String toString() {
+        return "SelectExpression{" +
+                "projectionExpr=" + projectionExpr +
+                '}';
+    }
+}
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
new file mode 100644
index 0000000..b23ba94
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/WhereExpression.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl.expression;
+
+import org.apache.groovy.linq.dsl.GinqVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+public class WhereExpression extends AbstractGinqExpression {
+    private final Expression filterExpr;
+
+    public WhereExpression(Expression filterExpr) {
+        this.filterExpr = filterExpr;
+    }
+
+    @Override
+    public <R> R accept(GinqVisitor<R> visitor) {
+        return visitor.visitWhereExpression(this);
+    }
+
+    public Expression getFilterExpr() {
+        return filterExpr;
+    }
+}


[groovy] 04/22: GROOVY-8258: test `stream` method and tweak tests

Posted by su...@apache.org.
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 ffde5337d791a27aab75fe118cf5816691722e6c
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 01:02:27 2020 +0800

    GROOVY-8258: test `stream` method and tweak tests
---
 .../linq/provider/QueryableCollectionTest.groovy   | 104 +++++++++++----------
 1 file changed, 54 insertions(+), 50 deletions(-)

diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy
index be20ea6..344ffa4 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy
@@ -26,21 +26,24 @@ import groovy.transform.ToString
 import org.apache.groovy.linq.Queryable
 import org.junit.Test
 
+import java.util.stream.Collectors
 import java.util.stream.Stream
 
+import static org.apache.groovy.linq.provider.QueryableCollection.from
+
 @CompileStatic
 class QueryableCollectionTest {
     @Test
     void testFrom() {
-        assert [1, 2, 3] == QueryableCollection.from(Stream.of(1, 2, 3)).toList()
-        assert [1, 2, 3] == QueryableCollection.from(Arrays.asList(1, 2, 3)).toList()
+        assert [1, 2, 3] == from(Stream.of(1, 2, 3)).toList()
+        assert [1, 2, 3] == from(Arrays.asList(1, 2, 3)).toList()
     }
 
     @Test
     void testInnerJoin0() {
         def nums1 = [1, 2, 3]
         def nums2 = [1, 2, 3]
-        def result = QueryableCollection.from(nums1).innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).innerJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, 1], [2, 2], [3, 3]] == result
     }
 
@@ -48,7 +51,7 @@ class QueryableCollectionTest {
     void testInnerJoin1() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).innerJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[2, 2], [3, 3]] == result
     }
 
@@ -56,7 +59,7 @@ class QueryableCollectionTest {
     void testLeftJoin0() {
         def nums1 = [1, 2, 3]
         def nums2 = [1, 2, 3]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, 1], [2, 2], [3, 3]] == result
     }
 
@@ -64,7 +67,7 @@ class QueryableCollectionTest {
     void testRightJoin0() {
         def nums2 = [1, 2, 3]
         def nums1 = [1, 2, 3]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, 1], [2, 2], [3, 3]] == result
     }
 
@@ -72,7 +75,7 @@ class QueryableCollectionTest {
     void testLeftJoin1() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3]] == result
     }
 
@@ -80,7 +83,7 @@ class QueryableCollectionTest {
     void testRightJoin1() {
         def nums2 = [1, 2, 3]
         def nums1 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3]] == result
     }
 
@@ -88,7 +91,7 @@ class QueryableCollectionTest {
     void testLeftJoin2() {
         def nums1 = [1, 2, 3, null]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -96,7 +99,7 @@ class QueryableCollectionTest {
     void testRightJoin2() {
         def nums2 = [1, 2, 3, null]
         def nums1 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -104,7 +107,7 @@ class QueryableCollectionTest {
     void testLeftJoin3() {
         def nums1 = [1, 2, 3, null]
         def nums2 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -112,7 +115,7 @@ class QueryableCollectionTest {
     void testRightJoin3() {
         def nums2 = [1, 2, 3, null]
         def nums1 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -120,7 +123,7 @@ class QueryableCollectionTest {
     void testLeftJoin4() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3]] == result
     }
 
@@ -128,7 +131,7 @@ class QueryableCollectionTest {
     void testRightJoin4() {
         def nums2 = [1, 2, 3]
         def nums1 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3]] == result
     }
 
@@ -136,7 +139,7 @@ class QueryableCollectionTest {
     void testLeftJoin5() {
         def nums1 = [1, 2, 3, null, null]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -144,7 +147,7 @@ class QueryableCollectionTest {
     void testRightJoin5() {
         def nums2 = [1, 2, 3, null, null]
         def nums1 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -152,7 +155,7 @@ class QueryableCollectionTest {
     void testLeftJoin6() {
         def nums1 = [1, 2, 3, null, null]
         def nums2 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -160,7 +163,7 @@ class QueryableCollectionTest {
     void testRightJoin6() {
         def nums2 = [1, 2, 3, null, null]
         def nums1 = [2, 3, 4, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -168,7 +171,7 @@ class QueryableCollectionTest {
     void testLeftJoin7() {
         def nums1 = [1, 2, 3, null, null]
         def nums2 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -176,7 +179,7 @@ class QueryableCollectionTest {
     void testRightJoin7() {
         def nums2 = [1, 2, 3, null, null]
         def nums1 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
     }
 
@@ -184,7 +187,7 @@ class QueryableCollectionTest {
     void testLeftJoin8() {
         def nums1 = [1, 2, 3, null]
         def nums2 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -192,7 +195,7 @@ class QueryableCollectionTest {
     void testRightJoin8() {
         def nums2 = [1, 2, 3, null]
         def nums1 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
     }
 
@@ -200,7 +203,7 @@ class QueryableCollectionTest {
     void testLeftJoin9() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).leftJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3]] == result
     }
 
@@ -208,7 +211,7 @@ class QueryableCollectionTest {
     void testRightJoin9() {
         def nums2 = [1, 2, 3]
         def nums1 = [2, 3, 4, null, null]
-        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).rightJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[null, 1], [2, 2], [3, 3]] == result
     }
 
@@ -216,7 +219,7 @@ class QueryableCollectionTest {
     void testFullJoin() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).fullJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        def result = from(nums1).fullJoin(from(nums2), (a, b) -> a == b).toList()
         assert [[1, null], [2, 2], [3, 3], [null, 4]] == result
     }
 
@@ -224,28 +227,28 @@ class QueryableCollectionTest {
     void testCrossJoin() {
         def nums1 = [1, 2, 3]
         def nums2 = [3, 4, 5]
-        def result = QueryableCollection.from(nums1).crossJoin(QueryableCollection.from(nums2)).toList()
+        def result = from(nums1).crossJoin(from(nums2)).toList()
         assert [[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 3], [3, 4], [3, 5]] == result
     }
 
     @Test
     void testWhere() {
         def nums = [1, 2, 3, 4, 5]
-        def result = QueryableCollection.from(nums).where(e -> e > 3).toList()
+        def result = from(nums).where(e -> e > 3).toList()
         assert [4, 5] == result
     }
 
     @Test
     void testGroupBySelect0() {
         def nums = [1, 2, 2, 3, 3, 4, 4, 5]
-        def result = QueryableCollection.from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.toList())).toList()
+        def result = from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.toList())).toList()
         assert [[1, [1]], [2, [2, 2]], [3, [3, 3]], [4, [4, 4]], [5, [5]]] == result
     }
 
     @Test
     void testGroupBySelect1() {
         def nums = [1, 2, 2, 3, 3, 4, 4, 5]
-        def result = QueryableCollection.from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.count())).toList()
+        def result = from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.count())).toList()
         assert [[1, 1], [2, 2], [3, 2], [4, 2], [5, 1]] == result
     }
 
@@ -253,7 +256,7 @@ class QueryableCollectionTest {
     void testGroupBySelect2() {
         def nums = [1, 2, 2, 3, 3, 4, 4, 5]
         def result =
-                QueryableCollection.from(nums).groupBy(e -> e)
+                from(nums).groupBy(e -> e)
                         .select(e ->
                                 Tuple.tuple(
                                         e.v1,
@@ -269,7 +272,7 @@ class QueryableCollectionTest {
     void testGroupBySelect3() {
         def nums = [1, 2, 2, 3, 3, 4, 4, 5]
         def result =
-                QueryableCollection.from(nums).groupBy(e -> e, (k, q) -> k > 2)
+                from(nums).groupBy(e -> e, (k, q) -> k > 2)
                         .select(e ->
                                 Tuple.tuple(
                                         e.v1,
@@ -288,25 +291,25 @@ class QueryableCollectionTest {
         Person john = new Person('John', 10)
 
         def persons = [daniel, peter, alice, john]
-        def result = QueryableCollection.from(persons).orderBy(
+        def result = from(persons).orderBy(
                 new Queryable.Order<Person, Comparable>((Person e) -> e.age, true),
                 new Queryable.Order<Person, Comparable>((Person e) -> e.name, true)
         ).toList()
         assert [john, peter, alice, daniel] == result
 
-        result = QueryableCollection.from(persons).orderBy(
+        result = from(persons).orderBy(
                 new Queryable.Order<Person, Comparable>((Person e) -> e.age, false),
                 new Queryable.Order<Person, Comparable>((Person e) -> e.name, true)
         ).toList()
         assert [daniel, alice, john, peter] == result
 
-        result = QueryableCollection.from(persons).orderBy(
+        result = from(persons).orderBy(
                 new Queryable.Order<Person, Comparable>((Person e) -> e.age, true),
                 new Queryable.Order<Person, Comparable>((Person e) -> e.name, false)
         ).toList()
         assert [peter, john, alice, daniel] == result
 
-        result = QueryableCollection.from(persons).orderBy(
+        result = from(persons).orderBy(
                 new Queryable.Order<Person, Comparable>((Person e) -> e.age, false),
                 new Queryable.Order<Person, Comparable>((Person e) -> e.name, false)
         ).toList()
@@ -316,24 +319,24 @@ class QueryableCollectionTest {
     @Test
     void testLimit() {
         def nums = [1, 2, 3, 4, 5]
-        def result = QueryableCollection.from(nums).limit(1, 2).toList()
+        def result = from(nums).limit(1, 2).toList()
         assert [2, 3] == result
 
-        result = QueryableCollection.from(nums).limit(2).toList()
+        result = from(nums).limit(2).toList()
         assert [1, 2] == result
     }
 
     @Test
     void testSelect() {
         def nums = [1, 2, 3, 4, 5]
-        def result = QueryableCollection.from(nums).select(e -> e + 1).toList()
+        def result = from(nums).select(e -> e + 1).toList()
         assert [2, 3, 4, 5, 6] == result
     }
 
     @Test
     void testDistinct() {
         def nums = [1, 2, 2, 3, 3, 2, 3, 4, 5, 5]
-        def result = QueryableCollection.from(nums).distinct().toList()
+        def result = from(nums).distinct().toList()
         assert [1, 2, 3, 4, 5] == result
     }
 
@@ -341,7 +344,7 @@ class QueryableCollectionTest {
     void testUnion() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).union(QueryableCollection.from(nums2)).toList()
+        def result = from(nums1).union(from(nums2)).toList()
         assert [1, 2, 3, 4] == result
     }
 
@@ -349,7 +352,7 @@ class QueryableCollectionTest {
     void testUnionAll() {
         def nums1 = [1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).unionAll(QueryableCollection.from(nums2)).toList()
+        def result = from(nums1).unionAll(from(nums2)).toList()
         assert [1, 2, 3, 2, 3, 4] == result
     }
 
@@ -357,7 +360,7 @@ class QueryableCollectionTest {
     void testIntersect() {
         def nums1 = [1, 2, 2, 3]
         def nums2 = [2, 3, 3, 4]
-        def result = QueryableCollection.from(nums1).intersect(QueryableCollection.from(nums2)).toList()
+        def result = from(nums1).intersect(from(nums2)).toList()
         assert [2, 3] == result
     }
 
@@ -365,7 +368,7 @@ class QueryableCollectionTest {
     void testMinus() {
         def nums1 = [1, 1, 2, 3]
         def nums2 = [2, 3, 4]
-        def result = QueryableCollection.from(nums1).minus(QueryableCollection.from(nums2)).toList()
+        def result = from(nums1).minus(from(nums2)).toList()
         assert [1] == result
     }
 
@@ -374,8 +377,8 @@ class QueryableCollectionTest {
         def nums1 = [1, 2, 3, 4, 5]
         def nums2 = [0, 1, 2, 3, 4, 5, 6]
         def result =
-                QueryableCollection.from(nums1)
-                        .innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b)
+                from(nums1)
+                        .innerJoin(from(nums2), (a, b) -> a == b)
                         .where(t -> t.v1 > 1)
                         .limit(1, 2)
                         .select(t -> t.v1 + 1)
@@ -383,11 +386,12 @@ class QueryableCollectionTest {
         assert [4, 5] == result
     }
 
-//    @Test void testIterator() {
-//        def nums = [1, 2, 3]
-//        def result = from(nums).iterator().toList()
-//        assert nums == result
-//    }
+    @Test
+    void testStream() {
+        def nums = [1, 2, 3]
+        def result = from(nums).stream().collect(Collectors.toList())
+        assert nums == result
+    }
 
     @ToString
     @EqualsAndHashCode


[groovy] 07/22: GROOVY-8258: minor refactor

Posted by su...@apache.org.
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 174b2270c6e392e8de290316d030e0784d6b90d7
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:17:33 2020 +0800

    GROOVY-8258: minor refactor
---
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 32 +++++++++-------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index cd6b502..ff368fb 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -88,29 +88,23 @@ class LinqGroovyMethods {
                     .from($v { fromEntry.value })
         }
 
-        MethodCallExpression where =
-                callX(
-                        from,
-                        "where",
-                        closureX(
-                                params(param(ClassHelper.DYNAMIC_TYPE, aliasVariable.name)),
-                                stmt(linqContext.whereList[0])
-                        )
-                )
-
-        MethodCallExpression select =
-                callX(
-                        where,
-                        "select",
-                        closureX(
-                                params(param(ClassHelper.DYNAMIC_TYPE, aliasVariable.name)),
-                                stmt(linqContext.selectList[0])
-                        )
-                )
+        MethodCallExpression where = callXWithClosure(from, "where", aliasVariable.name, linqContext.whereList[0])
+        MethodCallExpression select = callXWithClosure(where, "select", aliasVariable.name, linqContext.selectList[0])
 
         return select
     }
 
+    private static callXWithClosure(Expression receiver, String methodName, String closureParamName, Expression closureCode) {
+        callX(
+                receiver,
+                methodName,
+                closureX(
+                        params(param(ClassHelper.DYNAMIC_TYPE, closureParamName)),
+                        stmt(closureCode)
+                )
+        )
+    }
+
     @ToString(includeNames=true)
     static class LinqContext {
         Map<VariableExpression, Expression> fromMap = new LinkedHashMap<>()


[groovy] 15/22: GROOVY-8258: Rename class name

Posted by su...@apache.org.
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 9f92fc8615ddd111666e5351c025c403f18ef8bd
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 22:20:53 2020 +0800

    GROOVY-8258: Rename class name
---
 .../groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy   |  6 +++---
 .../groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java    | 12 ++++++------
 .../groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy     |  8 ++++----
 .../main/groovy/org/apache/groovy/linq/dsl/GinqVisitor.java  |  4 ++--
 .../{RootExpression.java => SimpleGinqExpression.java}       |  6 +++---
 5 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
index a46b291..5e521bb 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
@@ -21,7 +21,7 @@ package org.apache.groovy.linq
 import groovy.transform.CompileStatic
 import org.apache.groovy.linq.dsl.GinqAstBuilder
 import org.apache.groovy.linq.dsl.GinqBuilder
-import org.apache.groovy.linq.dsl.expression.RootExpression
+import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression
 import org.codehaus.groovy.ast.expr.ClosureExpression
 import org.codehaus.groovy.ast.expr.Expression
 import org.codehaus.groovy.ast.expr.MethodCallExpression
@@ -37,10 +37,10 @@ class GinqGroovyMethods {
 
         GinqAstBuilder ginqAstBuilder = new GinqAstBuilder()
         code.visit(ginqAstBuilder)
-        RootExpression rootExpression = ginqAstBuilder.getRootExpression()
+        SimpleGinqExpression simpleGinqExpression = ginqAstBuilder.getSimpleGinqExpression()
 
         GinqBuilder ginqBuilder = new GinqBuilder()
-        MethodCallExpression selectMethodCallExpression = ginqBuilder.visitRootExpression(rootExpression)
+        MethodCallExpression selectMethodCallExpression = ginqBuilder.visitSimpleGinqExpression(simpleGinqExpression)
 
         return selectMethodCallExpression
     }
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 f36e75c..0e75468 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
@@ -21,8 +21,8 @@ package org.apache.groovy.linq.dsl;
 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.RootExpression;
 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.GroovyBugError;
 import org.codehaus.groovy.ast.CodeVisitorSupport;
@@ -36,11 +36,11 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
  * @since 4.0.0
  */
 public class GinqAstBuilder extends CodeVisitorSupport {
-    private RootExpression rootExpression = new RootExpression(); // store the result
+    private SimpleGinqExpression simpleGinqExpression = new SimpleGinqExpression(); // store the result
     private GinqExpression ginqExpression; // store the return value
 
-    public RootExpression getRootExpression() {
-        return rootExpression;
+    public SimpleGinqExpression getSimpleGinqExpression() {
+        return simpleGinqExpression;
     }
 
     @Override
@@ -59,7 +59,7 @@ public class GinqAstBuilder extends CodeVisitorSupport {
             Expression dataSourceExpr = ((ArgumentListExpression) call.getArguments()).getExpression(0);
 
             FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr);
-            rootExpression.addFromExpression(fromExpression);
+            simpleGinqExpression.addFromExpression(fromExpression);
 
             ginqExpression = fromExpression;
             return;
@@ -80,7 +80,7 @@ public class GinqAstBuilder extends CodeVisitorSupport {
 
         if ("select".equals(methodName)) {
             SelectExpression selectExpression = new SelectExpression(call.getArguments());
-            rootExpression.setSelectExpression(selectExpression);
+            simpleGinqExpression.setSelectExpression(selectExpression);
 
             ginqExpression = selectExpression;
 
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 e5ee6e2..098bd41 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,7 +22,7 @@ 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.RootExpression
+import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression
 import org.apache.groovy.linq.dsl.expression.SelectExpression
 import org.apache.groovy.linq.dsl.expression.WhereExpression
 import org.codehaus.groovy.ast.ClassHelper
@@ -44,9 +44,9 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
 @CompileStatic
 class GinqBuilder implements GinqVisitor<Object> {
     @Override
-    MethodCallExpression visitRootExpression(RootExpression rootExpression) {
+    MethodCallExpression visitSimpleGinqExpression(SimpleGinqExpression simpleGinqExpression) {
         List<MethodCallExpression> fromMethodCallExpressionList = new LinkedList<>()
-        List<FromExpression> fromExpressionList = rootExpression.getFromExpressionList()
+        List<FromExpression> fromExpressionList = simpleGinqExpression.getFromExpressionList()
         for (FromExpression fromExpression : (fromExpressionList)) {
             MethodCallExpression methodCallExpression = this.visitFromExpression(fromExpression)
             fromMethodCallExpressionList.add(methodCallExpression)
@@ -54,7 +54,7 @@ class GinqBuilder implements GinqVisitor<Object> {
 
         MethodCallExpression selectMethodReceiver = fromMethodCallExpressionList.getLast()
 
-        SelectExpression selectExpression = rootExpression.getSelectExpression()
+        SelectExpression selectExpression = simpleGinqExpression.getSelectExpression()
         selectExpression.putNodeMetaData(__SELECT_METHOD_RECEIVER, selectMethodReceiver)
         selectExpression.putNodeMetaData(__ALIAS_EXPR, fromExpressionList.get(fromExpressionList.size() - 1).aliasExpr)
         MethodCallExpression selectMethodCallExpression = this.visitSelectExpression(selectExpression)
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 7072b5d..3ee3f4f 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,7 +20,7 @@ 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.RootExpression;
+import org.apache.groovy.linq.dsl.expression.SimpleGinqExpression;
 import org.apache.groovy.linq.dsl.expression.SelectExpression;
 import org.apache.groovy.linq.dsl.expression.WhereExpression;
 
@@ -31,7 +31,7 @@ import org.apache.groovy.linq.dsl.expression.WhereExpression;
  * @since 4.0.0
  */
 public interface GinqVisitor<R> {
-    R visitRootExpression(RootExpression rootExpression);
+    R visitSimpleGinqExpression(SimpleGinqExpression simpleGinqExpression);
     R visitFromExpression(FromExpression fromExpression);
     R visitWhereExpression(WhereExpression whereExpression);
     R visitSelectExpression(SelectExpression selectExpression);
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java
similarity index 91%
rename from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
rename to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java
index ac8a45c..a8307eb 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java
@@ -28,13 +28,13 @@ import java.util.List;
  *
  * @since 4.0.0
  */
-public class RootExpression extends AbstractGinqExpression {
+public class SimpleGinqExpression extends AbstractGinqExpression {
     private List<FromExpression> fromExpressionList = new ArrayList<>();
     private SelectExpression selectExpression;
 
     @Override
     public <R> R accept(GinqVisitor<R> visitor) {
-        return visitor.visitRootExpression(this);
+        return visitor.visitSimpleGinqExpression(this);
     }
 
     public List<FromExpression> getFromExpressionList() {
@@ -55,7 +55,7 @@ public class RootExpression extends AbstractGinqExpression {
 
     @Override
     public String toString() {
-        return "RootExpression{" +
+        return "SimpleGinqExpression{" +
                 "fromExpressionList=" + fromExpressionList +
                 ", selectExpression=" + selectExpression +
                 '}';


[groovy] 21/22: GROOVY-8258: trivial refactoring

Posted by su...@apache.org.
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 c7f0f4d4813a8e55c5ce1ea0d7bcac6a66f8bc04
Author: Daniel Sun <su...@apache.org>
AuthorDate: Tue Oct 6 04:31:26 2020 +0800

    GROOVY-8258: trivial refactoring
---
 .../groovy/org/apache/groovy/linq/dsl/GinqBuilder.groovy  | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

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 bbfe3cb..fdb2e96 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
@@ -50,12 +50,6 @@ 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<>()
@@ -168,7 +162,7 @@ class GinqBuilder implements GinqVisitor<Object> {
         Expression aliasExpr = selectExpression.getNodeMetaData(__ALIAS_EXPR)
         Expression projectionExpr = selectExpression.getProjectionExpr()
 
-        if (__T.equals(aliasExpr.text)) {
+        if (__T == aliasExpr.text) {
             projectionExpr = correctVariablesOfProjectExpression(selectExpression, projectionExpr)
         }
 
@@ -239,6 +233,11 @@ class GinqBuilder implements GinqVisitor<Object> {
 
     private static final String __FROM_EXPRESSION = "__fromExpression"
     private static final String __FROM_METHOD_CALL_EXPRESSION = "__fromMethodCallExpression"
-    private static final String __SELECT_METHOD_RECEIVER = "__selectMethodReceiver"
     private static final String __ALIAS_EXPR = "__aliasExpr"
+    private static final String __RECEIVER_ALIAS_EXPR = "__receiverAliasExpr"
+    private static final String __INNER_JOIN_METHOD_RECEIVER = "__innerJoinMethodReceiver"
+    private static final String __T = "__t"
+    private static final String __FIRST_ALIAS_EXPR = "__firstAliasExpr"
+    private static final String __SECOND_ALIAS_EXPR = "__secondAliasExpr"
+    private static final String __SELECT_METHOD_RECEIVER = "__selectMethodReceiver"
 }


[groovy] 12/22: GROOVY-8258: rename linq to ginq

Posted by su...@apache.org.
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 d355e9c38098a5c1c24b541faf58d5d6e6fd24db
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 17:31:42 2020 +0800

    GROOVY-8258: rename linq to ginq
---
 .../groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy |  2 +-
 .../groovy/linq/{LinqTest.groovy => GinqTest.groovy}       | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index dba4f9d..70a9596 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -42,7 +42,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
 @CompileStatic
 class LinqGroovyMethods {
     @Macro
-    static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
+    static Expression GINQ(MacroContext ctx, final ClosureExpression closureExpression) {
         BlockStatement code = (BlockStatement) closureExpression.getCode()
         List<Statement> statementList = code.getStatements()
 
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
similarity index 85%
rename from subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
rename to subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
index 30ad372..d164a65 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
@@ -26,12 +26,12 @@ import static groovy.test.GroovyAssert.assertScript
 
 
 @CompileStatic
-class LinqTest {
+class GinqTest {
     @Test
-    void "testLinq - from select - 1"() {
+    void "testGinq - from select - 1"() {
         assertScript '''
             def numbers = [0, 1, 2]
-            assert [0, 1, 2] == LINQ {
+            assert [0, 1, 2] == GINQ {
                 from n of numbers
                 select n
             }.toList()
@@ -39,10 +39,10 @@ class LinqTest {
     }
 
     @Test
-    void "testLinq - from select - 2"() {
+    void "testGinq - from select - 2"() {
         assertScript '''
             def numbers = [0, 1, 2]
-            assert [0, 2, 4] == LINQ {
+            assert [0, 2, 4] == GINQ {
                 from n of numbers
                 select n * 2
             }.toList()
@@ -50,10 +50,10 @@ class LinqTest {
     }
 
     @Test
-    void "testLinq - from where select"() {
+    void "testGinq - from where select"() {
         assertScript '''
             def numbers = [0, 1, 2, 3, 4, 5]
-            assert [2, 4, 6] == LINQ {
+            assert [2, 4, 6] == GINQ {
                 from n of numbers
                 where n > 0 && n <= 3
                 select n * 2


[groovy] 11/22: GROOVY-8258: enable STC

Posted by su...@apache.org.
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 189c49d56dc83a7dd27b1597739325ae6a3433bc
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:50:41 2020 +0800

    GROOVY-8258: enable STC
---
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 26 ++++++++++++++--------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index ad132e2..dba4f9d 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -18,6 +18,8 @@
  */
 package org.apache.groovy.linq
 
+import groovy.transform.CompileDynamic
+import groovy.transform.CompileStatic
 import groovy.transform.ToString
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.expr.ArgumentListExpression
@@ -37,6 +39,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.param
 import static org.codehaus.groovy.ast.tools.GeneralUtils.params
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
 
+@CompileStatic
 class LinqGroovyMethods {
     @Macro
     static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
@@ -54,7 +57,7 @@ class LinqGroovyMethods {
                     break
                 }
                 case 'of': {
-                    MethodCallExpression fromMethodCallExpression = methodCallExpression.getObjectExpression()
+                    MethodCallExpression fromMethodCallExpression = (MethodCallExpression) methodCallExpression.getObjectExpression()
                     VariableExpression aliasVariable = (VariableExpression) ((ArgumentListExpression) fromMethodCallExpression.getArguments()).getExpression(0)
                     Expression dataSourceExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
                     linqContext.addFrom(aliasVariable, dataSourceExpression)
@@ -79,16 +82,13 @@ class LinqGroovyMethods {
         constructLinqMethodCalls(linqContext)
     }
 
-    private static constructLinqMethodCalls(LinqContext linqContext) {
+    private static Expression constructLinqMethodCalls(LinqContext linqContext) {
         Map.Entry<VariableExpression, Expression> fromEntry = linqContext.fromMap.entrySet().toList().get(0)
         VariableExpression aliasVariable = fromEntry.key
 
         Expression selectMethodReceiver = null
 
-        MethodCallExpression from = macro {
-            org.apache.groovy.linq.provider.QueryableCollection
-                    .from($v { fromEntry.value })
-        }
+        MethodCallExpression from = constructFromMethodCall(fromEntry)
 
         selectMethodReceiver = from
 
@@ -102,13 +102,21 @@ class LinqGroovyMethods {
         return select
     }
 
-    private static callXWithLambda(Expression receiver, String methodName, String closureParamName, Expression closureCode) {
+    @CompileDynamic
+    private static MethodCallExpression constructFromMethodCall(fromEntry) {
+        macro {
+            org.apache.groovy.linq.provider.QueryableCollection
+                    .from($v { fromEntry.value })
+        }
+    }
+
+    private static MethodCallExpression callXWithLambda(Expression receiver, String methodName, String lambdaParamName, Expression lambdaCode) {
         callX(
                 receiver,
                 methodName,
                 lambdaX(
-                        params(param(ClassHelper.DYNAMIC_TYPE, closureParamName)),
-                        stmt(closureCode)
+                        params(param(ClassHelper.DYNAMIC_TYPE, lambdaParamName)),
+                        stmt(lambdaCode)
                 )
         )
     }


[groovy] 19/22: GROOVY-8258: Add 1 more error test

Posted by su...@apache.org.
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 07073498a044a78efc256748b1ab693f5197c286
Author: Daniel Sun <su...@apache.org>
AuthorDate: Tue Oct 6 00:34:09 2020 +0800

    GROOVY-8258: Add 1 more error test
---
 .../test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy
index cee78af..40831db 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy
@@ -45,6 +45,19 @@ class GinqErrorTest {
         def err = shouldFail '''\
             def numbers = [0, 1, 2]
             GINQ {
+                from n as numbers
+                select n
+            }
+        '''
+
+        assert err.toString().contains('`in` is expected for `from`, e.g. `from n in nums` @ line 3, column 17.')
+    }
+
+    @Test
+    void "testGinq - from select - 3"() {
+        def err = shouldFail '''\
+            def numbers = [0, 1, 2]
+            GINQ {
                 from n, numbers
                 select n
             }


[groovy] 14/22: GROOVY-8258: add javadoc and rename linq to ginq

Posted by su...@apache.org.
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 d413188abd8f510e7d20c3f6456c2ad5a1cdc7d2
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 21:14:43 2020 +0800

    GROOVY-8258: add javadoc and rename linq to ginq
---
 subprojects/groovy-linq/build.gradle               |  2 +-
 ...oovyMethods.groovy => GinqGroovyMethods.groovy} |  2 +-
 .../org/apache/groovy/linq/dsl/GinqAstBuilder.java | 23 ++++++++++++++++++++++
 .../org/apache/groovy/linq/dsl/GinqBuilder.groovy  |  5 +++++
 .../org/apache/groovy/linq/dsl/GinqVisitor.java    |  6 ++++++
 .../dsl/expression/AbstractGinqExpression.java     |  5 +++++
 .../linq/dsl/expression/FilterableExpression.java  |  5 +++++
 .../groovy/linq/dsl/expression/FromExpression.java |  5 +++++
 .../groovy/linq/dsl/expression/GinqExpression.java |  5 +++++
 .../groovy/linq/dsl/expression/RootExpression.java |  5 +++++
 .../linq/dsl/expression/SelectExpression.java      |  5 +++++
 .../linq/dsl/expression/WhereExpression.java       |  5 +++++
 12 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/subprojects/groovy-linq/build.gradle b/subprojects/groovy-linq/build.gradle
index 5c6a05b..cc476c4 100644
--- a/subprojects/groovy-linq/build.gradle
+++ b/subprojects/groovy-linq/build.gradle
@@ -25,7 +25,7 @@ dependencies {
 }
 
 task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorTask) {
-    extensionClasses = 'org.apache.groovy.linq.LinqGroovyMethods'
+    extensionClasses = 'org.apache.groovy.linq.GinqGroovyMethods'
 }
 
 compileJava.dependsOn moduleDescriptor
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
similarity index 98%
rename from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
rename to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
index 4d9af35..a46b291 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
@@ -30,7 +30,7 @@ import org.codehaus.groovy.macro.runtime.Macro
 import org.codehaus.groovy.macro.runtime.MacroContext
 
 @CompileStatic
-class LinqGroovyMethods {
+class GinqGroovyMethods {
     @Macro
     static Expression GINQ(MacroContext ctx, final ClosureExpression closureExpression) {
         Statement code = closureExpression.getCode()
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 e2bec3f..f36e75c 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
@@ -1,3 +1,21 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
 package org.apache.groovy.linq.dsl;
 
 import org.apache.groovy.linq.dsl.expression.FilterableExpression;
@@ -12,6 +30,11 @@ import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 
+/**
+ * Build the AST for GINQ
+ *
+ * @since 4.0.0
+ */
 public class GinqAstBuilder extends CodeVisitorSupport {
     private RootExpression rootExpression = new RootExpression(); // store the result
     private GinqExpression ginqExpression; // store the return value
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 8cbb86b..e5ee6e2 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
@@ -36,6 +36,11 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.param
 import static org.codehaus.groovy.ast.tools.GeneralUtils.params
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
 
+/**
+ * Visit AST of GINQ and generate target method calls for GINQ
+ *
+ * @since 4.0.0
+ */
 @CompileStatic
 class GinqBuilder implements GinqVisitor<Object> {
     @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 4e7c242..7072b5d 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
@@ -24,6 +24,12 @@ import org.apache.groovy.linq.dsl.expression.RootExpression;
 import org.apache.groovy.linq.dsl.expression.SelectExpression;
 import org.apache.groovy.linq.dsl.expression.WhereExpression;
 
+/**
+ * Represents the visitor for AST of GINQ
+ *
+ * @param <R> the type of visit result
+ * @since 4.0.0
+ */
 public interface GinqVisitor<R> {
     R visitRootExpression(RootExpression rootExpression);
     R visitFromExpression(FromExpression fromExpression);
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
index 25e4e84..25e20c9 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
@@ -5,6 +5,11 @@ import org.codehaus.groovy.ast.NodeMetaDataHandler;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+/**
+ * Represents GINQ expression which could hold meta data
+ *
+ * @since 4.0.0
+ */
 public abstract class AbstractGinqExpression implements GinqExpression, NodeMetaDataHandler {
     private Map<?, ?> metaDataMap = new LinkedHashMap<>();
 
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 d739e21..c0c1e8f 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
@@ -18,6 +18,11 @@
  */
 package org.apache.groovy.linq.dsl.expression;
 
+/**
+ * Represents expression which could be filtered via {@code where} expression
+ *
+ * @since 4.0.0
+ */
 public abstract class FilterableExpression extends AbstractGinqExpression {
     protected WhereExpression whereExpression;
 
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 4c212e4..248e9c0 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
@@ -21,6 +21,11 @@ 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
+ *
+ * @since 4.0.0
+ */
 public class FromExpression extends FilterableExpression {
     private final Expression aliasExpr;
     private final Expression dataSourceExpr;
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java
index 22ef3ff..32ae24b 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/GinqExpression.java
@@ -20,6 +20,11 @@ package org.apache.groovy.linq.dsl.expression;
 
 import org.apache.groovy.linq.dsl.GinqVisitor;
 
+/**
+ * Represents the GINQ expression
+ *
+ * @since 4.0.0
+ */
 public interface GinqExpression {
     <R> R accept(GinqVisitor<R> visitor);
 }
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
index d4ddf0c..ac8a45c 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/RootExpression.java
@@ -23,6 +23,11 @@ import org.apache.groovy.linq.dsl.GinqVisitor;
 import java.util.ArrayList;
 import java.util.List;
 
+/**
+ * Represent the root expression of GINQ
+ *
+ * @since 4.0.0
+ */
 public class RootExpression extends AbstractGinqExpression {
     private List<FromExpression> fromExpressionList = new ArrayList<>();
     private SelectExpression selectExpression;
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java
index 0cd3429..82ec0c1 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/SelectExpression.java
@@ -21,6 +21,11 @@ package org.apache.groovy.linq.dsl.expression;
 import org.apache.groovy.linq.dsl.GinqVisitor;
 import org.codehaus.groovy.ast.expr.Expression;
 
+/**
+ * Represents the select expression
+ *
+ * @since 4.0.0
+ */
 public class SelectExpression extends AbstractGinqExpression {
     private final Expression projectionExpr;
 
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 b23ba94..052347d 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
@@ -21,6 +21,11 @@ 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
+ *
+ * @since 4.0.0
+ */
 public class WhereExpression extends AbstractGinqExpression {
     private final Expression filterExpr;
 


[groovy] 22/22: GROOVY-8258: add more test cases

Posted by su...@apache.org.
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 fd4169e340c4b94ae1eae140d95cf640d4cf058d
Author: Daniel Sun <su...@apache.org>
AuthorDate: Tue Oct 6 05:05:13 2020 +0800

    GROOVY-8258: add more test cases
---
 .../org/apache/groovy/linq/dsl/GinqBuilder.groovy  |   3 +-
 .../groovy/org/apache/groovy/linq/GinqTest.groovy  | 157 ++++++++++++++++++++-
 2 files changed, 158 insertions(+), 2 deletions(-)

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 fdb2e96..b9dd39a 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
@@ -34,6 +34,7 @@ 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.TupleExpression
 import org.codehaus.groovy.ast.expr.VariableExpression
 
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
@@ -166,7 +167,7 @@ class GinqBuilder implements GinqVisitor<Object> {
             projectionExpr = correctVariablesOfProjectExpression(selectExpression, projectionExpr)
         }
 
-        List<Expression> expressionList = ((ArgumentListExpression) projectionExpr).getExpressions()
+        List<Expression> expressionList = ((TupleExpression) projectionExpr).getExpressions()
         Expression lambdaCode
         if (expressionList.size() > 1) {
             lambdaCode = new ListExpression(expressionList)
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 96d04cb..c97f09d 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
@@ -50,6 +50,69 @@ class GinqTest {
     }
 
     @Test
+    void "testGinq - from select - 3"() {
+        assertScript '''
+            class Person {
+                String name
+                int age
+                
+                Person(String name, int age) {
+                    this.name = name
+                    this.age = age
+                }
+            }
+
+            def persons = [new Person('Daniel', 35), new Person('Linda', 21), new Person('Peter', 30)]
+            assert [35, 21, 30] == GINQ {
+                from p in persons
+                select p.age
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from select - 4"() {
+        assertScript '''
+            class Person {
+                String name
+                int age
+                
+                Person(String name, int age) {
+                    this.name = name
+                    this.age = age
+                }
+            }
+
+            def persons = [new Person('Daniel', 35), new Person('Linda', 21), new Person('Peter', 30)]
+            assert [['Daniel', 35], ['Linda', 21], ['Peter', 30]] == GINQ {
+                from p in persons
+                select p.name, p.age
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from select - 5"() {
+        assertScript '''
+            class Person {
+                String name
+                int age
+                
+                Person(String name, int age) {
+                    this.name = name
+                    this.age = age
+                }
+            }
+
+            def persons = [new Person('Daniel', 35), new Person('Linda', 21), new Person('Peter', 30)]
+            assert [[name:'Daniel', age:35], [name:'Linda', age:21], [name:'Peter', age:30]] == GINQ {
+                from p in persons
+                select (name: p.name, age: p.age)
+            }.toList()
+        '''
+    }
+
+    @Test
     void "testGinq - from where select"() {
         assertScript '''
             def numbers = [0, 1, 2, 3, 4, 5]
@@ -62,7 +125,7 @@ class GinqTest {
     }
 
     @Test
-    void "testGinq - from innerJoin select"() {
+    void "testGinq - from innerJoin select - 1"() {
         assertScript '''
             def nums1 = [1, 2, 3]
             def nums2 = [1, 2, 3]
@@ -74,4 +137,96 @@ class GinqTest {
             }.toList()
         '''
     }
+
+    @Test
+    void "testGinq - from innerJoin select - 2"() {
+        assertScript '''
+            def nums1 = [1, 2, 3]
+            def nums2 = [1, 2, 3]
+            assert [[2, 1], [3, 2], [4, 3]] == GINQ {
+                from n1 in nums1
+                innerJoin n2 in nums2
+                on n1 == n2
+                select n1 + 1, n2
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from innerJoin select - 3"() {
+        assertScript '''
+            def nums1 = [1, 2, 3]
+            def nums2 = [1, 2, 3]
+            assert [[1, 2], [2, 3], [3, 4]] == GINQ {
+                from n1 in nums1
+                innerJoin n2 in nums2
+                on n1 == n2
+                select n1, n2 + 1
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from innerJoin select - 4"() {
+        assertScript '''
+            def nums1 = [1, 2, 3]
+            def nums2 = [1, 2, 3]
+            assert [[1, 2], [2, 3]] == GINQ {
+                from n1 in nums1
+                innerJoin n2 in nums2
+                on n1 + 1 == n2
+                select n1, n2
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from innerJoin select - 5"() {
+        assertScript '''
+            class Person {
+                String name
+                int age
+                
+                Person(String name, int age) {
+                    this.name = name
+                    this.age = age
+                }
+            }
+
+            def persons1 = [new Person('Daniel', 35), new Person('Linda', 21), new Person('Peter', 30)]
+            def persons2 = [new Person('Jack', 35), new Person('Rose', 21), new Person('Smith', 30)]
+            assert [['Daniel', 'Jack'], ['Linda', 'Rose'], ['Peter', 'Smith']] == GINQ {
+                from p1 in persons1
+                innerJoin p2 in persons2
+                on p1.age == p2.age
+                select p1.name, p2.name
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - from innerJoin select - 6"() {
+        assertScript '''
+            class Person {
+                String name
+                int age
+                
+                Person(String name, int age) {
+                    this.name = name
+                    this.age = age
+                }
+            }
+            
+            def same(str) { str }
+
+            def persons1 = [new Person('Daniel', 35), new Person('Linda', 21), new Person('Peter', 30)]
+            def persons2 = [new Person('Jack', 35), new Person('Rose', 21), new Person('Smith', 30)]
+            assert [['DANIEL', 'JACK'], ['LINDA', 'ROSE'], ['PETER', 'SMITH']] == GINQ {
+                from p1 in persons1
+                innerJoin p2 in persons2
+                on p1.age == p2.age
+                select same(p1.name.toUpperCase()), same(p2.name.toUpperCase())
+            }.toList()
+        '''
+    }
 }


[groovy] 17/22: GROOVY-8258: Use `in` instead of `of` for better readability

Posted by su...@apache.org.
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 2318b694c78743658a7f1db347403ac4f1bed849
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 22:39:21 2020 +0800

    GROOVY-8258: Use `in` instead of `of` for better readability
---
 .../groovy/org/apache/groovy/linq/dsl/GinqAstBuilder.java    | 12 +++++-------
 .../src/test/groovy/org/apache/groovy/linq/GinqTest.groovy   |  6 +++---
 2 files changed, 8 insertions(+), 10 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 0e75468..9a365e5 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
@@ -27,6 +27,7 @@ import org.apache.groovy.linq.dsl.expression.WhereExpression;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 
@@ -50,13 +51,10 @@ public class GinqAstBuilder extends CodeVisitorSupport {
         System.out.println(methodName + " : " + call);
 
         if ("from".equals(methodName)) {
-            return;
-        }
-
-        if ("of".equals(methodName)) {
-            MethodCallExpression fromMethodCallExpression = (MethodCallExpression) call.getObjectExpression();
-            Expression aliasExpr = ((ArgumentListExpression) fromMethodCallExpression.getArguments()).getExpression(0);
-            Expression dataSourceExpr = ((ArgumentListExpression) call.getArguments()).getExpression(0);
+            ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments();
+            BinaryExpression binaryExpression = (BinaryExpression) arguments.getExpression(0);
+            Expression aliasExpr = binaryExpression.getLeftExpression();
+            Expression dataSourceExpr = binaryExpression.getRightExpression();
 
             FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr);
             simpleGinqExpression.addFromExpression(fromExpression);
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 d164a65..1cdb0ef 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
@@ -32,7 +32,7 @@ class GinqTest {
         assertScript '''
             def numbers = [0, 1, 2]
             assert [0, 1, 2] == GINQ {
-                from n of numbers
+                from n in numbers
                 select n
             }.toList()
         '''
@@ -43,7 +43,7 @@ class GinqTest {
         assertScript '''
             def numbers = [0, 1, 2]
             assert [0, 2, 4] == GINQ {
-                from n of numbers
+                from n in numbers
                 select n * 2
             }.toList()
         '''
@@ -54,7 +54,7 @@ class GinqTest {
         assertScript '''
             def numbers = [0, 1, 2, 3, 4, 5]
             assert [2, 4, 6] == GINQ {
-                from n of numbers
+                from n in numbers
                 where n > 0 && n <= 3
                 select n * 2
             }.toList()


[groovy] 20/22: GROOVY-8258: Implement inner join

Posted by su...@apache.org.
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 <su...@apache.org>
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()
+        '''
+    }
 }


[groovy] 06/22: GROOVY-8258: Implement the very basic LINQ

Posted by su...@apache.org.
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 1ab90b54e7ed1b68f7eb31cb1398acb3a884ea97
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:08:42 2020 +0800

    GROOVY-8258: Implement the very basic LINQ
---
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 104 ++++++++++++++++++++-
 .../groovy/linq/provider/QueryableCollection.java  |   5 +
 .../groovy/org/apache/groovy/linq/LinqTest.groovy  |   9 +-
 3 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index 224c958..cd6b502 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -18,16 +18,116 @@
  */
 package org.apache.groovy.linq
 
+import groovy.transform.ToString
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
 import org.codehaus.groovy.ast.expr.ClosureExpression
-import org.codehaus.groovy.ast.expr.ConstantExpression
 import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
 import org.codehaus.groovy.macro.runtime.Macro
 import org.codehaus.groovy.macro.runtime.MacroContext
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.closureX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
+
 class LinqGroovyMethods {
     @Macro
     static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
-        return macro { 'TODO LINQ' }
+        BlockStatement code = (BlockStatement) closureExpression.getCode()
+        List<Statement> statementList = code.getStatements()
+
+        LinqContext linqContext = new LinqContext()
+        for (Statement statement : statementList) {
+            ExpressionStatement expressionStatement = (ExpressionStatement) statement
+            MethodCallExpression methodCallExpression = (MethodCallExpression) expressionStatement.getExpression()
+
+            String methodName = methodCallExpression.getMethodAsString()
+            switch (methodName) {
+                case 'from': {
+                    break
+                }
+                case 'of': {
+                    MethodCallExpression fromMethodCallExpression = methodCallExpression.getObjectExpression()
+                    VariableExpression aliasVariable = (VariableExpression) ((ArgumentListExpression) fromMethodCallExpression.getArguments()).getExpression(0)
+                    Expression dataSourceExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
+                    linqContext.addFrom(aliasVariable, dataSourceExpression)
+                    break
+                }
+                case 'where': {
+                    Expression conditionExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
+                    linqContext.addWhere(conditionExpression)
+                    break
+                }
+                case 'select': {
+                    Expression selectExpression = ((ArgumentListExpression) methodCallExpression.getArguments()).getExpression(0)
+                    linqContext.addSelect(selectExpression)
+                    break
+                }
+                default: {
+                    break
+                }
+            }
+        }
+
+        constructLinqMethodCalls(linqContext)
+    }
+
+    private static constructLinqMethodCalls(LinqContext linqContext) {
+        Map.Entry<VariableExpression, Expression> fromEntry = linqContext.fromMap.entrySet().toList().get(0)
+        VariableExpression aliasVariable = fromEntry.key
+
+        MethodCallExpression from = macro {
+            org.apache.groovy.linq.provider.QueryableCollection
+                    .from($v { fromEntry.value })
+        }
+
+        MethodCallExpression where =
+                callX(
+                        from,
+                        "where",
+                        closureX(
+                                params(param(ClassHelper.DYNAMIC_TYPE, aliasVariable.name)),
+                                stmt(linqContext.whereList[0])
+                        )
+                )
+
+        MethodCallExpression select =
+                callX(
+                        where,
+                        "select",
+                        closureX(
+                                params(param(ClassHelper.DYNAMIC_TYPE, aliasVariable.name)),
+                                stmt(linqContext.selectList[0])
+                        )
+                )
+
+        return select
+    }
+
+    @ToString(includeNames=true)
+    static class LinqContext {
+        Map<VariableExpression, Expression> fromMap = new LinkedHashMap<>()
+        List<Expression> whereList = new ArrayList<>()
+        List<Expression> selectList = new ArrayList<>()
+
+        void addFrom(VariableExpression aliasVariable, Expression dataSourceExpression) {
+            fromMap.put(aliasVariable, dataSourceExpression)
+        }
+
+        void addWhere(Expression... conditionExpressions) {
+            whereList.addAll(conditionExpressions)
+        }
+
+        void addSelect(Expression... selectExpressions) {
+            selectList.addAll(selectExpressions)
+        }
     }
 }
 
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
index 0eb3239..9d5d19d 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
@@ -243,4 +243,9 @@ public class QueryableCollection<T> implements Queryable<T>, Iterable<T> {
     private static <T> Iterable<T> toIterable(Stream<T> sourceStream) {
         return sourceStream::iterator;
     }
+
+    @Override
+    public String toString() {
+        return toList().toString();
+    }
 }
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
index 701f1c6..a19d39e 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
@@ -28,9 +28,14 @@ import static groovy.test.GroovyAssert.assertScript
 @CompileStatic
 class LinqTest {
     @Test
-    void testLinqMacroMethod() {
+    void "testLinqMacroMethod - from where select"() {
         assertScript '''
-            assert 'TODO LINQ' == LINQ {}
+            def numbers = [0, 1, 2, 3, 4, 5]
+            assert [2, 4, 6] == LINQ {
+                from n of numbers
+                where n > 0 && n <= 3
+                select n * 2
+            }.toList()
         '''
     }
 }


[groovy] 05/22: GROOVY-8258: mark backend classes as internal

Posted by su...@apache.org.
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 2610bac0444c09c2424ac0730158be1fcae97fd5
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 01:10:32 2020 +0800

    GROOVY-8258: mark backend classes as internal
---
 .../groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java   | 2 ++
 .../groovy/org/apache/groovy/linq/provider/QueryableCollection.java     | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java
index 95d67f9..56803ac 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java
@@ -19,6 +19,7 @@
 package org.apache.groovy.linq;
 
 import groovy.lang.Tuple2;
+import groovy.transform.Internal;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -34,6 +35,7 @@ import java.util.stream.Stream;
  * @param <T> the type of Queryable element
  * @since 4.0.0
  */
+@Internal
 public interface Queryable<T> {
     <U> Queryable<Tuple2<T, U>> innerJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner);
 
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
index 282e68b..0eb3239 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
@@ -20,6 +20,7 @@ package org.apache.groovy.linq.provider;
 
 import groovy.lang.Tuple;
 import groovy.lang.Tuple2;
+import groovy.transform.Internal;
 import org.apache.groovy.linq.Queryable;
 
 import java.math.BigDecimal;
@@ -40,6 +41,7 @@ import java.util.stream.StreamSupport;
  * @param <T> the type of Queryable element
  * @since 4.0.0
  */
+@Internal
 public class QueryableCollection<T> implements Queryable<T>, Iterable<T> {
     private final Iterable<T> sourceIterable;
     private Stream<T> sourceStream;


[groovy] 08/22: GROOVY-8258: Add 2 test cases

Posted by su...@apache.org.
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 9ff78df0042931e312aeb431f07056b0141c8250
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:25:12 2020 +0800

    GROOVY-8258: Add 2 test cases
---
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 12 ++++++++++--
 .../groovy/org/apache/groovy/linq/LinqTest.groovy  | 22 ++++++++++++++++++++++
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index ff368fb..71c3fe5 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -83,13 +83,21 @@ class LinqGroovyMethods {
         Map.Entry<VariableExpression, Expression> fromEntry = linqContext.fromMap.entrySet().toList().get(0)
         VariableExpression aliasVariable = fromEntry.key
 
+        Expression selectMethodReceiver = null
+
         MethodCallExpression from = macro {
             org.apache.groovy.linq.provider.QueryableCollection
                     .from($v { fromEntry.value })
         }
 
-        MethodCallExpression where = callXWithClosure(from, "where", aliasVariable.name, linqContext.whereList[0])
-        MethodCallExpression select = callXWithClosure(where, "select", aliasVariable.name, linqContext.selectList[0])
+        selectMethodReceiver = from
+
+        if (linqContext.whereList.size() > 0) {
+            MethodCallExpression where = callXWithClosure(from, "where", aliasVariable.name, linqContext.whereList[0])
+            selectMethodReceiver = where
+        }
+
+        MethodCallExpression select = callXWithClosure(selectMethodReceiver, "select", aliasVariable.name, linqContext.selectList[0])
 
         return select
     }
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
index a19d39e..b2b0887 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
@@ -28,6 +28,28 @@ import static groovy.test.GroovyAssert.assertScript
 @CompileStatic
 class LinqTest {
     @Test
+    void "testLinqMacroMethod - from select - 1"() {
+        assertScript '''
+            def numbers = [0, 1, 2]
+            assert [0, 1, 2] == LINQ {
+                from n of numbers
+                select n
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testLinqMacroMethod - from select - 2"() {
+        assertScript '''
+            def numbers = [0, 1, 2]
+            assert [0, 2, 4] == LINQ {
+                from n of numbers
+                select n * 2
+            }.toList()
+        '''
+    }
+
+    @Test
     void "testLinqMacroMethod - from where select"() {
         assertScript '''
             def numbers = [0, 1, 2, 3, 4, 5]


[groovy] 03/22: GROOVY-8258: Add macro method LINQ

Posted by su...@apache.org.
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 e233f3428354504f9c88a8154ae159a3b6a5a308
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 00:54:02 2020 +0800

    GROOVY-8258: Add macro method LINQ
---
 ...GroovyMethods.java => LinqGroovyMethods.groovy} | 17 +++++++--------
 .../groovy/org/apache/groovy/linq/LinqTest.groovy} | 24 +++++++++++++---------
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
similarity index 65%
copy from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index 936e6be..224c958 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -16,17 +16,18 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.groovy.linq;
+package org.apache.groovy.linq
 
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.macro.runtime.Macro;
-import org.codehaus.groovy.macro.runtime.MacroContext;
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.macro.runtime.Macro
+import org.codehaus.groovy.macro.runtime.MacroContext
 
-public class LinqGroovyMethods {
+class LinqGroovyMethods {
     @Macro
-    public static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
-        return null; // TODO
+    static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
+        return macro { 'TODO LINQ' }
     }
 }
 
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
similarity index 67%
rename from subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
rename to subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
index 936e6be..701f1c6 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
@@ -16,17 +16,21 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.groovy.linq;
+package org.apache.groovy.linq
 
-import org.codehaus.groovy.ast.expr.ClosureExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.macro.runtime.Macro;
-import org.codehaus.groovy.macro.runtime.MacroContext;
 
-public class LinqGroovyMethods {
-    @Macro
-    public static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
-        return null; // TODO
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+
+@CompileStatic
+class LinqTest {
+    @Test
+    void testLinqMacroMethod() {
+        assertScript '''
+            assert 'TODO LINQ' == LINQ {}
+        '''
     }
 }
-


[groovy] 16/22: GROOVY-8258: make field `final`

Posted by su...@apache.org.
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 b69bf21cc44f809558124c3e25eb98784008b6ec
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 22:22:02 2020 +0800

    GROOVY-8258: make field `final`
---
 .../org/apache/groovy/linq/dsl/expression/SimpleGinqExpression.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 a8307eb..21c00f4 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
@@ -29,7 +29,7 @@ import java.util.List;
  * @since 4.0.0
  */
 public class SimpleGinqExpression extends AbstractGinqExpression {
-    private List<FromExpression> fromExpressionList = new ArrayList<>();
+    private final List<FromExpression> fromExpressionList = new ArrayList<>();
     private SelectExpression selectExpression;
 
     @Override


[groovy] 01/22: GROOVY-8258: Implement the built-in collection LINQ provider

Posted by su...@apache.org.
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 ac922484de3b94feb6af2115d3ef69f03948b74c
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Oct 4 23:54:31 2020 +0800

    GROOVY-8258: Implement the built-in collection LINQ provider
---
 settings.gradle                                    |   1 +
 subprojects/groovy-linq/build.gradle               |  24 ++
 .../java/org/apache/groovy/linq/Queryable.java     | 124 +++++++
 .../groovy/linq/provider/QueryableCollection.java  | 244 +++++++++++++
 .../linq/provider/QueryableCollectionTest.groovy   | 403 +++++++++++++++++++++
 5 files changed, 796 insertions(+)

diff --git a/settings.gradle b/settings.gradle
index b8a3622..3aca670 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -45,6 +45,7 @@ def subprojects = ['groovy-ant',
         'groovy-jmx',
         'groovy-json',
         'groovy-jsr223',
+        'groovy-linq',
         'groovy-macro',
         'groovy-macro-library',
         'groovy-nio',
diff --git a/subprojects/groovy-linq/build.gradle b/subprojects/groovy-linq/build.gradle
new file mode 100644
index 0000000..8e249dd
--- /dev/null
+++ b/subprojects/groovy-linq/build.gradle
@@ -0,0 +1,24 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+
+dependencies {
+    api rootProject
+    testImplementation project(':groovy-test')
+}
diff --git a/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/Queryable.java b/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/Queryable.java
new file mode 100644
index 0000000..95d67f9
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/Queryable.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq;
+
+import groovy.lang.Tuple2;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * Represents the queryable objects, e.g. Java collections
+ *
+ * @param <T> the type of Queryable element
+ * @since 4.0.0
+ */
+public interface Queryable<T> {
+    <U> Queryable<Tuple2<T, U>> innerJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner);
+
+    <U> Queryable<Tuple2<T, U>> leftJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner);
+
+    <U> Queryable<Tuple2<T, U>> rightJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner);
+
+    default <U> Queryable<Tuple2<T, U>> fullJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner) {
+        Queryable<Tuple2<T, U>> lj = this.leftJoin(queryable, joiner);
+        Queryable<Tuple2<T, U>> rj = this.rightJoin(queryable, joiner);
+        return lj.union(rj);
+    }
+
+    <U> Queryable<Tuple2<T, U>> crossJoin(Queryable<? extends U> queryable);
+
+    Queryable<T> where(Predicate<? super T> filter);
+
+    <K> Queryable<Tuple2<K, Queryable<T>>> groupBy(Function<? super T, ? extends K> classifier, BiPredicate<? super K, ? super Queryable<? extends T>> having);
+
+    default <K> Queryable<Tuple2<K, Queryable<T>>> groupBy(Function<? super T, ? extends K> classifier) {
+        return groupBy(classifier, (k, l) -> true);
+    }
+
+    <U extends Comparable<? super U>> Queryable<T> orderBy(Order<? super T, ? extends U>... orders);
+
+    Queryable<T> limit(int offset, int size);
+
+    default Queryable<T> limit(int size) {
+        return limit(0, size);
+    }
+
+    <U> Queryable<U> select(Function<? super T, ? extends U> mapper);
+
+    Queryable<T> distinct();
+
+    default Queryable<T> union(Queryable<? extends T> queryable) {
+        return this.unionAll(queryable).distinct();
+    }
+
+    Queryable<T> unionAll(Queryable<? extends T> queryable);
+
+    Queryable<T> intersect(Queryable<? extends T> queryable);
+
+    Queryable<T> minus(Queryable<? extends T> queryable);
+
+    List<T> toList();
+
+    default Stream<T> stream() {
+        return toList().stream();
+    }
+
+    //  Built-in aggregate functions {
+    int count();
+    BigDecimal sum(Function<? super T, BigDecimal> mapper);
+    // } Built-in aggregate functions
+
+    class Order<T, U extends Comparable<? super U>> {
+        private final Function<? super T, ? extends U> keyExtractor;
+        private final boolean asc;
+
+        public Order(Function<? super T, ? extends U> keyExtractor, boolean asc) {
+            this.keyExtractor = keyExtractor;
+            this.asc = asc;
+        }
+
+        public Function<? super T, ? extends U> getKeyExtractor() {
+            return keyExtractor;
+        }
+
+        public boolean isAsc() {
+            return asc;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Order)) return false;
+            Order<?, ?> order = (Order<?, ?>) o;
+            return asc == order.asc &&
+                    keyExtractor.equals(order.keyExtractor);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(keyExtractor, asc);
+        }
+    }
+}
diff --git a/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/provider/QueryableCollection.java b/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/provider/QueryableCollection.java
new file mode 100644
index 0000000..282e68b
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/provider/QueryableCollection.java
@@ -0,0 +1,244 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.provider;
+
+import groovy.lang.Tuple;
+import groovy.lang.Tuple2;
+import org.apache.groovy.linq.Queryable;
+
+import java.math.BigDecimal;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * Represents the queryable collections
+ *
+ * @param <T> the type of Queryable element
+ * @since 4.0.0
+ */
+public class QueryableCollection<T> implements Queryable<T>, Iterable<T> {
+    private final Iterable<T> sourceIterable;
+    private Stream<T> sourceStream;
+
+    public static <T> Queryable<T> from(Iterable<T> sourceIterable) {
+        return new QueryableCollection<>(sourceIterable);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Queryable<T> from(Stream<? extends T> sourceStream) {
+        Iterable<T> sourceIterable = (Iterable<T>) toIterable(sourceStream);
+        return from(sourceIterable);
+    }
+
+    private QueryableCollection(Iterable<T> sourceIterable) {
+        this.sourceIterable = sourceIterable;
+        this.sourceStream = toStream(sourceIterable);
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return sourceIterable.iterator();
+    }
+
+    @Override
+    public <U> Queryable<Tuple2<T, U>> innerJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner) {
+        Stream<Tuple2<T, U>> stream =
+                this.stream()
+                        .flatMap(p ->
+                                queryable.stream()
+                                        .filter(c -> joiner.test(p, c))
+                                        .map(c -> Tuple.tuple(p, c)));
+
+        return from(stream);
+    }
+
+    @Override
+    public <U> Queryable<Tuple2<T, U>> leftJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner) {
+        return outerJoin(this, queryable, joiner);
+    }
+
+    @Override
+    public <U> Queryable<Tuple2<T, U>> rightJoin(Queryable<? extends U> queryable, BiPredicate<? super T, ? super U> joiner) {
+        return outerJoin(queryable, this, (a, b) -> joiner.test(b, a)).select(e -> Tuple.tuple(e.getV2(), e.getV1()));
+    }
+
+    @Override
+    public <U> Queryable<Tuple2<T, U>> crossJoin(Queryable<? extends U> queryable) {
+        Stream<Tuple2<T, U>> stream =
+                this.stream()
+                        .flatMap(p ->
+                                queryable.stream()
+                                        .map(c -> Tuple.tuple(p, c)));
+
+        return from(stream);
+    }
+
+    @Override
+    public Queryable<T> where(Predicate<? super T> filter) {
+        Stream<T> stream = this.stream().filter(filter::test);
+
+        return from(stream);
+    }
+
+    @Override
+    public <K> Queryable<Tuple2<K, Queryable<T>>> groupBy(Function<? super T, ? extends K> classifier, BiPredicate<? super K, ? super Queryable<? extends T>> having) {
+        Stream<Tuple2<K, Queryable<T>>> stream =
+                this.stream()
+                        .collect(Collectors.groupingBy(classifier, Collectors.toList()))
+                        .entrySet().stream()
+                        .filter(m -> having.test(m.getKey(), from(m.getValue())))
+                        .map(m -> Tuple.tuple(m.getKey(), from(m.getValue())));
+
+        return from(stream);
+    }
+
+    @Override
+    public <U extends Comparable<? super U>> Queryable<T> orderBy(Order<? super T, ? extends U>... orders) {
+        Comparator<T> comparator = null;
+        for (int i = 0, n = orders.length; i < n; i++) {
+            Order<? super T, ? extends U> order = orders[i];
+            Comparator<U> ascOrDesc = order.isAsc() ? Comparator.naturalOrder() : Comparator.reverseOrder();
+            comparator =
+                    0 == i
+                            ? Comparator.comparing(order.getKeyExtractor(), ascOrDesc)
+                            : comparator.thenComparing(order.getKeyExtractor(), ascOrDesc);
+        }
+
+        if (null == comparator) {
+            return this;
+        }
+
+        return from(this.stream().sorted(comparator));
+    }
+
+    @Override
+    public Queryable<T> limit(int offset, int size) {
+        Stream<T> stream = this.stream().skip(offset).limit(size);
+
+        return from(stream);
+    }
+
+    @Override
+    public <U> Queryable<U> select(Function<? super T, ? extends U> mapper) {
+        Stream<U> stream = this.stream().map(mapper);
+
+        return from(stream);
+    }
+
+    @Override
+    public Queryable<T> distinct() {
+        Stream<? extends T> stream = this.stream().distinct();
+
+        return from(stream);
+    }
+
+    @Override
+    public Queryable<T> unionAll(Queryable<? extends T> queryable) {
+        Stream<T> stream = Stream.concat(this.stream(), queryable.stream());
+
+        return from(stream);
+    }
+
+    @Override
+    public Queryable<T> intersect(Queryable<? extends T> queryable) {
+        Stream<T> stream = this.stream().filter(a -> queryable.stream().anyMatch(b -> b.equals(a))).distinct();
+
+        return from(stream);
+    }
+
+    @Override
+    public Queryable<T> minus(Queryable<? extends T> queryable) {
+        Stream<T> stream = this.stream().filter(a -> queryable.stream().noneMatch(b -> b.equals(a))).distinct();
+
+        return from(stream);
+    }
+
+    @Override
+    public List<T> toList() {
+        return stream().collect(Collectors.toList());
+    }
+
+    @Override
+    public Stream<T> stream() {
+        try {
+            sourceStream = sourceStream.peek(e -> {}); // check whether the stream is usable
+        } catch (IllegalStateException ex) {
+            sourceStream = toStream(sourceIterable);  // we have to create new stream every time because Java stream can not be reused
+        }
+
+        return sourceStream;
+    }
+
+    @Override
+    public int count() {
+        return toList().size();
+    }
+
+    @Override
+    public BigDecimal sum(Function<? super T, BigDecimal> mapper) {
+        return this.stream().map(mapper).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
+    private static <T, U> Queryable<Tuple2<T, U>> outerJoin(Queryable<? extends T> queryable1, Queryable<? extends U> queryable2, BiPredicate<? super T, ? super U> joiner) {
+        Stream<Tuple2<T, U>> stream =
+                queryable1.stream()
+                        .flatMap(p ->
+                                queryable2.stream()
+                                        .map(c -> joiner.test(p, c) ? c : null)
+                                        .reduce(new LinkedList<U>(), (r, e) -> {
+                                            int size = r.size();
+                                            if (0 == size) {
+                                                r.add(e);
+                                                return r;
+                                            }
+
+                                            int lastIndex = size - 1;
+                                            Object lastElement = r.get(lastIndex);
+
+                                            if (null != e) {
+                                                if (null == lastElement) {
+                                                    r.set(lastIndex, e);
+                                                } else {
+                                                    r.add(e);
+                                                }
+                                            }
+
+                                            return r;
+                                        }, (i, o) -> o).stream()
+                                        .map(c -> null == c ? Tuple.tuple(p, null) : Tuple.tuple(p, c)));
+
+        return from(stream);
+    }
+
+    private static <T> Stream<T> toStream(Iterable<T> sourceIterable) {
+        return StreamSupport.stream(sourceIterable.spliterator(), false);
+    }
+
+    private static <T> Iterable<T> toIterable(Stream<T> sourceStream) {
+        return sourceStream::iterator;
+    }
+}
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy
new file mode 100644
index 0000000..be20ea6
--- /dev/null
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/provider/QueryableCollectionTest.groovy
@@ -0,0 +1,403 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.provider
+
+
+import groovy.transform.CompileDynamic
+import groovy.transform.CompileStatic
+import groovy.transform.EqualsAndHashCode
+import groovy.transform.ToString
+import org.apache.groovy.linq.Queryable
+import org.junit.Test
+
+import java.util.stream.Stream
+
+@CompileStatic
+class QueryableCollectionTest {
+    @Test
+    void testFrom() {
+        assert [1, 2, 3] == QueryableCollection.from(Stream.of(1, 2, 3)).toList()
+        assert [1, 2, 3] == QueryableCollection.from(Arrays.asList(1, 2, 3)).toList()
+    }
+
+    @Test
+    void testInnerJoin0() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [1, 2, 3]
+        def result = QueryableCollection.from(nums1).innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testInnerJoin1() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testLeftJoin0() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [1, 2, 3]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testRightJoin0() {
+        def nums2 = [1, 2, 3]
+        def nums1 = [1, 2, 3]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testLeftJoin1() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testRightJoin1() {
+        def nums2 = [1, 2, 3]
+        def nums1 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testLeftJoin2() {
+        def nums1 = [1, 2, 3, null]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin2() {
+        def nums2 = [1, 2, 3, null]
+        def nums1 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin3() {
+        def nums1 = [1, 2, 3, null]
+        def nums2 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin3() {
+        def nums2 = [1, 2, 3, null]
+        def nums1 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin4() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testRightJoin4() {
+        def nums2 = [1, 2, 3]
+        def nums1 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testLeftJoin5() {
+        def nums1 = [1, 2, 3, null, null]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin5() {
+        def nums2 = [1, 2, 3, null, null]
+        def nums1 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin6() {
+        def nums1 = [1, 2, 3, null, null]
+        def nums2 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin6() {
+        def nums2 = [1, 2, 3, null, null]
+        def nums1 = [2, 3, 4, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin7() {
+        def nums1 = [1, 2, 3, null, null]
+        def nums2 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin7() {
+        def nums2 = [1, 2, 3, null, null]
+        def nums1 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin8() {
+        def nums1 = [1, 2, 3, null]
+        def nums2 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testRightJoin8() {
+        def nums2 = [1, 2, 3, null]
+        def nums1 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3], [null, null]] == result
+    }
+
+    @Test
+    void testLeftJoin9() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).leftJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testRightJoin9() {
+        def nums2 = [1, 2, 3]
+        def nums1 = [2, 3, 4, null, null]
+        def result = QueryableCollection.from(nums1).rightJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[null, 1], [2, 2], [3, 3]] == result
+    }
+
+    @Test
+    void testFullJoin() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).fullJoin(QueryableCollection.from(nums2), (a, b) -> a == b).toList()
+        assert [[1, null], [2, 2], [3, 3], [null, 4]] == result
+    }
+
+    @Test
+    void testCrossJoin() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [3, 4, 5]
+        def result = QueryableCollection.from(nums1).crossJoin(QueryableCollection.from(nums2)).toList()
+        assert [[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 3], [3, 4], [3, 5]] == result
+    }
+
+    @Test
+    void testWhere() {
+        def nums = [1, 2, 3, 4, 5]
+        def result = QueryableCollection.from(nums).where(e -> e > 3).toList()
+        assert [4, 5] == result
+    }
+
+    @Test
+    void testGroupBySelect0() {
+        def nums = [1, 2, 2, 3, 3, 4, 4, 5]
+        def result = QueryableCollection.from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.toList())).toList()
+        assert [[1, [1]], [2, [2, 2]], [3, [3, 3]], [4, [4, 4]], [5, [5]]] == result
+    }
+
+    @Test
+    void testGroupBySelect1() {
+        def nums = [1, 2, 2, 3, 3, 4, 4, 5]
+        def result = QueryableCollection.from(nums).groupBy(e -> e).select(e -> Tuple.tuple(e.v1, e.v2.count())).toList()
+        assert [[1, 1], [2, 2], [3, 2], [4, 2], [5, 1]] == result
+    }
+
+    @Test
+    void testGroupBySelect2() {
+        def nums = [1, 2, 2, 3, 3, 4, 4, 5]
+        def result =
+                QueryableCollection.from(nums).groupBy(e -> e)
+                        .select(e ->
+                                Tuple.tuple(
+                                        e.v1,
+                                        e.v2.count(),
+                                        e.v2.sum(n -> new BigDecimal(n))
+                                )
+                        ).toList()
+        assert [[1, 1, 1], [2, 2, 4], [3, 2, 6], [4, 2, 8], [5, 1, 5]] == result
+    }
+
+    @Test
+    @CompileDynamic
+    void testGroupBySelect3() {
+        def nums = [1, 2, 2, 3, 3, 4, 4, 5]
+        def result =
+                QueryableCollection.from(nums).groupBy(e -> e, (k, q) -> k > 2)
+                        .select(e ->
+                                Tuple.tuple(
+                                        e.v1,
+                                        e.v2.count(),
+                                        e.v2.sum(n -> new BigDecimal(n))
+                                )
+                        ).toList()
+        assert [[3, 2, 6], [4, 2, 8], [5, 1, 5]] == result
+    }
+
+    @Test
+    void testOrderBy() {
+        Person daniel = new Person('Daniel', 35)
+        Person peter = new Person('Peter', 10)
+        Person alice = new Person('Alice', 22)
+        Person john = new Person('John', 10)
+
+        def persons = [daniel, peter, alice, john]
+        def result = QueryableCollection.from(persons).orderBy(
+                new Queryable.Order<Person, Comparable>((Person e) -> e.age, true),
+                new Queryable.Order<Person, Comparable>((Person e) -> e.name, true)
+        ).toList()
+        assert [john, peter, alice, daniel] == result
+
+        result = QueryableCollection.from(persons).orderBy(
+                new Queryable.Order<Person, Comparable>((Person e) -> e.age, false),
+                new Queryable.Order<Person, Comparable>((Person e) -> e.name, true)
+        ).toList()
+        assert [daniel, alice, john, peter] == result
+
+        result = QueryableCollection.from(persons).orderBy(
+                new Queryable.Order<Person, Comparable>((Person e) -> e.age, true),
+                new Queryable.Order<Person, Comparable>((Person e) -> e.name, false)
+        ).toList()
+        assert [peter, john, alice, daniel] == result
+
+        result = QueryableCollection.from(persons).orderBy(
+                new Queryable.Order<Person, Comparable>((Person e) -> e.age, false),
+                new Queryable.Order<Person, Comparable>((Person e) -> e.name, false)
+        ).toList()
+        assert [daniel, alice, peter, john] == result
+    }
+
+    @Test
+    void testLimit() {
+        def nums = [1, 2, 3, 4, 5]
+        def result = QueryableCollection.from(nums).limit(1, 2).toList()
+        assert [2, 3] == result
+
+        result = QueryableCollection.from(nums).limit(2).toList()
+        assert [1, 2] == result
+    }
+
+    @Test
+    void testSelect() {
+        def nums = [1, 2, 3, 4, 5]
+        def result = QueryableCollection.from(nums).select(e -> e + 1).toList()
+        assert [2, 3, 4, 5, 6] == result
+    }
+
+    @Test
+    void testDistinct() {
+        def nums = [1, 2, 2, 3, 3, 2, 3, 4, 5, 5]
+        def result = QueryableCollection.from(nums).distinct().toList()
+        assert [1, 2, 3, 4, 5] == result
+    }
+
+    @Test
+    void testUnion() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).union(QueryableCollection.from(nums2)).toList()
+        assert [1, 2, 3, 4] == result
+    }
+
+    @Test
+    void testUnionAll() {
+        def nums1 = [1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).unionAll(QueryableCollection.from(nums2)).toList()
+        assert [1, 2, 3, 2, 3, 4] == result
+    }
+
+    @Test
+    void testIntersect() {
+        def nums1 = [1, 2, 2, 3]
+        def nums2 = [2, 3, 3, 4]
+        def result = QueryableCollection.from(nums1).intersect(QueryableCollection.from(nums2)).toList()
+        assert [2, 3] == result
+    }
+
+    @Test
+    void testMinus() {
+        def nums1 = [1, 1, 2, 3]
+        def nums2 = [2, 3, 4]
+        def result = QueryableCollection.from(nums1).minus(QueryableCollection.from(nums2)).toList()
+        assert [1] == result
+    }
+
+    @Test
+    void testFromWhereLimitSelect() {
+        def nums1 = [1, 2, 3, 4, 5]
+        def nums2 = [0, 1, 2, 3, 4, 5, 6]
+        def result =
+                QueryableCollection.from(nums1)
+                        .innerJoin(QueryableCollection.from(nums2), (a, b) -> a == b)
+                        .where(t -> t.v1 > 1)
+                        .limit(1, 2)
+                        .select(t -> t.v1 + 1)
+                        .toList()
+        assert [4, 5] == result
+    }
+
+//    @Test void testIterator() {
+//        def nums = [1, 2, 3]
+//        def result = from(nums).iterator().toList()
+//        assert nums == result
+//    }
+
+    @ToString
+    @EqualsAndHashCode
+    static class Person {
+        String name
+        int age
+
+        Person(String name, int age) {
+            this.name = name
+            this.age = age
+        }
+    }
+}


[groovy] 02/22: GROOVY-8258: Add macro method LINQ entry

Posted by su...@apache.org.
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 3e39e7022e667173dafda9813ad0165dec29419d
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 00:32:21 2020 +0800

    GROOVY-8258: Add macro method LINQ entry
---
 subprojects/groovy-linq/build.gradle                       | 11 +++++++++--
 .../groovy/org/apache/groovy/linq/LinqGroovyMethods.java}  | 14 +++++++++++---
 .../{java => groovy}/org/apache/groovy/linq/Queryable.java |  0
 .../apache/groovy/linq/provider/QueryableCollection.java   |  0
 4 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/subprojects/groovy-linq/build.gradle b/subprojects/groovy-linq/build.gradle
index 8e249dd..5c6a05b 100644
--- a/subprojects/groovy-linq/build.gradle
+++ b/subprojects/groovy-linq/build.gradle
@@ -17,8 +17,15 @@
  *  under the License.
  */
 
-
 dependencies {
-    api rootProject
+    implementation rootProject
+    implementation project(':groovy-macro')
+    testImplementation rootProject.sourceSets.test.runtimeClasspath
     testImplementation project(':groovy-test')
 }
+
+task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorTask) {
+    extensionClasses = 'org.apache.groovy.linq.LinqGroovyMethods'
+}
+
+compileJava.dependsOn moduleDescriptor
diff --git a/subprojects/groovy-linq/build.gradle b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
similarity index 66%
copy from subprojects/groovy-linq/build.gradle
copy to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
index 8e249dd..936e6be 100644
--- a/subprojects/groovy-linq/build.gradle
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.java
@@ -16,9 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.groovy.linq;
 
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.macro.runtime.Macro;
+import org.codehaus.groovy.macro.runtime.MacroContext;
 
-dependencies {
-    api rootProject
-    testImplementation project(':groovy-test')
+public class LinqGroovyMethods {
+    @Macro
+    public static Expression LINQ(MacroContext ctx, final ClosureExpression closureExpression) {
+        return null; // TODO
+    }
 }
+
diff --git a/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/Queryable.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java
similarity index 100%
rename from subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/Queryable.java
rename to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/Queryable.java
diff --git a/subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/provider/QueryableCollection.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java
similarity index 100%
rename from subprojects/groovy-linq/src/main/java/org/apache/groovy/linq/provider/QueryableCollection.java
rename to subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/QueryableCollection.java


[groovy] 18/22: GROOVY-8258: Add node positions and error tests

Posted by su...@apache.org.
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 b94d20f9b60255b344a1f74ecc379606f4ddb1d9
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 23:35:51 2020 +0800

    GROOVY-8258: Add node positions and error tests
---
 .../apache/groovy/linq/GinqGroovyMethods.groovy    |  2 +-
 .../org/apache/groovy/linq/dsl/GinqAstBuilder.java | 45 +++++++++++++++--
 .../apache/groovy/linq/dsl/GinqSyntaxError.java    | 43 +++++++++++++++++
 .../dsl/expression/AbstractGinqExpression.java     | 44 +++++++++++++++++
 .../org/apache/groovy/linq/GinqErrorTest.groovy    | 56 ++++++++++++++++++++++
 5 files changed, 186 insertions(+), 4 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
index 5e521bb..c3f0dcb 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/GinqGroovyMethods.groovy
@@ -35,7 +35,7 @@ class GinqGroovyMethods {
     static Expression GINQ(MacroContext ctx, final ClosureExpression closureExpression) {
         Statement code = closureExpression.getCode()
 
-        GinqAstBuilder ginqAstBuilder = new GinqAstBuilder()
+        GinqAstBuilder ginqAstBuilder = new GinqAstBuilder(ctx.getSourceUnit())
         code.visit(ginqAstBuilder)
         SimpleGinqExpression simpleGinqExpression = ginqAstBuilder.getSimpleGinqExpression()
 
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 9a365e5..c80e347 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
@@ -30,6 +30,10 @@ import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.syntax.Types;
 
 /**
  * Build the AST for GINQ
@@ -39,6 +43,11 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
 public class GinqAstBuilder extends CodeVisitorSupport {
     private SimpleGinqExpression simpleGinqExpression = new SimpleGinqExpression(); // store the result
     private GinqExpression ginqExpression; // store the return value
+    private final SourceUnit sourceUnit;
+
+    public GinqAstBuilder(SourceUnit sourceUnit) {
+        this.sourceUnit = sourceUnit;
+    }
 
     public SimpleGinqExpression getSimpleGinqExpression() {
         return simpleGinqExpression;
@@ -52,13 +61,32 @@ public class GinqAstBuilder extends CodeVisitorSupport {
 
         if ("from".equals(methodName)) {
             ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments();
-            BinaryExpression binaryExpression = (BinaryExpression) arguments.getExpression(0);
+            if (arguments.getExpressions().size() != 1) {
+                this.collectSyntaxError(
+                        new GinqSyntaxError(
+                                "Only 1 argument expected for `from`, e.g. `from n in nums`",
+                                call.getLineNumber(), call.getColumnNumber()
+                        )
+                );
+            }
+            final Expression expression = arguments.getExpression(0);
+            if (!(expression instanceof BinaryExpression
+                    && ((BinaryExpression) expression).getOperation().getType() == Types.KEYWORD_IN)) {
+                this.collectSyntaxError(
+                        new GinqSyntaxError(
+                                "`in` is expected for `from`, e.g. `from n in nums`",
+                                call.getLineNumber(), call.getColumnNumber()
+                        )
+                );
+            }
+            BinaryExpression binaryExpression = (BinaryExpression) expression;
             Expression aliasExpr = binaryExpression.getLeftExpression();
             Expression dataSourceExpr = binaryExpression.getRightExpression();
 
             FromExpression fromExpression = new FromExpression(aliasExpr, dataSourceExpr);
-            simpleGinqExpression.addFromExpression(fromExpression);
+            fromExpression.setSourcePosition(call);
 
+            simpleGinqExpression.addFromExpression(fromExpression);
             ginqExpression = fromExpression;
             return;
         }
@@ -66,6 +94,7 @@ public class GinqAstBuilder extends CodeVisitorSupport {
         if ("where".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);
@@ -78,11 +107,21 @@ public class GinqAstBuilder extends CodeVisitorSupport {
 
         if ("select".equals(methodName)) {
             SelectExpression selectExpression = new SelectExpression(call.getArguments());
-            simpleGinqExpression.setSelectExpression(selectExpression);
+            selectExpression.setSourcePosition(call);
 
+            simpleGinqExpression.setSelectExpression(selectExpression);
             ginqExpression = selectExpression;
 
             return;
         }
     }
+
+    private void collectSyntaxError(GinqSyntaxError ginqSyntaxError) {
+        SyntaxException e = new SyntaxException(
+                ginqSyntaxError.getMessage(),
+                ginqSyntaxError,
+                ginqSyntaxError.getLine(),
+                ginqSyntaxError.getColumn());
+        sourceUnit.getErrorCollector().addFatalError(new SyntaxErrorMessage(e, sourceUnit));
+    }
 }
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqSyntaxError.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqSyntaxError.java
new file mode 100644
index 0000000..652d835
--- /dev/null
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/GinqSyntaxError.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq.dsl;
+
+/**
+ * Represents GINQ syntax error
+ *
+ * @since 4.0.0
+ */
+public class GinqSyntaxError extends AssertionError {
+    private final int line;
+    private final int column;
+
+    public GinqSyntaxError(String message, int line, int column) {
+        super(message, null);
+        this.line = line;
+        this.column = column;
+    }
+
+    public int getLine() {
+        return line;
+    }
+
+    public int getColumn() {
+        return column;
+    }
+}
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
index 25e20c9..5cc3c36 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/dsl/expression/AbstractGinqExpression.java
@@ -1,5 +1,6 @@
 package org.apache.groovy.linq.dsl.expression;
 
+import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.NodeMetaDataHandler;
 
 import java.util.LinkedHashMap;
@@ -12,6 +13,10 @@ import java.util.Map;
  */
 public abstract class AbstractGinqExpression implements GinqExpression, NodeMetaDataHandler {
     private Map<?, ?> metaDataMap = new LinkedHashMap<>();
+    private int lineNumber = -1;
+    private int columnNumber = -1;
+    private int lastLineNumber = -1;
+    private int lastColumnNumber = -1;
 
     @Override
     public Map<?, ?> getMetaDataMap() {
@@ -22,4 +27,43 @@ public abstract class AbstractGinqExpression implements GinqExpression, NodeMeta
     public void setMetaDataMap(Map<?, ?> metaDataMap) {
         this.metaDataMap = metaDataMap;
     }
+
+    public void setSourcePosition(ASTNode node) {
+        this.lineNumber = node.getLineNumber();
+        this.columnNumber = node.getColumnNumber();
+        this.lastLineNumber = node.getLastLineNumber();
+        this.lastColumnNumber = node.getLastColumnNumber();
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public void setColumnNumber(int columnNumber) {
+        this.columnNumber = columnNumber;
+    }
+
+    public int getLastLineNumber() {
+        return lastLineNumber;
+    }
+
+    public void setLastLineNumber(int lastLineNumber) {
+        this.lastLineNumber = lastLineNumber;
+    }
+
+    public int getLastColumnNumber() {
+        return lastColumnNumber;
+    }
+
+    public void setLastColumnNumber(int lastColumnNumber) {
+        this.lastColumnNumber = lastColumnNumber;
+    }
 }
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy
new file mode 100644
index 0000000..cee78af
--- /dev/null
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqErrorTest.groovy
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.linq
+
+
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.shouldFail
+
+
+@CompileStatic
+class GinqErrorTest {
+    @Test
+    void "testGinq - from select - 1"() {
+        def err = shouldFail '''\
+            def numbers = [0, 1, 2]
+            GINQ {
+                from numbers
+                select n
+            }
+        '''
+
+        assert err.toString().contains('`in` is expected for `from`, e.g. `from n in nums` @ line 3, column 17.')
+    }
+
+    @Test
+    void "testGinq - from select - 2"() {
+        def err = shouldFail '''\
+            def numbers = [0, 1, 2]
+            GINQ {
+                from n, numbers
+                select n
+            }
+        '''
+
+        assert err.toString().contains('Only 1 argument expected for `from`, e.g. `from n in nums` @ line 3, column 17.')
+    }
+
+}


[groovy] 10/22: GROOVY-8258: use lambda instead

Posted by su...@apache.org.
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 0c7a6fe0c2f7f786a07b04719944a13923144084
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:40:58 2020 +0800

    GROOVY-8258: use lambda instead
---
 src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java  |  9 +++++++++
 .../groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy     | 10 +++++-----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
index 6abbe61..15e4db6 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -43,6 +43,7 @@ import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.DeclarationExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.LambdaExpression;
 import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
@@ -251,6 +252,14 @@ public class GeneralUtils {
         return closureX(Parameter.EMPTY_ARRAY, code);
     }
 
+    public static LambdaExpression lambdaX(final Parameter[] params, final Statement code) {
+        return new LambdaExpression(params, code);
+    }
+
+    public static LambdaExpression lambdaX(final Statement code) {
+        return lambdaX(Parameter.EMPTY_ARRAY, code);
+    }
+
     /**
      * Builds a binary expression that compares two values.
      *
diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
index 71c3fe5..ad132e2 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/LinqGroovyMethods.groovy
@@ -32,7 +32,7 @@ import org.codehaus.groovy.macro.runtime.Macro
 import org.codehaus.groovy.macro.runtime.MacroContext
 
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.closureX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.lambdaX
 import static org.codehaus.groovy.ast.tools.GeneralUtils.param
 import static org.codehaus.groovy.ast.tools.GeneralUtils.params
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt
@@ -93,20 +93,20 @@ class LinqGroovyMethods {
         selectMethodReceiver = from
 
         if (linqContext.whereList.size() > 0) {
-            MethodCallExpression where = callXWithClosure(from, "where", aliasVariable.name, linqContext.whereList[0])
+            MethodCallExpression where = callXWithLambda(from, "where", aliasVariable.name, linqContext.whereList[0])
             selectMethodReceiver = where
         }
 
-        MethodCallExpression select = callXWithClosure(selectMethodReceiver, "select", aliasVariable.name, linqContext.selectList[0])
+        MethodCallExpression select = callXWithLambda(selectMethodReceiver, "select", aliasVariable.name, linqContext.selectList[0])
 
         return select
     }
 
-    private static callXWithClosure(Expression receiver, String methodName, String closureParamName, Expression closureCode) {
+    private static callXWithLambda(Expression receiver, String methodName, String closureParamName, Expression closureCode) {
         callX(
                 receiver,
                 methodName,
-                closureX(
+                lambdaX(
                         params(param(ClassHelper.DYNAMIC_TYPE, closureParamName)),
                         stmt(closureCode)
                 )


[groovy] 09/22: GROOVY-8258: rename test names

Posted by su...@apache.org.
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 581ee9525c73f5761a6b0f9f37fd3c6416567816
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Oct 5 04:34:26 2020 +0800

    GROOVY-8258: rename test names
---
 .../src/test/groovy/org/apache/groovy/linq/LinqTest.groovy          | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
index b2b0887..30ad372 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/LinqTest.groovy
@@ -28,7 +28,7 @@ import static groovy.test.GroovyAssert.assertScript
 @CompileStatic
 class LinqTest {
     @Test
-    void "testLinqMacroMethod - from select - 1"() {
+    void "testLinq - from select - 1"() {
         assertScript '''
             def numbers = [0, 1, 2]
             assert [0, 1, 2] == LINQ {
@@ -39,7 +39,7 @@ class LinqTest {
     }
 
     @Test
-    void "testLinqMacroMethod - from select - 2"() {
+    void "testLinq - from select - 2"() {
         assertScript '''
             def numbers = [0, 1, 2]
             assert [0, 2, 4] == LINQ {
@@ -50,7 +50,7 @@ class LinqTest {
     }
 
     @Test
-    void "testLinqMacroMethod - from where select"() {
+    void "testLinq - from where select"() {
         assertScript '''
             def numbers = [0, 1, 2, 3, 4, 5]
             assert [2, 4, 6] == LINQ {