[ https://issues.apache.org/jira/browse/GROOVY-9159?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Daniel Sun updated GROOVY-9159: ------------------------------- Description: _{color:#d04437}(Note: The exact syntax might be altered before introduction, currently working on the general principle){color}_ GINQ will reuse most of standard SQL syntax, which can make the learning curve smooth and avoid infringing the patent of Microsoft. All GINQ related keywords are uppercase to avoid breaking existing source code as possible as we can, e.g. {{FROM}}, {{WHERE}}, {{SELECT}}, etc. In order to support type inference better, {{SELECT}} clause is placed at the end of GINQ expression. h2. EBNF h3. TBD h2. Examples h3. 1. Filtering {code:java} @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p // p is an alias WHERE p.age > 15 AND p.age <= 35 SELECT p.name assert ['Daniel', 'Alice'] == result result = FROM persons p // p is an alias WHERE p.age > 15 AND p.age <= 35 SELECT p.VALUE assert [new Person(name: 'Daniel', age: 35), new Person(name: 'Alice', age: 22)] == result {code} {code:java} def numbers = [1, 2, 3] def result = FROM numbers t // t is an alias WHERE t.VALUE <= 2 // VALUE is a virtual property SELECT t.VALUE assert [1, 2] == result {code} h3. 2. Joining {code:java} import static groovy.lang.Tuple.* @groovy.transform.EqualsAndHashCode class Person { String name int age City city } @groovy.transform.EqualsAndHashCode class City { String name } def persons = [new Person(name: 'Daniel', age: 35, city: new City('Shanghai')), new Person(name: 'Peter', age: 10, city: new City('Beijing')), new Person(name: 'Alice', age: 22, city: new City('Hangzhou'))] def cities = [new City('Shanghai'), new City('Beijing'), new City('Guangzhou')] // inner join def result = FROM persons p INNER JOIN cities c ON p.city.name = c.name SELECT p.name assert ['Daniel', 'Peter'] == result result = FROM persons p, cities c WHERE p.city.name = c.name SELECT p.name assert ['Daniel', 'Peter'] == result result = FROM persons p, cities c WHERE p.city = c.VALUE SELECT p.name assert ['Daniel', 'Peter'] == result // left outer join result = FROM persons p LEFT JOIN cities c // same to LEFT OUTER JOIN ON p.city.name = c.name SELECT p.name, c.name assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), tuple('Alice', null)] == result // right outer join result = FROM persons p RIGHT JOIN cities c // same to RIGHT OUTER JOIN ON p.city.name = c.name SELECT p.name, c.name assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), tuple(null, 'Guangzhou')] == result {code} h3. 3. Projection {code:java} import static groovy.lang.Tuple.* @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p SELECT p.name assert ['Daniel', 'Peter', 'Alice'] == result result = FROM persons p SELECT p.name, p.age assert [tuple('Daniel', 35), tuple('Peter', 10), tuple('Alice', 22)] == result result = FROM persons p SELECT [name: p.name, age: p.age] assert [ [name: 'Daniel', age: 35], [name: 'Peter', age: 10], [name: 'Alice', age: 22] ] == result result = FROM persons p SELECT new Person(name: p.name, age: p.age) assert persons == result result = FROM persons p SELECT p.VALUE assert persons == result {code} h3. 4. Sorting {code:java} @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p ORDER BY p.age SELECT p.name assert ['Peter', 'Alice', 'Daniel'] == result result = FROM persons p ORDER BY p.age desc SELECT p.name assert ['Daniel', 'Alice', 'Peter'] == result {code} h3. 5. Grouping {code:java} import static groovy.lang.Tuple.* @groovy.transform.EqualsAndHashCode class Person { String name int age String gender } def persons = [new Person(name: 'Daniel', age: 35, gender: 'Male'), new Person(name: 'Peter', age: 10, gender: 'Male'), new Person(name: 'Alice', age: 22, gender: 'Female')] def result = FROM persons p GROUP BY p.gender SELECT p.gender, MAX(p.age) assert [tuple('Male', 35), tuple('Female', 22)] == result {code} was: _{color:#d04437}(Note: The exact syntax might be altered before introduction, currently working on the general principle){color}_ GINQ will reuse most of standard SQL syntax, which can make the learning curve smooth and avoid infringing the patent of Microsoft. All GINQ related keywords are uppercase to avoid breaking existing source code as possible as we can, e.g. {{FROM}}, {{WHERE}}, {{SELECT}}, etc. In order to support type inference better, {{SELECT}} clause is placed at the end of GINQ expression. h2. EBNF h3. TBD h2. Examples h3. 1. Filtering {code:java} @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p // p is an alias WHERE p.age > 15 AND p.age <= 35 SELECT p.name assert ['Daniel', 'Alice'] == result result = FROM persons p // p is an alias WHERE p.age > 15 AND p.age <= 35 SELECT p.VALUE assert [new Person(name: 'Daniel', age: 35), new Person(name: 'Alice', age: 22)] == result {code} {code:java} def numbers = [1, 2, 3] def result = FROM numbers t // t is an alias WHERE t.VALUE <= 2 // VALUE is a virtual property SELECT t.VALUE assert [1, 2] == result {code} h3. 2. Joining {code:java} import static groovy.lang.Tuple.* @groovy.transform.EqualsAndHashCode class Person { String name int age City city } @groovy.transform.EqualsAndHashCode class City { String name } def persons = [new Person(name: 'Daniel', age: 35, city: new City('Shanghai')), new Person(name: 'Peter', age: 10, city: new City('Beijing')), new Person(name: 'Alice', age: 22, city: new City('Hangzhou'))] def cities = [new City('Shanghai'), new City('Beijing'), new City('Guangzhou')] // inner join def result = FROM persons p INNER JOIN cities c ON p.city.name = c.name SELECT p.name assert ['Daniel', 'Peter'] == result result = FROM persons p, cities c WHERE p.city.name = c.name SELECT p.name assert ['Daniel', 'Peter'] == result result = FROM persons p, cities c WHERE p.city = c.VALUE SELECT p.name assert ['Daniel', 'Peter'] == result // left outer join result = FROM persons p LEFT JOIN cities c // same to LEFT OUTER JOIN ON p.city.name = c.name SELECT p.name, c.name assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), tuple('Alice', null)] == result // right outer join result = FROM persons p RIGHT JOIN cities c // same to RIGHT OUTER JOIN ON p.city.name = c.name SELECT p.name, c.name assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), tuple(null, 'Guangzhou')] == result {code} h3. 3. Projection {code:java} import static groovy.lang.Tuple.* @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p SELECT p.name assert ['Daniel', 'Peter', 'Alice'] == result result = FROM persons p SELECT p.name, p.age assert [tuple('Daniel', 35), tuple('Peter', 10), tuple('Alice', 22)] == result result = FROM persons p SELECT [name: p.name, age: p.age] assert [ [name: 'Daniel', age: 35], [name: 'Peter', age: 10], [name: 'Alice', age: 22] ] == result result = FROM persons p SELECT new Person(name: p.name, age: p.age) assert persons == result result = FROM persons p SELECT p.VALUE assert persons == result {code} h3. 4. Sorting {code:java} @groovy.transform.EqualsAndHashCode class Person { String name int age } def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', age: 10), new Person(name: 'Alice', age: 22)] def result = FROM persons p ORDER BY p.age SELECT p.name assert ['Peter', 'Alice', 'Daniel'] == result result = FROM persons p ORDER BY p.age desc SELECT p.name assert ['Daniel', 'Alice', 'Peter'] == result {code} > [GEP] Support LINQ, aka GINQ > ---------------------------- > > Key: GROOVY-9159 > URL: https://issues.apache.org/jira/browse/GROOVY-9159 > Project: Groovy > Issue Type: New Feature > Reporter: Daniel Sun > Priority: Major > Fix For: 4.x > > > _{color:#d04437}(Note: The exact syntax might be altered before introduction, > currently working on the general principle){color}_ > GINQ will reuse most of standard SQL syntax, which can make the learning > curve smooth and avoid infringing the patent of Microsoft. > All GINQ related keywords are uppercase to avoid breaking existing source > code as possible as we can, e.g. {{FROM}}, {{WHERE}}, {{SELECT}}, etc. > In order to support type inference better, {{SELECT}} clause is placed at the > end of GINQ expression. > h2. EBNF > h3. TBD > h2. Examples > h3. 1. Filtering > {code:java} > @groovy.transform.EqualsAndHashCode > class Person { > String name > int age > } > def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', > age: 10), new Person(name: 'Alice', age: 22)] > def result = > FROM persons p // p is an alias > WHERE p.age > 15 AND p.age <= 35 > SELECT p.name > assert ['Daniel', 'Alice'] == result > result = > FROM persons p // p is an alias > WHERE p.age > 15 AND p.age <= 35 > SELECT p.VALUE > assert [new Person(name: 'Daniel', age: 35), new Person(name: 'Alice', age: > 22)] == result > {code} > {code:java} > def numbers = [1, 2, 3] > def result = > FROM numbers t // t is an alias > WHERE t.VALUE <= 2 // VALUE is a virtual property > SELECT t.VALUE > assert [1, 2] == result > {code} > h3. 2. Joining > {code:java} > import static groovy.lang.Tuple.* > @groovy.transform.EqualsAndHashCode > class Person { > String name > int age > City city > } > @groovy.transform.EqualsAndHashCode > class City { > String name > } > def persons = [new Person(name: 'Daniel', age: 35, city: new > City('Shanghai')), new Person(name: 'Peter', age: 10, city: new > City('Beijing')), new Person(name: 'Alice', age: 22, city: new > City('Hangzhou'))] > def cities = [new City('Shanghai'), new City('Beijing'), new > City('Guangzhou')] > // inner join > def result = > FROM persons p INNER JOIN cities c > ON p.city.name = c.name > SELECT p.name > assert ['Daniel', 'Peter'] == result > result = > FROM persons p, cities c > WHERE p.city.name = c.name > SELECT p.name > assert ['Daniel', 'Peter'] == result > result = > FROM persons p, cities c > WHERE p.city = c.VALUE > SELECT p.name > assert ['Daniel', 'Peter'] == result > // left outer join > result = > FROM persons p LEFT JOIN cities c // same to LEFT OUTER JOIN > ON p.city.name = c.name > SELECT p.name, c.name > assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), > tuple('Alice', null)] == result > // right outer join > result = > FROM persons p RIGHT JOIN cities c // same to RIGHT OUTER JOIN > ON p.city.name = c.name > SELECT p.name, c.name > assert [tuple('Daniel', 'Shanghai'), tuple('Peter', 'Beijing'), tuple(null, > 'Guangzhou')] == result > {code} > h3. 3. Projection > {code:java} > import static groovy.lang.Tuple.* > @groovy.transform.EqualsAndHashCode > class Person { > String name > int age > } > def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', > age: 10), new Person(name: 'Alice', age: 22)] > def result = > FROM persons p > SELECT p.name > assert ['Daniel', 'Peter', 'Alice'] == result > result = > FROM persons p > SELECT p.name, p.age > assert [tuple('Daniel', 35), tuple('Peter', 10), tuple('Alice', 22)] == result > result = > FROM persons p > SELECT [name: p.name, age: p.age] > assert [ [name: 'Daniel', age: 35], [name: 'Peter', age: 10], [name: 'Alice', > age: 22] ] == result > result = > FROM persons p > SELECT new Person(name: p.name, age: p.age) > assert persons == result > result = > FROM persons p > SELECT p.VALUE > assert persons == result > {code} > h3. 4. Sorting > {code:java} > @groovy.transform.EqualsAndHashCode > class Person { > String name > int age > } > def persons = [new Person(name: 'Daniel', age: 35), new Person(name: 'Peter', > age: 10), new Person(name: 'Alice', age: 22)] > def result = > FROM persons p > ORDER BY p.age > SELECT p.name > assert ['Peter', 'Alice', 'Daniel'] == result > result = > FROM persons p > ORDER BY p.age desc > SELECT p.name > assert ['Daniel', 'Alice', 'Peter'] == result > {code} > h3. 5. Grouping > {code:java} > import static groovy.lang.Tuple.* > @groovy.transform.EqualsAndHashCode > class Person { > String name > int age > String gender > } > def persons = [new Person(name: 'Daniel', age: 35, gender: 'Male'), new > Person(name: 'Peter', age: 10, gender: 'Male'), new Person(name: 'Alice', > age: 22, gender: 'Female')] > def result = > FROM persons p > GROUP BY p.gender > SELECT p.gender, MAX(p.age) > assert [tuple('Male', 35), tuple('Female', 22)] == result > {code} -- This message was sent by Atlassian JIRA (v7.6.3#76005)