You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by GitBox <gi...@apache.org> on 2020/10/04 16:01:43 UTC

[GitHub] [groovy] danielsun1106 opened a new pull request #1395: [GEP] Create a LINQ-like DSL

danielsun1106 opened a new pull request #1395:
URL: https://github.com/apache/groovy/pull/1395


   https://issues.apache.org/jira/browse/GROOVY-8258


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] paulk-asert commented on pull request #1395: GROOVY-8258: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
paulk-asert commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-722662316


   Merged! Thanks for a great contribution.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] muse-dev[bot] commented on a change in pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
muse-dev[bot] commented on a change in pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#discussion_r499265164



##########
File path: 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) -> {

Review comment:
       *JdkObsolete:*  It is very rare for LinkedList to out-perform ArrayList or ArrayDeque. Avoid it unless you're willing to invest a lot of time into benchmarking. Caveat: LinkedList supports null elements, but ArrayDeque does not.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] danielsun1106 commented on pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
danielsun1106 commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-703318665


   I believe most of us are familiar with SQL-like language, so it's good to reuse the knowledge to deal with collection for higher productivity and better readability. As you found, GORM and Hibernate are powerful enough to deal with DB population, so currently groovy-linq is just target to collection. Parsing XML, JSON and YAML could use groovy-linq too because they can be parsed into collections.
   
   > Is this something that could start life as an external project?
   
   No worries, the PR will not be merged util review passed. BTW, groovy-linq may be a new module of Groovy 4.0( http://groovy-lang.org/releasenotes/groovy-4.0.html ) /cc @paulk-asert 
   
   
   > Is LINQ a trademark of Microsoft's? In any case, for searchability, I would suggest consideration of another name.
   
   Any suggestion for the better name? GINQ?
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] asfgit closed pull request #1395: GROOVY-8258: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
asfgit closed pull request #1395:
URL: https://github.com/apache/groovy/pull/1395


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] danielsun1106 commented on pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
danielsun1106 commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-704506406


   > Is there any reason this new feature could not be part of the groovy-sql module under the org.apache.groovy.sql.dsl package? Then whatever marketing name you choose would not impact the packaging and its association with SQL would be clear.
   
   Good idea. but I am a bit afraid that `groovy-sql` module name will make users misunderstand GINQ supports populating DB too, actually I am going to only support populating collections(XML, JSON, YAML could be parsed into collections) at the beginning because GORM and hibernate are powerful enough as you found and supporting DB is too heavy for a languange.
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] danielsun1106 commented on pull request #1395: GROOVY-8258: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
danielsun1106 commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-721085666


   @paulk-asert Thanks a lot for your reviewing. I've tweaked the PR as you suggested.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] eric-milles edited a comment on pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
eric-milles edited a comment on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-703312353


   Is this something that could start life as an external project?  What is the case for beginning as part of the language/runtime offerings from the start?  I'm sorry, I can't reach the JIRA ticket for a look -- what is the significant advantage over something like GORM or Hibernate or similar mature technologies?
   
   Is LINQ a trademark of Microsoft's?  In any case, for searchability, I would suggest consideration of another name.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] eric-milles commented on pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
eric-milles commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-703312353


   Is this something that could start life as an external project?  What is the case for beginning as part of the language/runtime offerings from the start?  I'm sorry, I can't reach the JIRA ticket for a look -- what is the significant advantage over something like Hibernate or similar mature technologies?
   
   Is LINQ a trademark of Microsoft's?  In any case, for searchability, I would suggest consideration of another name.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [groovy] eric-milles commented on pull request #1395: [GEP] Create a LINQ-like DSL

Posted by GitBox <gi...@apache.org>.
eric-milles commented on pull request #1395:
URL: https://github.com/apache/groovy/pull/1395#issuecomment-704496749


   Is there any reason this new feature could not be part of the `groovy-sql` module under the `org.apache.groovy.sql.dsl` package?  Then whatever marketing name you choose would not impact the packaging and its association with SQL would be clear.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org