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/25 17:20:59 UTC

[groovy] 02/02: Tweak `orderby` for window function

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

commit 89db644b8ad79aa910686e6b059cc9be8cd1ac7c
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Dec 26 01:20:34 2020 +0800

    Tweak `orderby` for window function
---
 .../ginq/provider/collection/GinqAstWalker.groovy  |  4 ++--
 .../provider/collection/runtime/Queryable.java     |  1 +
 .../collection/runtime/WindowDefinition.java       | 23 ++++++++++++++++++----
 .../collection/runtime/WindowDefinitionImpl.java   | 15 +++++++-------
 .../provider/collection/runtime/WindowImpl.java    |  8 ++++----
 .../test/org/apache/groovy/ginq/GinqTest.groovy    | 20 +++++++++++++++++++
 6 files changed, 54 insertions(+), 17 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 5ad13c2..a82357a 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
@@ -760,8 +760,8 @@ class GinqAstWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable
         }
 
         if (orderExpr) {
-            def orderCtorCallExpression = constructOrderCtorCallExpressions(orderExpr, dataSourceExpression).get(0)
-            argumentExpressionList << orderCtorCallExpression
+            def orderCtorCallExpressions = constructOrderCtorCallExpressions(orderExpr, dataSourceExpression)
+            argumentExpressionList << new ListExpression(orderCtorCallExpressions)
         }
 
         callX(
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/Queryable.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/Queryable.java
index cfc422d..8021955 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/Queryable.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/Queryable.java
@@ -462,6 +462,7 @@ public interface Queryable<T> {
     class Order<T, U extends Comparable<? super U>> {
         private final Function<? super T, ? extends U> keyExtractor;
         private final boolean asc;
+        public static final Order[] EMPTY_ARRAY = new Order[0];
 
         public Order(Function<? super T, ? extends U> keyExtractor, boolean asc) {
             this.keyExtractor = keyExtractor;
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinition.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinition.java
index 5567507..88e72f6 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinition.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinition.java
@@ -18,6 +18,8 @@
  */
 package org.apache.groovy.ginq.provider.collection.runtime;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.function.Function;
 
 /**
@@ -52,6 +54,19 @@ public interface WindowDefinition<T, U extends Comparable<? super U>> {
      * @since 4.0.0
      */
     static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Queryable.Order<? super T, ? extends U> orderBy) {
+        return new WindowDefinitionImpl<T, U>(Collections.singletonList(orderBy));
+    }
+
+    /**
+     * Factory method to create {@link WindowDefinition} instance
+     *
+     * @param orderBy order definition
+     * @param <T> the type of {@link Queryable} element
+     * @param <U> the type of field to sort
+     * @return the {@link WindowDefinition} instance
+     * @since 4.0.0
+     */
+    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(List<Queryable.Order<? super T, ? extends U>> orderBy) {
         return new WindowDefinitionImpl<>(orderBy);
     }
 
@@ -65,7 +80,7 @@ public interface WindowDefinition<T, U extends Comparable<? super U>> {
      * @return the {@link WindowDefinition} instance
      * @since 4.0.0
      */
-    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy) {
+    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy) {
         return new WindowDefinitionImpl<>(partitionBy, orderBy);
     }
 
@@ -80,7 +95,7 @@ public interface WindowDefinition<T, U extends Comparable<? super U>> {
      * @return the {@link WindowDefinition} instance
      * @since 4.0.0
      */
-    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy, RowBound rows) {
+    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy, RowBound rows) {
         return new WindowDefinitionImpl<>(partitionBy, orderBy, rows);
     }
 
@@ -95,7 +110,7 @@ public interface WindowDefinition<T, U extends Comparable<? super U>> {
      * @return the {@link WindowDefinition} instance
      * @since 4.0.0
      */
-    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy, ValueBound<? extends U, ? extends U> range) {
+    static <T, U extends Comparable<? super U>> WindowDefinition<T, U> of(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy, ValueBound<? extends U, ? extends U> range) {
         return new WindowDefinitionImpl<>(partitionBy, orderBy, range);
     }
 
@@ -114,7 +129,7 @@ public interface WindowDefinition<T, U extends Comparable<? super U>> {
      * @return order definition
      * @since 4.0.0
      */
-    Queryable.Order<? super T, ? extends U> orderBy();
+    List<Queryable.Order<? super T, ? extends U>> orderBy();
 
     /**
      * Define the window bounds by offsets, similar to MySQL's {@code rows between 1 preceding and 1 following } of window definition
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinitionImpl.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinitionImpl.java
index efd946b..39c350a 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinitionImpl.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowDefinitionImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.groovy.ginq.provider.collection.runtime;
 
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
 
@@ -30,11 +31,11 @@ import java.util.function.Function;
  */
 class WindowDefinitionImpl<T, U extends Comparable<? super U>> implements WindowDefinition<T, U> {
     private final Function<? super T, ?> partitionBy;
-    private final Queryable.Order<? super T, ? extends U> orderBy;
+    private final List<Queryable.Order<? super T, ? extends U>> orderBy;
     private final RowBound rows;
     private final ValueBound<? extends U, ? extends U> range;
 
-    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy,
+    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy,
                                 RowBound rows, ValueBound<? extends U, ? extends U> range) {
         this.partitionBy = partitionBy;
         this.orderBy = orderBy;
@@ -46,20 +47,20 @@ class WindowDefinitionImpl<T, U extends Comparable<? super U>> implements Window
         this(partitionBy, null, RowBound.DEFAULT, null);
     }
 
-    public WindowDefinitionImpl(Queryable.Order<? super T, ? extends U> orderBy) {
+    public WindowDefinitionImpl(List<Queryable.Order<? super T, ? extends U>> orderBy) {
         this((T t) -> Queryable.NULL, orderBy, RowBound.DEFAULT, null);
     }
 
-    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy) {
+    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy) {
         this(partitionBy, orderBy, RowBound.DEFAULT, null);
     }
 
-    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy,
+    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy,
                                 RowBound rows) {
         this(partitionBy, orderBy, rows, null);
     }
 
-    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, Queryable.Order<? super T, ? extends U> orderBy,
+    public WindowDefinitionImpl(Function<? super T, ?> partitionBy, List<Queryable.Order<? super T, ? extends U>> orderBy,
                                 ValueBound<? extends U, ? extends U> range) {
         this(partitionBy, orderBy, RowBound.DEFAULT, range);
     }
@@ -70,7 +71,7 @@ class WindowDefinitionImpl<T, U extends Comparable<? super U>> implements Window
     }
 
     @Override
-    public Queryable.Order<? super T, ? extends U> orderBy() {
+    public List<Queryable.Order<? super T, ? extends U>> orderBy() {
         return orderBy;
     }
 
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowImpl.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowImpl.java
index 61dad4b..c6a654b 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowImpl.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/WindowImpl.java
@@ -36,14 +36,14 @@ class WindowImpl<T, U extends Comparable<? super U>> extends QueryableCollection
     private final WindowDefinition<T, U> windowDefinition;
 
     WindowImpl(T currentRecord, Queryable<T> partition, WindowDefinition<T, U> windowDefinition) {
-        super(partition.orderBy(windowDefinition.orderBy()).toList());
+        super(partition.orderBy(windowDefinition.orderBy().toArray(Order.EMPTY_ARRAY)).toList());
         this.currentRecord = currentRecord;
         this.windowDefinition = windowDefinition;
 
         List<T> sortedList = this.toList();
-        final Order<? super T, ? extends U> order = windowDefinition.orderBy();
-        if (null != order) {
-            this.value = order.getKeyExtractor().apply(currentRecord);
+        final List<Order<? super T, ? extends U>> order = windowDefinition.orderBy();
+        if (null != order && 1 == order.size()) {
+            this.value = order.get(0).getKeyExtractor().apply(currentRecord);
         } else {
             this.value = null;
         }
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 cfccb5a..83b6d8c 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
@@ -4905,6 +4905,26 @@ class GinqTest {
         '''
     }
 
+    @Test
+    void "testGinq - window - 24"() {
+        assertGinqScript '''
+            assert [['a', 'bc'], ['ab', null], ['b', 'a'], ['bc', 'ab']] == GQ {
+                from s in ['a', 'ab', 'b', 'bc']
+                select s, (lead(s) over(orderby s.length(), s in desc))
+            }.toList()
+        '''
+    }
+
+    @Test
+    void "testGinq - window - 25"() {
+        assertGinqScript '''
+            assert [['a', null], ['ab', null], ['b', 'a'], ['bc', 'ab']] == GQ {
+                from s in ['a', 'ab', 'b', 'bc']
+                select s, (lead(s) over(partitionby s.length() orderby s.length(), s in desc))
+            }.toList()
+        '''
+    }
+
     private static void assertGinqScript(String script) {
         String deoptimizedScript = script.replaceAll(/\bGQ\s*[{]/, 'GQ(optimize:false) {')
         List<String> scriptList = [deoptimizedScript, script]