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/23 00:09:05 UTC

[groovy] branch master updated: Tweak validation for window function and add more test cases

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 544ef57  Tweak validation for window function and add more test cases
544ef57 is described below

commit 544ef57dea9bc698381749b25780793c08cb1279
Author: Daniel Sun <su...@apache.org>
AuthorDate: Wed Dec 23 08:08:01 2020 +0800

    Tweak validation for window function and add more test cases
---
 .../ginq/provider/collection/GinqAstWalker.groovy  | 74 +++++++++++++---------
 .../test/org/apache/groovy/ginq/GinqTest.groovy    | 21 ++++++
 .../org/apache/groovy/ginq/GinqErrorTest.groovy    | 12 ++++
 3 files changed, 76 insertions(+), 31 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 017ed64..5b1cd1d 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
@@ -666,41 +666,53 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
                             VariableExpression currentRecordVar = varX(lambdaParamName)
 
                             currentGinqExpression.putNodeMetaData(__VISITING_WINDOW_FUNCTION, true)
-                            def windowDefinitionFactoryMethodCallExpression = constructWindowDefinitionFactoryMethodCallExpression(expression, dataSourceExpression)
-                            Expression newObjectExpression = callX(wqVar, 'over', args(
-                                    currentRecordVar,
-                                    windowDefinitionFactoryMethodCallExpression
-                            ))
-
                             def windowFunctionMethodCallExpression = (MethodCallExpression) expression.objectExpression
-                            def windowFunctionLambdaCode = ((ArgumentListExpression) windowFunctionMethodCallExpression.arguments).getExpression(0)
-                            def windowFunctionLambdaName = findRootObjectExpression(windowFunctionLambdaCode).text
-                            def newWindowFunctionLambdaName = '__wfp'
-
-                            windowFunctionLambdaCode = ((ListExpression) (new ListExpression(Collections.singletonList(windowFunctionLambdaCode)).transformExpression(new ExpressionTransformer() {
-                                @Override
-                                Expression transform(Expression expr) {
-                                    if (expr instanceof VariableExpression) {
-                                        if (windowFunctionLambdaName == expr.text) {
-                                            if (dataSourceExpression instanceof JoinExpression) {
-                                                return correctVars(dataSourceExpression, newWindowFunctionLambdaName=getLambdaParamName(dataSourceExpression, expr), expr)
-                                            } else {
-                                                return new VariableExpression(newWindowFunctionLambdaName)
+
+                            Expression result = null
+                            if (windowFunctionMethodCallExpression.methodAsString in ['lead', 'lag']) {
+                                def windowFunctionLambdaCode = ((ArgumentListExpression) windowFunctionMethodCallExpression.arguments).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)
-
-                            def result = callX(
-                                    newObjectExpression,
-                                    windowFunctionMethodCallExpression.methodAsString,
-                                    lambdaX(
-                                            params(param(ClassHelper.DYNAMIC_TYPE, newWindowFunctionLambdaName)),
-                                            block(stmt(windowFunctionLambdaCode))
-                                    )
-                            )
+                                }))).getExpression(0)
+
+                                def argumentExpressionList = []
+                                argumentExpressionList << lambdaX(
+                                        params(param(ClassHelper.DYNAMIC_TYPE, windowFunctionLambdaName)),
+                                        block(stmt(windowFunctionLambdaCode))
+                                )
+
+                                def windowDefinitionFactoryMethodCallExpression = constructWindowDefinitionFactoryMethodCallExpression(expression, dataSourceExpression)
+                                Expression newObjectExpression = callX(wqVar, 'over', args(
+                                        currentRecordVar,
+                                        windowDefinitionFactoryMethodCallExpression
+                                ))
+                                result = callX(
+                                        newObjectExpression,
+                                        windowFunctionMethodCallExpression.methodAsString,
+                                        args(argumentExpressionList)
+                                )
+                            } else {
+                                GinqAstWalker.this.collectSyntaxError(new GinqSyntaxError(
+                                        "Unsupported window function: `${windowFunctionMethodCallExpression.methodAsString}`",
+                                        windowFunctionMethodCallExpression.getLineNumber(), windowFunctionMethodCallExpression.getColumnNumber()
+                                ))
+                            }
+
                             currentGinqExpression.putNodeMetaData(__VISITING_WINDOW_FUNCTION, false)
 
                             return result
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 6d2b48d..f0251fa 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
@@ -4669,6 +4669,27 @@ class GinqTest {
         '''
     }
 
+    @Test
+    void "testGinq - window - 2"() {
+        assertGinqScript '''
+            assert [[2, 3], [1, 2], [3, null]] == GQ {
+                from n in [2, 1, 3]
+                select n, (lead(n) over(orderby n))
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - window - 3"() {
+        assertGinqScript '''
+            assert [[2, 3], [1, 2], [3, null]] == GQ {
+                from n in [2, 1, 3]
+                join m in [2, 1, 3] on m == n
+                select n, (lead(n) over(orderby n))
+            }.toList()
+        '''
+    }
+
     private static void assertGinqScript(String script) {
         String deoptimizedScript = script.replaceAll(/\bGQ\s*[{]/, 'GQ(optimize:false) {')
         List<String> scriptList = [deoptimizedScript, script]
diff --git a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy b/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
index cd365f0..8bf9087 100644
--- a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
+++ b/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqErrorTest.groovy
@@ -430,4 +430,16 @@ class GinqErrorTest {
 
         assert err.toString().contains('Only binary expressions(`==`, `&&`) are allowed in `on` clause of hash join @ line 3, column 49.')
     }
+
+    @Test
+    void "testGinq - window - 0"() {
+        def err = shouldFail  '''\
+            GQ {
+                from n in [2, 1, 3]
+                select n, (xxx(n) over(orderby n))
+            }.toList()
+        '''
+
+        assert err.toString().contains('Unsupported window function: `xxx` @ line 3, column 28.')
+    }
 }