Hi Daniel,
I tried to expand the Employee object into a
org.apache.groovy.ginq.provider.collection.runtime.NamedRecord
NamedRecord expand(Object e) {
new NamedRecord(
[e.mainSsn, e.coSsn, e.firstName, e.salary, e.startDate],
['mainSsn', 'coSsn', 'firstName', 'salary', 'startDate']
)
}
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
}
But in the result, the named record is treated just as the original
object i.e:
+-----------------------------------------+----------------+--------------+
| this.expand(e) | mainCustomerId | coCustomerId |
+-----------------------------------------+----------------+--------------+
| [111, null, 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 |
+-----------------------------------------+----------------+--------------+
is there a way to convert the object into something with metadata that
ginq would accept just as it would an attribute?
Regards,
Per
On 6/21/25 16:43, Daniel Sun wrote:
Hi Per,
GINQ is based on object, but SQL is based on table. We can get metadata
for table via database at compile time, but it's hard to get metadata for
object by a dynamic language at compile time.
Why do we need metadata? Because we use the metadata to process semantic
analysis and construct `NamedRecord` which requires the names.
As for `e.*`, `e` actually represents the wrapped result of `e.*`, for
example,
```
GQ {
from e in employees
leftjoin mcid in identifiers on e.mainSsn == mcid.lei
select e, mcid // the wrapped result for e.*, mcid.*
}
```
BTW, I tried to find the `e.*` usage in LINQ of C#, it is not supported
either.
Cheers,
Daniel Sun
On 2025/06/20 22:29:13 Per Nyfelt wrote:
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