Hi all,
Another use case we have is as follows. We have an expression for the child
entity. For example:
Expression paintingExpression = exp("name like 'G%' or name like 'A%'");
Now, I want to use that to fetch the artists that have paintings that match
that expression. I have to prefix each key with “paitings." in order to use it
to fetch those artists. The expression would then become “paintings.name like
'G%' or paintings.name like 'A%’”.
Is there something in Cayenne already to convert an expression by prefixing
every key path in the expression?
For example, not knowing much about Cayenne, I wrote the following utility
method that seems to do the job:
public static <T> Expression prefix(BaseProperty<T> rel, Expression
subExpression) {
return
subExpression.transform(o -> {
if (o instanceof CayennePath path) {
// e.g. Turn name path into paintings.name
return rel.getPath().dot(path);
}
return o;
});
}
Then I use it as follows:
Expression paintingsExpr = exp("name like 'G%' or name like 'A%'”);
// This returns expression for "paintings.name like 'G%' or paintings.name like
'A%'"
Expression expr = prefix(Artist.PAINTINGS, paintingsExpr);
// Artists with paintings starting with letter G or A
List<Artist> someArtists = ObjectSelect
.query(Artist.class)
.where(expr.exists())
.select(context);
Generates the following SQL (formatted by me for readability):
INFO: --- transaction started.
INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
WHERE EXISTS (
SELECT t1.ID FROM PAINTING t1
WHERE ( t1.NAME LIKE ? OR t1.NAME LIKE ? )
AND ( t1.ARTIST_ID = t0.ID )
)
[bind: 1->NAME:'G%', 2->NAME:'A%']
INFO: === returned 1 row. - took 1 ms.
INFO: +++ transaction committed.
Summary
Am I reinventing the wheel by writing this prefix() utility method? Does
Cayenne have something like that already?
Thank you