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}
This commit is contained in:
Rob Bygrave
2023-08-19 13:54:38 +12:00
parent 9756c9133e
commit 8a4024ecfc
3 changed files with 64 additions and 2 deletions
@@ -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.
*/
@@ -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");
}
}
@@ -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<String> 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() {