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/04 20:09:11 UTC

[groovy] branch GROOVY-8258 updated (85879be -> fcb8590)

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.


    from 85879be  GROOVY-8258: test `stream` method and tweak tests
     new a950f51  GROOVY-8258: mark backend classes as internal
     new fcb8590  GROOVY-8258: Implement the very basic LINQ

The 2 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:
 .../apache/groovy/linq/LinqGroovyMethods.groovy    | 104 ++++++++++++++++++++-
 .../groovy/org/apache/groovy/linq/Queryable.java   |   2 +
 .../groovy/linq/provider/QueryableCollection.java  |   7 ++
 .../groovy/org/apache/groovy/linq/LinqTest.groovy  |   9 +-
 4 files changed, 118 insertions(+), 4 deletions(-)


[groovy] 02/02: 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 fcb8590583181d9e062e87b86cad6592eb0bf080
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] 01/02: 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 a950f5162701035b2b8b652d61c1627ce462f428
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;