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/12/26 16:52:29 UTC

[groovy] branch master updated: Support window function `rowNumber`

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

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 865fa04  Support window function `rowNumber`
865fa04 is described below

commit 865fa043da4473ed010ffff19656eb31aca340f5
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Dec 27 00:52:01 2020 +0800

    Support window function `rowNumber`
---
 .../ginq/provider/collection/GinqAstWalker.groovy  | 55 ++++++++++++----------
 .../groovy-ginq/src/spec/doc/ginq-userguide.adoc   | 12 +++--
 .../test/org/apache/groovy/ginq/GinqTest.groovy    | 12 +++++
 3 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
index fce78b0..30347b5 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy
@@ -677,36 +677,38 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
                             Expression result = null
                             if (windowFunctionMethodCallExpression.methodAsString in WINDOW_FUNCTION_LIST) {
                                 def argumentListExpression = (ArgumentListExpression) windowFunctionMethodCallExpression.arguments
-                                def windowFunctionLambdaCode = argumentListExpression.getExpression(0)
-                                def windowFunctionLambdaName = '__wfp'
-                                def rootObjectExpression = findRootObjectExpression(windowFunctionLambdaCode)
-
-                                windowFunctionLambdaCode = ((ListExpression) (new ListExpression(Collections.singletonList(windowFunctionLambdaCode)).transformExpression(new ExpressionTransformer() {
-                                    @Override
-                                    Expression transform(Expression expr) {
-                                        if (expr instanceof VariableExpression) {
-                                            if (rootObjectExpression.text == expr.text) {
-                                                if (dataSourceExpression instanceof JoinExpression) {
-                                                    return correctVars(dataSourceExpression, windowFunctionLambdaName=getLambdaParamName(dataSourceExpression, expr), expr)
-                                                } else {
-                                                    return new VariableExpression(windowFunctionLambdaName)
+                                List<Expression> argumentExpressionList = []
+                                if (windowFunctionMethodCallExpression.methodAsString !in [FUNCTION_ROW_NUMBER]) {
+                                    def windowFunctionLambdaCode = argumentListExpression.getExpression(0)
+                                    def windowFunctionLambdaName = '__wfp'
+                                    def rootObjectExpression = findRootObjectExpression(windowFunctionLambdaCode)
+
+                                    windowFunctionLambdaCode = ((ListExpression) (new ListExpression(Collections.singletonList(windowFunctionLambdaCode)).transformExpression(new ExpressionTransformer() {
+                                        @Override
+                                        Expression transform(Expression expr) {
+                                            if (expr instanceof VariableExpression) {
+                                                if (rootObjectExpression.text == expr.text) {
+                                                    if (dataSourceExpression instanceof JoinExpression) {
+                                                        return correctVars(dataSourceExpression, windowFunctionLambdaName=getLambdaParamName(dataSourceExpression, expr), expr)
+                                                    } else {
+                                                        return new VariableExpression(windowFunctionLambdaName)
+                                                    }
                                                 }
                                             }
+                                            return expr.transformExpression(this)
                                         }
-                                        return expr.transformExpression(this)
-                                    }
-                                }))).getExpression(0)
+                                    }))).getExpression(0)
 
-                                def argumentExpressionList = []
-                                argumentExpressionList << lambdaX(
-                                        params(param(ClassHelper.DYNAMIC_TYPE, windowFunctionLambdaName)),
-                                        block(stmt(windowFunctionLambdaCode))
-                                )
+                                    argumentExpressionList << lambdaX(
+                                            params(param(ClassHelper.DYNAMIC_TYPE, windowFunctionLambdaName)),
+                                            block(stmt(windowFunctionLambdaCode))
+                                    )
 
-                                if (windowFunctionMethodCallExpression.methodAsString in [FUNCTION_LEAD, FUNCTION_LAG]) {
-                                    List<Expression> exprList = argumentListExpression.getExpressions()
-                                    if (exprList.size() > 1) {
-                                        argumentExpressionList.addAll(exprList.subList(1, exprList.size()))
+                                    if (windowFunctionMethodCallExpression.methodAsString in [FUNCTION_LEAD, FUNCTION_LAG]) {
+                                        List<Expression> exprList = argumentListExpression.getExpressions()
+                                        if (exprList.size() > 1) {
+                                            argumentExpressionList.addAll(exprList.subList(1, exprList.size()))
+                                        }
                                     }
                                 }
 
@@ -1342,12 +1344,13 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
     private static final String FUNCTION_AGG = 'agg'
     private static final List<String> AGG_FUNCTION_NAME_LIST = [FUNCTION_COUNT, FUNCTION_MIN, FUNCTION_MAX, FUNCTION_SUM, FUNCTION_AVG, FUNCTION_MEDIAN, FUNCTION_AGG]
 
+    private static final String FUNCTION_ROW_NUMBER = 'rowNumber'
     private static final String FUNCTION_LEAD = 'lead'
     private static final String FUNCTION_LAG = 'lag'
     private static final String FUNCTION_FIRST_VALUE = 'firstValue'
     private static final String FUNCTION_LAST_VALUE = 'lastValue'
     private static final List<String> WINDOW_FUNCTION_LIST = [FUNCTION_COUNT, FUNCTION_MIN, FUNCTION_MAX, FUNCTION_SUM, FUNCTION_AVG, FUNCTION_MEDIAN,
-                                                              FUNCTION_LEAD, FUNCTION_LAG, FUNCTION_FIRST_VALUE, FUNCTION_LAST_VALUE]
+                                                              FUNCTION_ROW_NUMBER, FUNCTION_LEAD, FUNCTION_LAG, FUNCTION_FIRST_VALUE, FUNCTION_LAST_VALUE]
 
     private static final String NAMEDRECORD_CLASS_NAME = NamedRecord.class.name
 
diff --git a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
index 95f9c37..46631cf 100644
--- a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
+++ b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
@@ -411,16 +411,22 @@ include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_nested_04,inde
 
 ==== Window Functions
 GINQ supports some built-in window functions, e.g.
-`lead`, `lag`, `firstValue`, `lastValue`, `min`, `max`, `count`, `sum`, `avg`, `median`, etc.
+`rowNumber`, `lead`, `lag`, `firstValue`, `lastValue`, `min`, `max`, `count`, `sum`, `avg`, `median`, etc.
 
-===== `lead` and `lag`
+===== `rowNumber`
 [source, groovy]
 ----
-include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_winfunction_02,indent=0]
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_winfunction_24,indent=0]
 ----
 [NOTE]
 The parentheses around the window function is required.
 
+===== `lead` and `lag`
+[source, groovy]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_winfunction_02,indent=0]
+----
+
 [source, groovy]
 ----
 include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_winfunction_04,indent=0]
diff --git a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index afb84c6..3e6f7f98 100644
--- a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -5147,6 +5147,18 @@ class GinqTest {
         '''
     }
 
+    @Test
+    void "testGinq - window - 43"() {
+        assertGinqScript '''
+// tag::ginq_winfunction_24[]
+            assert [[2, 1], [1, 0], [3, 2]] == GQ {
+                from n in [2, 1, 3]
+                select n, (rowNumber() over(orderby n))
+            }.toList()
+// end::ginq_winfunction_24[]
+        '''
+    }
+
     private static void assertGinqScript(String script) {
         String deoptimizedScript = script.replaceAll(/\bGQ\s*[{]/, 'GQ(optimize:false) {')
         List<String> scriptList = [deoptimizedScript, script]