diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpression.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpression.java
index cad22c50a..007e9f29f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpression.java
@@ -105,4 +105,9 @@ public interface SpiExpression extends Expression {
* Check for match to a natural key query returning false if it doesn't match.
*/
boolean naturalKey(NaturalKeyQueryData> data);
+
+ /**
+ * Apply property prefix when filterMany expressions included into main query.
+ */
+ void prefixProperty(String path);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionList.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionList.java
index 3cf5c2e64..c4764b30f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionList.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionList.java
@@ -43,4 +43,9 @@ public interface SpiExpressionList extends ExpressionList, SpiExpression {
default void applyRowLimits(SpiQuery> query) {
// do nothing by default
}
+
+ /**
+ * Apply property prefix when filterMany expressions included in main query.
+ */
+ void prefixProperty(String path);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java
index 3ec5deac7..5548c88e3 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java
@@ -219,10 +219,10 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery
*/
@Override
public void prepareQuery() {
+ secondaryQueries = query.convertJoins();
beanDescriptor.prepareQuery(query);
adapterPreQuery();
- this.secondaryQueries = query.convertJoins();
- this.queryPlanKey = query.prepare(this);
+ queryPlanKey = query.prepare(this);
}
public boolean isNativeSql() {
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java
index 0ae5cd6fc..c3090e38f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java
@@ -16,12 +16,17 @@ import io.ebeaninternal.api.NaturalKeyQueryData;
*/
public abstract class AbstractExpression implements SpiExpression {
- protected final String propName;
+ protected String propName;
protected AbstractExpression(String propName) {
this.propName = propName;
}
+ @Override
+ public void prefixProperty(String path) {
+ this.propName = path + "." + propName;
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// by default can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java
index 798908335..a50ec888f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java
@@ -17,8 +17,8 @@ class BetweenPropertyExpression extends NonPrepareExpression {
private static final String BETWEEN = " between ";
- private final String lowProperty;
- private final String highProperty;
+ private String lowProperty;
+ private String highProperty;
private final Object value;
BetweenPropertyExpression(String lowProperty, String highProperty, Object value) {
@@ -27,6 +27,12 @@ class BetweenPropertyExpression extends NonPrepareExpression {
this.value = value;
}
+ @Override
+ public void prefixProperty(String path) {
+ this.lowProperty = path + "." + lowProperty;
+ this.highProperty = path + "." + highProperty;
+ }
+
protected String name(String propName) {
return propName;
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExampleExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExampleExpression.java
index c6fa5d087..aade99f5a 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExampleExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExampleExpression.java
@@ -88,6 +88,13 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
}
}
+ @Override
+ public void prefixProperty(String path) {
+ for (SpiExpression exp : list) {
+ exp.prefixProperty(path);
+ }
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
index c034b2992..ab80ae9e5 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
@@ -126,6 +126,13 @@ public class DefaultExpressionList implements SpiExpressionList {
}
}
+ @Override
+ public void prefixProperty(String path) {
+ for (SpiExpression exp : list) {
+ exp.prefixProperty(path);
+ }
+ }
+
@Override
public Junction toJunction() {
return new JunctionExpression<>(Junction.Type.FILTER, this);
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java
index 8918bd05d..32ae2bccc 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java
@@ -36,6 +36,11 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
this.subQuery = null;
}
+ @Override
+ public void prefixProperty(String path) {
+ // do nothing
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java
index 12910fb37..b5280b868 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java
@@ -19,6 +19,11 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
this.value = value;
}
+ @Override
+ public void prefixProperty(String path) {
+ throw new IllegalStateException("Not allowed?");
+ }
+
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeId(value);
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
index f048f1163..0aae30886 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
@@ -66,6 +66,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
this.exprList = exprList;
}
+ @Override
+ public void prefixProperty(String path) {
+ exprList.prefixProperty(path);
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LogicExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LogicExpression.java
index 0fa0d9b37..482aac6e8 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LogicExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LogicExpression.java
@@ -57,6 +57,12 @@ abstract class LogicExpression implements SpiExpression {
this.expTwo = (SpiExpression) expTwo;
}
+ @Override
+ public void prefixProperty(String path) {
+ expOne.prefixProperty(path);
+ expTwo.prefixProperty(path);
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NestedPathWrapperExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NestedPathWrapperExpression.java
index c7f5d193e..77f46828b 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NestedPathWrapperExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NestedPathWrapperExpression.java
@@ -24,6 +24,11 @@ class NestedPathWrapperExpression implements SpiExpression {
this.delegate = delegate;
}
+ @Override
+ public void prefixProperty(String path) {
+ // do nothing
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NonPrepareExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NonPrepareExpression.java
index 675e641ee..e384bbd1e 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NonPrepareExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NonPrepareExpression.java
@@ -9,6 +9,11 @@ import io.ebeaninternal.api.NaturalKeyQueryData;
*/
abstract class NonPrepareExpression implements SpiExpression {
+ @Override
+ public void prefixProperty(String path) {
+ // do nothing
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NoopExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NoopExpression.java
index c95c8585b..28c9e3c78 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NoopExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NoopExpression.java
@@ -17,6 +17,11 @@ class NoopExpression implements SpiExpression {
protected static final NoopExpression INSTANCE = new NoopExpression();
+ @Override
+ public void prefixProperty(String path) {
+ // do nothing
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NotExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NotExpression.java
index 29535cd95..60ade47b0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NotExpression.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NotExpression.java
@@ -22,6 +22,11 @@ final class NotExpression implements SpiExpression {
this.exp = (SpiExpression) exp;
}
+ @Override
+ public void prefixProperty(String path) {
+ exp.prefixProperty(path);
+ }
+
@Override
public boolean naturalKey(NaturalKeyQueryData> data) {
// can't use naturalKey cache
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
index 867e16dfa..71fe9ff68 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -1238,6 +1238,7 @@ public class DefaultOrmQuery implements SpiQuery {
* Prepare the expressions (compile sub-queries etc).
*/
private void prepareExpressions(BeanQueryRequest> request) {
+ detail.prepareExpressions(request);
if (whereExpressions != null) {
whereExpressions.prepareExpression(request);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
index 6f96fbbea..6646746eb 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchConfig;
+import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
@@ -9,25 +10,16 @@ import io.ebeaninternal.server.el.ElPropertyValue;
import javax.persistence.PersistenceException;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
/**
* Represents the internal structure of an Object Relational query.
*
* Holds the select() and join() details of a ORM query.
- *
*
* It is worth noting that for AutoTune a "tuned fetch info" builds an instance of OrmQueryDetail.
* Tuning a query is a matter of replacing an instance of this class with one that has been tuned
* with select() and join() set.
- *
*/
public class OrmQueryDetail implements Serializable {
@@ -81,7 +73,6 @@ public class OrmQueryDetail implements Serializable {
* Return true if equal in terms of autoTune (select and fetch without property ordering).
*/
public boolean isAutoTuneEqual(OrmQueryDetail otherDetail) {
-
if (!isSameByAutoTune(baseProps, otherDetail.baseProps)) {
return false;
}
@@ -175,9 +166,7 @@ public class OrmQueryDetail implements Serializable {
}
private List removeSecondaryQueries(boolean lazyQuery) {
-
ArrayList matchingPaths = new ArrayList<>(2);
-
for (OrmQueryProperties chunk : fetchPaths.values()) {
boolean match = lazyQuery ? chunk.isLazyFetch() : chunk.isQueryFetch();
if (match) {
@@ -191,7 +180,6 @@ public class OrmQueryDetail implements Serializable {
// sort into depth order to remove
Collections.sort(matchingPaths);
-
// the list of secondary queries
ArrayList props = new ArrayList<>();
@@ -225,14 +213,11 @@ public class OrmQueryDetail implements Serializable {
OrmQueryProperties chunk = getChunk(split[0], true);
chunk.addSecondaryQueryJoin(split[1]);
}
-
return props;
}
boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
-
boolean tuned = false;
-
OrmQueryProperties tunedRoot = tunedDetail.getChunk(null, false);
if (tunedRoot != null) {
tuned = true;
@@ -257,10 +242,7 @@ public class OrmQueryDetail implements Serializable {
}
/**
- * Remove all joins and properties.
- *
- * Typically for the row count query.
- *
+ * Remove all joins and properties. Typically for the row count query.
*/
public void clear() {
fetchPaths.clear();
@@ -306,7 +288,6 @@ public class OrmQueryDetail implements Serializable {
}
private void sortFetchPaths(BeanDescriptor> d, boolean addIds) {
-
if (!fetchPaths.isEmpty()) {
LinkedHashMap sorted = new LinkedHashMap<>();
for (OrmQueryProperties p : fetchPaths.values()) {
@@ -317,7 +298,6 @@ public class OrmQueryDetail implements Serializable {
}
private void sortFetchPaths(BeanDescriptor> d, OrmQueryProperties p, LinkedHashMap sorted, boolean addId) {
-
String path = p.getPath();
if (!sorted.containsKey(path)) {
String parentPath = p.getParentPath();
@@ -339,7 +319,6 @@ public class OrmQueryDetail implements Serializable {
parentProp = new OrmQueryProperties(parentPath, Collections.emptySet());
}
}
-
sortFetchPaths(d, parentProp, sorted, addId);
sorted.put(path, p);
}
@@ -350,14 +329,12 @@ public class OrmQueryDetail implements Serializable {
* Mark 'fetch joins' to 'many' properties over to 'query joins' where needed.
*/
void markQueryJoins(BeanDescriptor> beanDescriptor, String lazyLoadManyPath, boolean allowOne, boolean addIds) {
-
if (fetchPaths.isEmpty()) {
return;
}
// the name of the many fetch property if there is one
String manyFetchProperty = null;
-
// flag that is set once the many fetch property is chosen
boolean fetchJoinFirstMany = allowOne;
@@ -375,6 +352,7 @@ public class OrmQueryDetail implements Serializable {
// letting the first one remain a 'fetch join'
fetchJoinFirstMany = false;
manyFetchProperty = pair.getPath();
+ chunk.filterManyInline();
} else {
// convert this one over to a 'query join'
chunk.markForQueryJoin();
@@ -388,7 +366,6 @@ public class OrmQueryDetail implements Serializable {
* Sort the fetch entries taking into account fetchPreference on the path.
*/
private List sortByFetchPreference(BeanDescriptor> desc) {
-
List entries = new ArrayList<>(fetchPaths.size());
int idx = 0;
for (Map.Entry entry : fetchPaths.entrySet()) {
@@ -452,11 +429,9 @@ public class OrmQueryDetail implements Serializable {
*
*/
public void setDefaultSelectClause(BeanDescriptor> desc) {
-
if (desc.hasDefaultSelectClause() && !hasSelectClause()) {
baseProps = new OrmQueryProperties(null, desc.getDefaultSelectClause());
}
-
for (OrmQueryProperties joinProps : fetchPaths.values()) {
if (!joinProps.hasSelectClause()) {
BeanDescriptor> assocDesc = desc.getBeanDescriptor(joinProps.getPath());
@@ -506,7 +481,6 @@ public class OrmQueryDetail implements Serializable {
props = new OrmQueryProperties(path);
fetch(props);
return props;
-
} else {
return props;
}
@@ -516,9 +490,7 @@ public class OrmQueryDetail implements Serializable {
* Return true if the fetch path is included.
*/
public boolean includesPath(String path) {
-
OrmQueryProperties chunk = fetchPaths.get(path);
-
// may not have fetch properties if just +cache etc
return chunk != null && !chunk.isCache();
}
@@ -537,6 +509,15 @@ public class OrmQueryDetail implements Serializable {
return fetchPaths.entrySet();
}
+ /**
+ * Prepare filterMany expressions that are being included into the main query.
+ */
+ public void prepareExpressions(BeanQueryRequest> request) {
+ for (OrmQueryProperties value : fetchPaths.values()) {
+ value.prepareExpressions(request);
+ }
+ }
+
private static class FetchEntry implements Comparable {
private final int index;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java
index 466bb3eb9..0a8b51465 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java
@@ -4,6 +4,7 @@ import io.ebean.ExpressionFactory;
import io.ebean.FetchConfig;
import io.ebean.OrderBy;
import io.ebean.Query;
+import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionFactory;
@@ -178,8 +179,6 @@ public class OrmQueryProperties implements Serializable {
SpiExpressionFactory queryEf = (SpiExpressionFactory) rootQuery.getExpressionFactory();
ExpressionFactory filterEf = queryEf.createExpressionFactory();// exprPath);
filterMany = new FilterExpressionList(exprPath, filterEf, rootQuery);
- // by default we need to make this a 'query join' now
- markForQueryJoin = true;
}
return filterMany;
}
@@ -194,6 +193,24 @@ public class OrmQueryProperties implements Serializable {
return filterMany.trimPath(trimPath);
}
+ /**
+ * Adjust filterMany expressions for inclusion in main query.
+ */
+ public void filterManyInline() {
+ if (filterMany != null){
+ filterMany.prefixProperty(path);
+ }
+ }
+
+ /**
+ * Prepare filterMany expressions for query plan key.
+ */
+ public void prepareExpressions(BeanQueryRequest> request) {
+ if (filterMany != null) {
+ filterMany.prepareExpression(request);
+ }
+ }
+
/**
* Return the filterMany expression list (can be null).
*/
@@ -206,7 +223,6 @@ public class OrmQueryProperties implements Serializable {
*/
public void setFilterMany(SpiExpressionList> filterMany) {
this.filterMany = filterMany;
- this.markForQueryJoin = true;
}
/**
diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java
index 12c731115..1a5484f16 100644
--- a/ebean-core/src/test/java/io/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java
+++ b/ebean-core/src/test/java/io/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java
@@ -288,7 +288,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
}
@Test
- public void test_removeJoinToMany_when_filterMany() {
+ public void test_filterMany_included() {
Query query = Ebean.find(Order.class)
.fetch("details")
@@ -301,6 +301,40 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
OrmQueryRequest queryRequest = queryRequest(query);
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
+ assertThat(detail.getFetchPaths()).containsExactly("details", "details.product", "customer");
+ }
+
+ @Test
+ public void test_filterMany_excludedByOrdering() {
+
+ Query query = Ebean.find(Order.class)
+ .fetch("customer")
+ .fetch("customer.contacts")
+ .fetch("details")
+ .fetch("details.product")
+ .filterMany("details").eq("orderQuantity", 10)
+ .query();
+
+ OrmQueryRequest queryRequest = queryRequest(query);
+ OrmQueryDetail detail = queryRequest.getQuery().getDetail();
+
+ assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
+ }
+
+ @Test
+ public void test_filterMany_excludedExplicitly() {
+
+ Query query = Ebean.find(Order.class)
+ .fetchQuery("details")
+ .fetch("details.product")
+ .fetch("customer")
+ .fetch("customer.contacts")
+ .filterMany("details").eq("orderQuantity", 10)
+ .query();
+
+ OrmQueryRequest queryRequest = queryRequest(query);
+ OrmQueryDetail detail = queryRequest.getQuery().getDetail();
+
assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
}
diff --git a/ebean-core/src/test/java/org/tests/query/TestQueryFilterMany.java b/ebean-core/src/test/java/org/tests/query/TestQueryFilterMany.java
index 976dac580..be58fb8c4 100644
--- a/ebean-core/src/test/java/org/tests/query/TestQueryFilterMany.java
+++ b/ebean-core/src/test/java/org/tests/query/TestQueryFilterMany.java
@@ -172,7 +172,6 @@ public class TestQueryFilterMany extends BaseTestCase {
LoggedSqlCollector.start();
Query query = Ebean.find(Customer.class)
- .fetch("orders")
.filterMany("orders").raw("1=0")
.where().isNotEmpty("orders")
.query();
@@ -183,12 +182,10 @@ public class TestQueryFilterMany extends BaseTestCase {
}
List sqlList = LoggedSqlCollector.stop();
- assertEquals(2, sqlList.size());
- assertThat(sqlList.get(0)).contains("where exists (select 1 from o_order x where x.kcustomer_id = t0.id)");
- assertThat(sqlList.get(1)).contains("and 1=0");
+ assertEquals(1, sqlList.size());
+ assertThat(sqlList.get(0)).contains("from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where exists (select 1 from o_order x where x.kcustomer_id = t0.id) and 1=0 order by t0.id");
}
-
@Test
public void test_filterMany_in_findCount() {
@@ -212,7 +209,6 @@ public class TestQueryFilterMany extends BaseTestCase {
public void test_filterMany_copy_findList() {
ResetBasicData.reset();
-
LoggedSqlCollector.start();
Query query = Ebean.find(Customer.class)
@@ -222,17 +218,35 @@ public class TestQueryFilterMany extends BaseTestCase {
query.copy().findList();
+ List sqlList = LoggedSqlCollector.stop();
+ assertEquals(1, sqlList.size());
+ assertThat(sqlList.get(0)).contains("from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where t1.status in (?) order by t0.id");
+ }
+
+ @Test
+ public void test_filterMany_fetchQuery() {
+
+ ResetBasicData.reset();
+ LoggedSqlCollector.start();
+
+ Query query = Ebean.find(Customer.class)
+ .fetchQuery("orders") // explicitly fetch orders separately
+ .filterMany("orders").in("status", Order.Status.NEW)
+ .order().asc("id");
+
+ query.findList();
+
List sqlList = LoggedSqlCollector.stop();
assertEquals(2, sqlList.size());
assertThat(sqlList.get(0)).contains("from o_customer t0");
- assertThat(sqlList.get(1)).contains("from o_order t0 join o_customer t1");
+ assertThat(sqlList.get(1)).contains("from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where t0.order_date is not null and (t0.kcustomer_id) in ");
+ assertThat(sqlList.get(1)).contains(" and t0.status in ");
}
@Test
public void testDisjunction() {
ResetBasicData.reset();
-
LoggedSqlCollector.start();
Ebean.find(Customer.class)
@@ -243,8 +257,8 @@ public class TestQueryFilterMany extends BaseTestCase {
.findList();
List sql = LoggedSqlCollector.stop();
- assertEquals(2, sql.size());
- assertSql(sql.get(1)).contains("and (t0.status = ? or t0.order_date = ?");
+ assertEquals(1, sql.size());
+ assertSql(sql.get(0)).contains(" from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where (t1.status = ? or t1.order_date = ?) order by t0.id");
}
@Test
@@ -259,12 +273,10 @@ public class TestQueryFilterMany extends BaseTestCase {
List sql = LoggedSqlCollector.stop();
- assertThat(sql).hasSize(3);
- assertSql(sql.get(0)).contains(" from o_customer t0; --bind()");
- platformAssertIn(sql.get(1), " from contact t0 where (t0.customer_id)");
- assertSql(sql.get(1)).contains(" and t0.first_name is not null");
- platformAssertIn(sql.get(2), " from contact_note t0 where (t0.contact_id)");
- assertSql(sql.get(2)).contains(" and lower(t0.title) like");
+ assertThat(sql).hasSize(2);
+ assertSql(sql.get(0)).contains(" from o_customer t0 left join contact t1 on t1.customer_id = t0.id where t1.first_name is not null order by t0.id; --bind()");
+ platformAssertIn(sql.get(1), " from contact_note t0 where (t0.contact_id)");
+ assertSql(sql.get(1)).contains(" and lower(t0.title) like");
}
@Test
@@ -280,9 +292,7 @@ public class TestQueryFilterMany extends BaseTestCase {
List sql = LoggedSqlCollector.stop();
- assertThat(sql).hasSize(2);
- assertSql(sql.get(0)).contains(" from o_customer t0");
- assertSql(sql.get(1)).contains("from contact t0 where ");
- assertSql(sql.get(1)).contains("and (t0.first_name is not null and lower(t0.email) like ?");
+ assertThat(sql).hasSize(1);
+ assertSql(sql.get(0)).contains(" from o_customer t0 left join contact t1 on t1.customer_id = t0.id where (t1.first_name is not null and lower(t1.email) like ? escape'|' ) order by t0.id; --bind(rob%)");
}
}