From 8a4024ecfcdb95f51221f4dbd30fdd4ac375ea92 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 19 Aug 2023 13:54:38 +1200 Subject: [PATCH] FIX for filterMany with raw expression with single SQL query Fix for the case where the filterMany is not executed on a separate query but instead part of the origin query. The fix is to use the appropriate DeployParser and also fix the path alias like ${} -> ${contacts} --- .../server/query/CQueryPredicates.java | 22 ++++++++++++++-- .../server/query/CQueryPredicatesTest.java | 26 +++++++++++++++++++ .../org/tests/query/TestQueryFilterMany.java | 18 +++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 ebean-core/src/test/java/io/ebeaninternal/server/query/CQueryPredicatesTest.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java index 78b54d56d..99ab30224 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java @@ -10,6 +10,7 @@ import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.DeployParser; +import io.ebeaninternal.server.deploy.DeployPropertyParser; import io.ebeaninternal.server.expression.DefaultExpressionRequest; import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.querydefn.OrmQueryProperties; @@ -198,9 +199,10 @@ public final class CQueryPredicates { OrmQueryProperties chunk = query.detail().getChunk(manyProperty.name(), false); SpiExpressionList filterManyExpr = chunk.getFilterMany(); if (filterManyExpr != null) { - this.filterMany = new DefaultExpressionRequest(request, deployParser, binder, filterManyExpr); + DeployPropertyParser parser = manyProperty.targetDescriptor().parser(); + this.filterMany = new DefaultExpressionRequest(request, parser, binder, filterManyExpr); if (buildSql) { - dbFilterMany = filterMany.buildSql(); + dbFilterMany = filterManyPaths(manyProperty.name(), filterMany.buildSql()); } } } @@ -216,6 +218,22 @@ public final class CQueryPredicates { } } + static String filterManyPaths(String prefix, String raw) { + final StringBuilder sb = new StringBuilder(raw.length() + 50); + int lastPos = 0; + int nextPos = raw.indexOf("${"); + while (nextPos > -1) { + sb.append(raw.substring(lastPos, nextPos)).append("${").append(prefix); + if (raw.charAt(nextPos + 2) != '}') { + sb.append('.'); + } + lastPos = nextPos + 2; + nextPos = raw.indexOf("${", nextPos + 2); + } + sb.append(raw.substring(lastPos)); + return sb.toString(); + } + /** * Replace the table alias place-holders. */ diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/query/CQueryPredicatesTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/query/CQueryPredicatesTest.java new file mode 100644 index 000000000..5a355b933 --- /dev/null +++ b/ebean-core/src/test/java/io/ebeaninternal/server/query/CQueryPredicatesTest.java @@ -0,0 +1,26 @@ +package io.ebeaninternal.server.query; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CQueryPredicatesTest { + + @Test + void filterManyPaths_one() { + String result = CQueryPredicates.filterManyPaths("contacts", "${}first is not null"); + assertThat(result).isEqualTo("${contacts}first is not null"); + } + + @Test + void filterManyPaths_nested() { + String result = CQueryPredicates.filterManyPaths("contacts", "${address}city"); + assertThat(result).isEqualTo("${contacts.address}city"); + } + + @Test + void filterManyPaths_2() { + String result = CQueryPredicates.filterManyPaths("contacts", "${}first ${}last"); + assertThat(result).isEqualTo("${contacts}first ${contacts}last"); + } +} diff --git a/ebean-test/src/test/java/org/tests/query/TestQueryFilterMany.java b/ebean-test/src/test/java/org/tests/query/TestQueryFilterMany.java index 0ebf2bdc6..dffe3a72e 100644 --- a/ebean-test/src/test/java/org/tests/query/TestQueryFilterMany.java +++ b/ebean-test/src/test/java/org/tests/query/TestQueryFilterMany.java @@ -152,6 +152,24 @@ public class TestQueryFilterMany extends BaseTestCase { assertThat(sql.get(1)).contains("from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where"); } + @Test + public void test_with_findOne_rawSameQuery() { + ResetBasicData.reset(); + + LoggedSql.start(); + var result = DB.find(Customer.class) + .order().asc("id") + .fetch("orders") + .filterMany("orders").raw("orderDate is not null") + .findList(); + + assertThat(result).isNotEmpty(); + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("from o_customer t0 left join o_order t1"); + assertThat(sql.get(0)).contains("where t1.order_date is not null"); + } + @Test public void test_with_findOneOrEmpty() {