Converting child expression to be used on parent entity

Ricardo Parada <[email protected]> Sun, 28 Sep 2025 13:52:37 -0400
Newsgroups gmane.comp.java.cayenne.user
Message-ID <[email protected]>
--Apple-Mail=_B4CC9112-4740-4A1A-9788-BAA1A4F6976A
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=utf-8

Hi all,

Another use case we have is as follows.  We have an expression for the =
child entity.  For example:

Expression paintingExpression =3D 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 =E2=80=9Cpaitings."=
 in order to use it to fetch those artists.  The expression would then =
become =E2=80=9Cpaintings.name like 'G%' or paintings.name like =
'A%=E2=80=99=E2=80=9D.

Is there something in Cayenne already to convert an expression by =
prefixing every key path in the expression? =20

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 =3D exp("name like 'G%' or name like 'A%'=E2=80=9D=
);

// This returns expression for "paintings.name like 'G%' or =
paintings.name like 'A%'"
Expression expr =3D prefix(Artist.PAINTINGS, paintingsExpr);

// Artists with paintings starting with letter G or A
List<Artist> someArtists =3D 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=20
      WHERE EXISTS (
          SELECT t1.ID FROM PAINTING t1=20
          WHERE ( t1.NAME LIKE ? OR t1.NAME LIKE ? )=20
          AND ( t1.ARTIST_ID =3D t0.ID )
      )=20
      [bind: 1->NAME:'G%', 2->NAME:'A%']
INFO: =3D=3D=3D 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



--Apple-Mail=_B4CC9112-4740-4A1A-9788-BAA1A4F6976A--