Re: Ginq enhancement?

Per Nyfelt <[email protected]> Sat, 21 Jun 2025 00:29:13 +0200
Newsgroups gmane.comp.lang.groovy.user
Organization Alipsa HB
Message-ID <[email protected]>
Hi Daniel,

I was obviously not phrasing my question well. Let me give it another go:

Given two list of objects:

import java.time.*

class Employee {
   String mainSsn
   String coSsn
   String firstName
   BigDecimal salary
   LocalDate startDate
}

class Identifier {
   String customerId
   String lei
}


List employees = [
   new Employee(mainSsn: '111', firstName: 'Rick', salary: 623.3, 
startDate: LocalDate.parse('2012-01-01')),
   new Employee(mainSsn: '222', coSsn: '444', firstName: 'Dan', salary: 
515.2, startDate: LocalDate.parse('2013-09-23')),
   new Employee(mainSsn: '555', coSsn: '555', firstName: 'Michelle', 
salary: 611.0, startDate: LocalDate.parse('2014-11-15')),
]

List identifiers = [
   new Identifier(customerId: '2', lei: '111'),
   new Identifier(customerId: '3', lei: '222'),
   new Identifier(customerId: '4', lei: '333'),
   new Identifier(customerId: '5', lei: '444'),
   new Identifier(customerId: '6', lei: '555'),
]

// To add customerId to employees I can do:
def result = GQ {
   from e in employees
   leftjoin mcid in identifiers on e.mainSsn == mcid.lei
   leftjoin cocid in identifiers on e.coSsn == cocid.lei
   select e.mainSsn, e.coSsn, e.firstName, e.salary, e.startDate, 
mcid?.customerId as mainCustomerId, cocid?.customerId as coCustomerId
}

and get this nice output:

+---------+-------+-----------+--------+------------+----------------+--------------+
| mainSsn | coSsn | firstName | salary | startDate  | mainCustomerId | 
coCustomerId |
+---------+-------+-----------+--------+------------+----------------+--------------+
| 111     |       | Rick      | 623.3  | 2012-01-01 | 2              
|              |
| 222     | 444   | Dan       | 515.2  | 2013-09-23 | 3              | 
5            |
| 555     | 555   | Michelle  | 611.0  | 2014-11-15 | 6              | 
6            |
+---------+-------+-----------+--------+------------+----------------+--------------+

// But this is rather tedious and i would want something that is 
equivalent to the .* construct in SQL. I.e:
def result = GQ {
   from e in employees
   leftjoin mcid in identifiers on e.mainSsn == mcid.lei
   leftjoin cocid in identifiers on e.coSsn == cocid.lei
   select e.*, mcid?.customerId as mainCustomerId, cocid?.customerId as 
coCustomerId
}

This does not work but if there was some way to convert e to "whatever 
construct that is needed to make it expand all the properties", lets 
call it expand(). The I could do

def result = GQ {
   from e in employees
   leftjoin mcid in identifiers on e.mainSsn == mcid.lei
   leftjoin cocid in identifiers on e.coSsn == cocid.lei
   select expand(e), mcid?.customerId as mainCustomerId, 
cocid?.customerId as coCustomerId
}

is there (or could there be) a type (class) that expand(e) could return 
so it would give me the same result as when i explicitly specify each field?

Regards,

Per

On 6/20/25 15:47, Daniel Sun wrote:
> Hi Per,
>
> You can find the `leftjoin` usage here: https://github.com/apache/groovy/blob/b046d1b2bcbbddd59ea3d6abdf5de24a671ce51a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy#L763
>
> Cheers,
> Daniel Sun
>
> On 2025/06/17 20:46:35 Per Nyfelt wrote:
>> Hi,
>>
>> I ran into a a ginq "issue" today.
>>
>> I have two list of rows where each key is the column name (actually
>> List<Row> but you can think about it as a List<Map>)  collections that
>> looks like this:
>>
>> employees: 3 obs * 5 variables
>> mainSsn    coSsn    firstName    salary    startDate
>> 111                           Rick               623.3 2012-01-01
>> 222             444       Dan               515.2    2013-09-23
>> 333             555       Michelle       611.0    2014-11-15
>>
>> eln: 5 obs * 2 variables
>> customerId    lei
>>            2             111
>>            3             222
>>            4             333
>>            5             444
>>            6             555
>>
>> I want to join employees with eln and add customerIs columns matching
>> mainSsn and CoSsn. Thinking SQL, I wanted to do something like this
>>
>> def result =GQ {
>>     from tin employees
>>     leftjoin mcidin elnon t.mainSsn == mcid.lei leftjoin cocidin elnon t.coSsn == cocid.lei select t.*, mcid?.customerId as'mainCustomerId', cocid?.customerId as'coCustomerId' }
>>
>> but this is not supported in ginq and I could not find any signs of support for wildcards in the docs.
>>
>> I found that could do this:
>> def result = GQ {
>>     from t in table
>>     leftjoin mcid in ssnCustomerId on t.mainSsn == mcid.lei
>>     leftjoin cocid in ssnCustomerId on t.coSsn == cocid.lei
>>     select t + mcid?.customerId+ cocid?.customerId
>> }
>>
>> Which gives me a List of Lists but then i loose the column names. i.e.
>> merged: 3 obs * 7 variables
>> c1 	c2 	c3      	   c4	c5        	c6	  c7
>> 111	444	Rick    	623.3	2012-01-01	 2	   5
>> 222	   	Dan     	515.2	2013-09-23	 3	null
>> 333	555	Michelle	611.0	2014-11-15	 4	   6
>>
>> Instead i had to do this:
>>
>> def result =GQ {
>>     from tin employees
>>     leftjoin mcidin elnon t.mainSsn == mcid.lei leftjoin cocidin elnon t.coSsn == cocid.lei select t.toMap() + [mainCustomerId: mcid?.customerId] + [coCustomerId: cocid?.customerId]
>> }
>>
>> (This relies on the fact that a matrix Row has a toMap() method)
>>
>> ginq result content:
>> [{mainSsn=111, coSsn=, firstName=Rick, salary=623.3,
>> startDate=2012-01-01, mainCustomerId=2, coCustomerId=null},
>> {mainSsn=222, coSsn=444, firstName=Dan, salary=515.2,
>> startDate=2013-09-23, mainCustomerId=3, coCustomerId=5}, {mainSsn=333,
>> coSsn=555, firstName=Michelle, salary=611.0, startDate=2014-11-15,
>> mainCustomerId=4, coCustomerId=6}]
>>
>> Which is could then easily transform back into a list of rows (actually
>> a matrix but you can think of it as a List<Map>
>>
>> result matrix content:
>> merged: 3 obs * 7 variables
>> mainSsn    coSsn    firstName    salary    startDate mainCustomerId
>> coCustomerId
>> 111                           Rick               623.3
>> 2012-01-01                              2 null
>> 222             444       Dan               515.2
>> 2013-09-23                              3    5
>> 333             555       Michelle       611.0 2014-11-15
>>                  4     6
>>
>> Has there been any discussions about supporting  breaking up the select
>> objects into parts using wildcards and deemed it not feasible to
>> implement or did nobody have this problem before?
>>
>> Something like this could perhaps be an alternative to wildcard syntax:
>>
>> def result =GQ {
>>     from tin employees
>>     leftjoin mcidin elnon t.mainSsn == mcid.lei leftjoin cocidin elnon t.coSsn == cocid.lei select toMap(t) + [mainCustomerId: mcid?.customerId,coCustomerId: cocid?.customerId])
>> }
>>
>> what do you think?
>>
>> Best regards,
>>
>> Per
>>