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/11/05 00:17:13 UTC
[groovy] branch GROOVY-8258 updated (f555b6c -> 840e09d)
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.
discard f555b6c GROOVY-8258: tweak doco and add sample code
discard bd4d462 GROOVY-8258: eliminate redundant parentheses in the sample code
discard 2b6a7e5 GROOVY-8258: add GINQ tips in the doco
discard 069ceea GROOVY-8258: tweak doco
discard 3c80a91 GROOVY-8258: add more aggregate function examples in the doco
discard f3adf96 GROOVY-8258: add more aggregate function examples in the doco
discard 1c2b070 GROOVY-8258: add more joining examples in the doco
discard 122c152 GROOVY-8258: add a doco for GINQ
new 840e09d GROOVY-8258: trivial tweak and add doco for GINQ
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (f555b6c)
\
N -- N -- N refs/heads/GROOVY-8258 (840e09d)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 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:
.../collection/runtime/QueryableCollection.java | 13 +++++++++++++
.../test/org/apache/groovy/ginq/GinqTest.groovy | 21 +++++++++++++++++++++
2 files changed, 34 insertions(+)
[groovy] 01/01: GROOVY-8258: trivial tweak and add doco for GINQ
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 840e09d7ccbdfb1db7e707962604a138ffc787cb
Author: Daniel Sun <su...@apache.org>
AuthorDate: Thu Nov 5 08:16:53 2020 +0800
GROOVY-8258: trivial tweak and add doco for GINQ
---
subprojects/groovy-binary/src/spec/doc/index.adoc | 2 +
.../collection/runtime/QueryableCollection.java | 13 ++
.../groovy-ginq/src/spec/doc/ginq-userguide.adoc | 225 ++++++++++++++++++
.../test}/org/apache/groovy/ginq/GinqTest.groovy | 254 ++++++++++++++++++++-
4 files changed, 492 insertions(+), 2 deletions(-)
diff --git a/subprojects/groovy-binary/src/spec/doc/index.adoc b/subprojects/groovy-binary/src/spec/doc/index.adoc
index 07e933d..00b756e 100644
--- a/subprojects/groovy-binary/src/spec/doc/index.adoc
+++ b/subprojects/groovy-binary/src/spec/doc/index.adoc
@@ -100,6 +100,8 @@ include::../../../../../subprojects/groovy-json/src/spec/doc/json-userguide.adoc
include::../../../../../subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc[leveloffset=+2]
+include::../../../../../subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc[leveloffset=+2]
+
include::../../../../../subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc[leveloffset=+2]
include::../../../../../subprojects/groovy-yaml/src/spec/doc/yaml-userguide.adoc[leveloffset=+2]
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
index 5110ff8..f2b9f13 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
@@ -324,6 +324,19 @@ class QueryableCollection<T> implements Queryable<T>, Serializable {
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof QueryableCollection)) return false;
+ QueryableCollection<?> that = (QueryableCollection<?>) o;
+ return toList().equals(that.toList());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(toList());
+ }
+
+ @Override
public String toString() {
return AsciiTableMaker.makeAsciiTable(this);
}
diff --git a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
new file mode 100644
index 0000000..5bb79d6
--- /dev/null
+++ b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
@@ -0,0 +1,225 @@
+//////////////////////////////////////////
+
+ 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.
+
+//////////////////////////////////////////
+
+= Interacting with collections in a SQL-like style
+
+Groovy's `groovy-ginq` module provides a higher-level abstraction over collections.
+Also, querying XML, JSON, YAML, etc. could be supported by GINQ too because they can be parsed into collections.
+As GORM and Hibernate are powerful enough to support DB populating, we will cover collections first.
+
+== GINQ a.k.a. Groovy-Integrated Query
+
+GINQ is a DSL for querying, which consists of the following structure:
+```
+ GINQ
+ |__ from
+ |__ [innerjoin/leftjoin/rightjoin/fulljoin/crossjoin]*
+ | |__ on (Note: crossjoin does not need the "on" clause)
+ |__ [where]
+ |__ [groupby]
+ | |__ [having]
+ |__ [orderby]
+ |__ [limit]
+ |__ select
+```
+[NOTE]
+`[]` means the related clause is optional.
+
+As we could see, the simplest GINQ consists of a `from` clause and a `select` clause, which looks like:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_simplest,indent=0]
+----
+
+As a DSL, GINQ should be wrapped with the following block to be executed:
+```groovy
+GQ { /* GINQ CODE */ }
+```
+For example,
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_execution_01,indent=0]
+----
+
+=== GINQ Syntax
+
+==== Projection
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_projection_01,indent=0]
+----
+
+==== Filtering
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_filtering_01,indent=0]
+----
+
+==== Joining
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_joining_01,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_joining_02,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_joining_03,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_joining_04,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_joining_05,indent=0]
+----
+
+==== Grouping
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_01,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_02,indent=0]
+----
+
+`count()` is similar to `count(*)` in SQL:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_07,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_06,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_05,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_04,indent=0]
+----
+
+`_g` is an implicit variable representing the grouped `Queryable` object:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_grouping_03,indent=0]
+----
+
+[NOTE]
+GINQ supports some built-in aggregate functions, e.g.
+`count`, `min`, `max`, `sum` and the most powerful one `agg`
+
+==== Sorting
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_sorting_01,indent=0]
+----
+[NOTE]
+`in asc` is optional when sorting in ascending order
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_sorting_03,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_sorting_02,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_sorting_04,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_sorting_05,indent=0]
+----
+
+==== Pagination
+`limit` is similar to the `limit` clause of MySQL, which could specify the `offset`(first argument) and `size`(second argument) for paginating,
+or just specify the only one argument as `size`
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_pagination_01,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_pagination_02,indent=0]
+----
+
+==== Nested GINQ
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_nested_01,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_nested_02,indent=0]
+----
+
+=== GINQ Tips
+
+==== List Comprehension
+
+List comprehension is an elegant way to define and create lists based on existing lists:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_01,indent=0]
+----
+
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_02,indent=0]
+----
+
+GINQ as list comprehension used in loop directly:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_03,indent=0]
+----
+
+==== Customize GINQ
+
+For advanced users, you could customize GINQ behaviour by specifying your own target code generator.
+For example, we could specify the qualified class name `org.apache.groovy.ginq.provider.collection.GinqAstWalker` as the target code generator to generate GINQ method calls for querying collections,
+which is the default behaviour of GINQ:
+[source, sql]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_customize_01,indent=0]
+----
diff --git a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
similarity index 89%
rename from subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqTest.groovy
rename to subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index f4b2b58..3a9b10c 100644
--- a/subprojects/groovy-ginq/src/test/groovy/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -29,8 +29,10 @@ class GinqTest {
void "testGinq - from select - 0"() {
assertScript '''
assert [0, 1, 2] == GQ {
+// tag::ginq_simplest[]
from n in [0, 1, 2]
select n
+// end::ginq_simplest[]
}.toList()
'''
}
@@ -38,11 +40,13 @@ class GinqTest {
@Test
void "testGinq - from select - 1"() {
assertScript '''
+// tag::ginq_execution_01[]
def numbers = [0, 1, 2]
assert [0, 1, 2] == GQ {
from n in numbers
select n
}.toList()
+// end::ginq_execution_01[]
'''
}
@@ -153,6 +157,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from where select - 3"() {
+ assertScript '''
+ assert [2, 4, 6] == GQ {
+// tag::ginq_filtering_01[]
+ from n in [0, 1, 2, 3, 4, 5]
+ where n > 0 && n <= 3
+ select n * 2
+// end::ginq_filtering_01[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from innerjoin select - 1"() {
assertScript '''
def nums1 = [1, 2, 3]
@@ -357,6 +374,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from innerjoin select - 14"() {
+ assertScript '''
+ assert [[1, 1], [3, 3]] == GQ {
+// tag::ginq_joining_01[]
+ from n1 in [1, 2, 3]
+ innerjoin n2 in [1, 3] on n1 == n2
+ select n1, n2
+// end::ginq_joining_01[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from innerjoin where select - 1"() {
assertScript '''
def nums1 = [1, 2, 3]
@@ -449,11 +479,13 @@ class GinqTest {
void "testGinq - nested from - 0"() {
assertScript '''
assert [1, 2, 3] == GQ {
+// tag::ginq_nested_01[]
from v in (
from n in [1, 2, 3]
select n
)
select v
+// end::ginq_nested_01[]
}.toList()
'''
}
@@ -697,12 +729,14 @@ class GinqTest {
void "testGinq - nested from - 15"() {
assertScript '''
assert [1, 2] == GQ {
+// tag::ginq_nested_02[]
from n in [0, 1, 2]
where n in (
from m in [1, 2]
select m
)
select n
+// end::ginq_nested_02[]
}.toList()
'''
}
@@ -812,8 +846,10 @@ class GinqTest {
assertScript '''
assert [[1, 1], [2, 4], [3, 9]] == GQ {
from v in (
+// tag::ginq_projection_01[]
from n in [1, 2, 3]
select n, Math.pow(n, 2) as powerOfN
+// end::ginq_projection_01[]
)
select v.n, v.powerOfN
}.toList()
@@ -979,6 +1015,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from leftjoin select - 11"() {
+ assertScript '''
+ assert [[1, null], [2, 2], [3, 3]] == GQ {
+// tag::ginq_joining_02[]
+ from n1 in [1, 2, 3]
+ leftjoin n2 in [2, 3, 4] on n1 == n2
+ select n1, n2
+// end::ginq_joining_02[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from leftjoin where select - 1"() {
assertScript '''
def nums1 = [1, 2, 3]
@@ -1123,6 +1172,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from rightjoin select - 11"() {
+ assertScript '''
+ assert [[null, 1], [2, 2], [3, 3]] == GQ {
+// tag::ginq_joining_03[]
+ from n1 in [2, 3, 4]
+ rightjoin n2 in [1, 2, 3] on n1 == n2
+ select n1, n2
+// end::ginq_joining_03[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from rightjoin where select - 1"() {
assertScript '''
def nums2 = [1, 2, 3]
@@ -1150,6 +1212,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from fulljoin select - 2"() {
+ assertScript '''
+ assert [[1, null], [2, 2], [3, 3], [null, 4]] == GQ {
+// tag::ginq_joining_04[]
+ from n1 in [1, 2, 3]
+ fulljoin n2 in [2, 3, 4] on n1 == n2
+ select n1, n2
+// end::ginq_joining_04[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from fulljoin where select - 1"() {
assertScript '''
def nums1 = [1, 2, 3]
@@ -1177,6 +1252,19 @@ class GinqTest {
}
@Test
+ void "testGinq - from crossjoin select - 2"() {
+ assertScript '''
+ assert [[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 3], [3, 4], [3, 5]] == GQ {
+// tag::ginq_joining_05[]
+ from n1 in [1, 2, 3]
+ crossjoin n2 in [3, 4, 5]
+ select n1, n2
+// end::ginq_joining_05[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from crossjoin where select - 1"() {
assertScript '''
def nums1 = [1, 2, 3]
@@ -1194,9 +1282,11 @@ class GinqTest {
void "testGinq - from orderby select - 1"() {
assertScript '''
assert [1, 2, 5, 6] == GQ {
+// tag::ginq_sorting_01[]
from n in [1, 5, 2, 6]
orderby n
select n
+// end::ginq_sorting_01[]
}.toList()
'''
}
@@ -1356,6 +1446,58 @@ class GinqTest {
}
@Test
+ void "testGinq - from orderby select - 10"() {
+ assertScript '''
+ assert [6, 5, 2, 1] == GQ {
+// tag::ginq_sorting_02[]
+ from n in [1, 5, 2, 6]
+ orderby n in desc
+ select n
+// end::ginq_sorting_02[]
+ }.toList()
+ '''
+ }
+
+ @Test
+ void "testGinq - from orderby select - 11"() {
+ assertScript '''
+ assert [1, 2, 5, 6] == GQ {
+// tag::ginq_sorting_03[]
+ from n in [1, 5, 2, 6]
+ orderby n in asc
+ select n
+// end::ginq_sorting_03[]
+ }.toList()
+ '''
+ }
+
+ @Test
+ void "testGinq - from orderby select - 12"() {
+ assertScript '''
+ assert ['cd', 'ef', 'a', 'b'] == GQ {
+// tag::ginq_sorting_04[]
+ from s in ['a', 'b', 'ef', 'cd']
+ orderby s.length() in desc, s in asc
+ select s
+// end::ginq_sorting_04[]
+ }.toList()
+ '''
+ }
+
+ @Test
+ void "testGinq - from orderby select - 13"() {
+ assertScript '''
+ assert ['cd', 'ef', 'a', 'b'] == GQ {
+// tag::ginq_sorting_05[]
+ from s in ['a', 'b', 'ef', 'cd']
+ orderby s.length() in desc, s
+ select s
+// end::ginq_sorting_05[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from innerjoin orderby select - 1"() {
assertScript '''
assert [2, 3] == GQ {
@@ -1395,9 +1537,11 @@ class GinqTest {
void "testGinq - from limit select - 1"() {
assertScript '''
assert [1, 2, 3] == GQ {
+// tag::ginq_pagination_01[]
from n in [1, 2, 3, 4, 5]
limit 3
select n
+// end::ginq_pagination_01[]
}.toList()
'''
}
@@ -1406,9 +1550,11 @@ class GinqTest {
void "testGinq - from limit select - 2"() {
assertScript '''
assert [2, 3, 4] == GQ {
+// tag::ginq_pagination_02[]
from n in [1, 2, 3, 4, 5]
limit 1, 3
select n
+// end::ginq_pagination_02[]
}.toList()
'''
}
@@ -1521,10 +1667,13 @@ class GinqTest {
@Test
void "testGinq - from groupby select - 1"() {
assertScript '''
+ // reference the column `n` in the groupby clause, and `count` is a built-in aggregate function
assert [[1, 2], [3, 2], [6, 3]] == GQ {
+// tag::ginq_grouping_01[]
from n in [1, 1, 3, 3, 6, 6, 6]
groupby n
- select n, count(n) // reference the column `n` in the groupby clause, and `count` is a built-in aggregate function
+ select n, count(n)
+// end::ginq_grouping_01[]
}.toList()
'''
}
@@ -1533,9 +1682,11 @@ class GinqTest {
void "testGinq - from groupby select - 2"() {
assertScript '''
assert [[1, 2], [3, 6], [6, 18]] == GQ {
+// tag::ginq_grouping_04[]
from n in [1, 1, 3, 3, 6, 6, 6]
groupby n
select n, sum(n)
+// end::ginq_grouping_04[]
}.toList()
'''
}
@@ -1643,10 +1794,13 @@ class GinqTest {
@Test
void "testGinq - from groupby select - 7"() {
assertScript '''
+ // `agg` is the most powerful aggregate function, `_g` represents the grouped Queryable object
assert [[1, 2], [3, 6], [6, 18]] == GQ {
+// tag::ginq_grouping_03[]
from n in [1, 1, 3, 3, 6, 6, 6]
groupby n
- select n, agg(_g.stream().map(r -> r.n).reduce(BigDecimal.ZERO, BigDecimal::add)) // the most powerful aggregate function, `_g` represents the grouped Queryable object
+ select n, agg(_g.stream().map(r -> r.n).reduce(BigDecimal.ZERO, BigDecimal::add))
+// end::ginq_grouping_03[]
}.toList()
'''
}
@@ -1723,6 +1877,46 @@ class GinqTest {
}
@Test
+ void "testGinq - from groupby select - 12"() {
+ assertScript '''
+ assert [[1, 'b'], [2, 'ef']] == GQ {
+// tag::ginq_grouping_05[]
+ from s in ['a', 'b', 'cd', 'ef']
+ groupby s.size() as length
+ select length, max(s)
+// end::ginq_grouping_05[]
+ }.toList()
+ '''
+ }
+
+ @Test
+ void "testGinq - from groupby select - 13"() {
+ assertScript '''
+ assert [[1, 'a'], [2, 'cd']] == GQ {
+// tag::ginq_grouping_06[]
+ from s in ['a', 'b', 'cd', 'ef']
+ groupby s.size() as length
+ select length, min(s)
+// end::ginq_grouping_06[]
+ }.toList()
+ '''
+ }
+
+ @Test
+ void "testGinq - from groupby select - 14"() {
+ assertScript '''
+ // reference the column `n` in the groupby clause, and `count` is a built-in aggregate function
+ assert [[1, 2], [3, 2], [6, 3]] == GQ {
+// tag::ginq_grouping_07[]
+ from n in [1, 1, 3, 3, 6, 6, 6]
+ groupby n
+ select n, count()
+// end::ginq_grouping_07[]
+ }.toList()
+ '''
+ }
+
+ @Test
void "testGinq - from where groupby select - 1"() {
assertScript '''
assert [[1, 2], [6, 3]] == GQ {
@@ -1807,10 +2001,12 @@ class GinqTest {
void "testGinq - from groupby having select - 1"() {
assertScript '''
assert [[3, 2], [6, 3]] == GQ {
+// tag::ginq_grouping_02[]
from n in [1, 1, 3, 3, 6, 6, 6]
groupby n
having n >= 3
select n, count(n)
+// end::ginq_grouping_02[]
}.toList()
'''
}
@@ -1949,10 +2145,64 @@ class GinqTest {
@Test
void "testGinq - customize GINQ target - 0"() {
assertScript '''
+// tag::ginq_customize_01[]
assert [0, 1, 2] == GQ('org.apache.groovy.ginq.provider.collection.GinqAstWalker') {
from n in [0, 1, 2]
select n
}.toList()
+// end::ginq_customize_01[]
+ '''
+ }
+
+ @Test
+ void "testGinq - GINQ tips - 0"() {
+ assertScript '''
+// tag::ginq_tips_01[]
+ assert [4, 16, 36, 64, 100] == GQ {from n in 1..<11 where n % 2 == 0 select n ** 2}.toList()
+// end::ginq_tips_01[]
+ '''
+ }
+
+ @Test
+ void "testGinq - GINQ tips - 1"() {
+ assertScript '''
+// tag::ginq_tips_02[]
+ assert [4, 16, 36, 64, 100] == GQ {from n in 1..<11 where n % 2 == 0 select n ** 2} as List
+// end::ginq_tips_02[]
+ '''
+ }
+
+ @Test
+ void "testGinq - GINQ tips - 2"() {
+ assertScript '''
+// tag::ginq_tips_03[]
+ def result = []
+ for (def x : GQ {from n in 1..<11 where n % 2 == 0 select n ** 2}) {
+ result << x
+ }
+ assert [4, 16, 36, 64, 100] == result
+// end::ginq_tips_03[]
+ '''
+ }
+
+ @Test
+ void "testGinq - GINQ equals - 2"() {
+ assertScript '''
+ def q1 = GQ {from n in [1, 2, 3] select n}
+ def q2 = GQ {from n in [1, 2, 3] select n}
+ assert q1 == q2
+ '''
+ }
+
+ @Test
+ void "testGinq - GINQ equals and hashCode - 2"() {
+ assertScript '''
+ def set = new HashSet()
+ def q1 = GQ {from n in [1, 2, 3] select n}
+ def q2 = GQ {from n in [1, 2, 3] select n}
+ set.add(q1)
+ set.add(q2)
+ assert 1 == set.size()
'''
}
}