(includedBeanJoin);
@@ -290,17 +282,28 @@ public class OrmQueryProperties implements Serializable {
return included != null;
}
+ /**
+ * Return true if the properties and configuration are empty.
+ */
+ public boolean isEmpty() {
+ return rawProperties == null || rawProperties.isEmpty();
+ }
+
public String toString() {
- String s = "";
+ StringBuilder sb = new StringBuilder(40);
+ append("", sb);
+ return sb.toString();
+ }
+
+ public String append(String prefix, StringBuilder sb) {
+ sb.append(prefix);
if (path != null) {
- s += path + " ";
+ sb.append(path).append(" ");
}
- if (properties != null) {
- s += "(" + properties + ") ";
- } else if (included != null) {
- s += "(" + included + ") ";
+ if (!isEmpty()) {
+ sb.append("(").append(rawProperties).append(") ");
}
- return s;
+ return sb.toString();
}
public boolean isChild(OrmQueryProperties possibleChild) {
@@ -318,35 +321,22 @@ public class OrmQueryProperties implements Serializable {
}
/**
- * Calculate the query plan hash.
+ * Return the raw properties.
*/
- @SuppressWarnings("unchecked")
- public void queryPlanHash(HashQueryPlanBuilder builder) {
-
- builder.add(path);
- if (properties != null) {
- builder.add(properties);
- } else {
- builder.add(included);
- }
- builder.add(filterMany != null);
- if (filterMany != null) {
- filterMany.queryPlanHash(builder);
- }
- builder.add(lazyFetchBatch);
- builder.add(queryFetchBatch);
- builder.add(queryFetchAll);
- }
-
public String getProperties() {
- return properties;
+ return rawProperties;
}
/**
- * Return true if this has properties.
+ * Return true if this has properties. Returning false means this part of the
+ * path is a partial object.
*/
public boolean hasProperties() {
- return properties != null || included != null;
+ return included != null;
+ }
+
+ public boolean allProperties() {
+ return included == null;
}
/**
@@ -370,10 +360,6 @@ public class OrmQueryProperties implements Serializable {
includedBeanJoin.add(propertyName);
}
- public boolean allProperties() {
- return included == null;
- }
-
/**
* This excludes the bean joined properties.
*
@@ -386,7 +372,7 @@ public class OrmQueryProperties implements Serializable {
return included;
}
- LinkedHashSet temp = new LinkedHashSet(secondaryQueryJoins.size() + included.size());
+ LinkedHashSet temp = new LinkedHashSet(2 * (secondaryQueryJoins.size() + included.size()));
temp.addAll(included);
temp.addAll(secondaryQueryJoins);
return temp;
@@ -400,30 +386,10 @@ public class OrmQueryProperties implements Serializable {
}
/**
- * Return all the properties including the bean joins. This is the set that will be used by
- * EntityBeanIntercept to determine if a property needs to be lazy loaded.
+ * Return the property set.
*/
- public Set getAllIncludedProperties() {
-
- if (included == null) {
- return null;
- }
-
- if (includedBeanJoin == null && secondaryQueryJoins == null) {
- return new LinkedHashSet(included);
- }
-
- LinkedHashSet s = new LinkedHashSet(2 * (included.size() + 5));
- if (included != null) {
- s.addAll(included);
- }
- if (includedBeanJoin != null) {
- s.addAll(includedBeanJoin);
- }
- if (secondaryQueryJoins != null) {
- s.addAll(secondaryQueryJoins);
- }
- return s;
+ protected Set getIncluded() {
+ return included;
}
public boolean isIncluded(String propName) {
@@ -480,96 +446,47 @@ public class OrmQueryProperties implements Serializable {
return path;
}
- private void parseProperties() {
- if (trimmedProperties == null) {
- return;
- }
- int pos = trimmedProperties.indexOf("+readonly");
- if (pos > -1) {
- trimmedProperties = StringHelper.replaceString(trimmedProperties, "+readonly", "");
- this.readOnly = true;
- }
- pos = trimmedProperties.indexOf("+cache");
- if (pos > -1) {
- trimmedProperties = StringHelper.replaceString(trimmedProperties, "+cache", "");
- this.cache = true;
- }
- pos = trimmedProperties.indexOf("+query");
- if (pos > -1) {
- queryFetchBatch = parseBatchHint(pos, "+query");
- }
- pos = trimmedProperties.indexOf("+lazy");
- if (pos > -1) {
- lazyFetchBatch = parseBatchHint(pos, "+lazy");
- }
-
- trimmedProperties = trimmedProperties.trim();
- while (trimmedProperties.startsWith(",")) {
- trimmedProperties = trimmedProperties.substring(1).trim();
- }
- }
-
- private int parseBatchHint(int pos, String option) {
-
- int startPos = pos + option.length();
-
- int endPos = findEndPos(startPos, trimmedProperties);
- if (endPos == -1) {
- trimmedProperties = StringHelper.replaceString(trimmedProperties, option, "");
- return 0;
-
- } else {
-
- String batchParam = trimmedProperties.substring(startPos + 1, endPos);
-
- if (endPos + 1 >= trimmedProperties.length()) {
- trimmedProperties = trimmedProperties.substring(0, pos);
- } else {
- trimmedProperties = trimmedProperties.substring(0, pos) + trimmedProperties.substring(endPos + 1);
- }
- return Integer.parseInt(batchParam);
- }
- }
-
- private int findEndPos(int pos, String props) {
-
- if (pos < props.length()) {
- if (props.charAt(pos) == '(') {
- int endPara = props.indexOf(')', pos + 1);
- if (endPara == -1) {
- String m = "Error could not find ')' in " + props + " after position " + pos;
- throw new RuntimeException(m);
- }
- return endPara;
- }
- }
- return -1;
- }
-
/**
- * Parse the include separating by comma or semicolon.
+ * Return true if the properties are the same for autoTune purposes.
*/
- private static Set parseIncluded(String rawList) {
-
- String[] res = rawList.split(",");
-
- LinkedHashSet set = new LinkedHashSet(res.length + 3);
-
- String temp;
- for (int i = 0; i < res.length; i++) {
- temp = res[i].trim();
- if (temp.length() > 0) {
- set.add(temp);
- }
- }
-
- return Collections.unmodifiableSet(set);
- }
-
- public boolean isSame(OrmQueryProperties p2) {
+ public boolean isSameByAutoTune(OrmQueryProperties p2) {
if (included == null) {
return p2.included == null;
}
return included.equals(p2.included);
}
+
+ /**
+ * Properties are the same for query plan purposes.
+ */
+ public boolean isSameByPlan(OrmQueryProperties p2) {
+
+ if (!Same.sameByValue(secondaryQueryJoins, p2.secondaryQueryJoins)) return false;
+ if (!Same.sameByValue(included, p2.included)) return false;
+ if (!Same.sameByNull(filterMany, p2.filterMany)) return false;
+ if (filterMany != null && !filterMany.isSameByPlan(p2.filterMany)) return false;
+
+ return lazyFetchBatch == p2.lazyFetchBatch
+ && queryFetchBatch == p2.queryFetchBatch
+ && queryFetchAll == p2.queryFetchAll;
+ }
+
+ /**
+ * Calculate the query plan hash.
+ */
+ public void queryPlanHash(HashQueryPlanBuilder builder) {
+
+ builder.add(path);
+ builder.addOrdered(included);
+ builder.add(secondaryQueryJoins);
+
+ builder.add(filterMany != null);
+ if (filterMany != null) {
+ filterMany.queryPlanHash(builder);
+ }
+ builder.add(lazyFetchBatch);
+ builder.add(queryFetchBatch);
+ builder.add(queryFetchAll);
+ }
+
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java
new file mode 100644
index 000000000..fce8b056d
--- /dev/null
+++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java
@@ -0,0 +1,183 @@
+package com.avaje.ebeaninternal.server.querydefn;
+
+import com.avaje.ebeaninternal.server.lib.util.StringHelper;
+
+import java.util.LinkedHashSet;
+
+/**
+ * Parses the path properties string.
+ */
+public class OrmQueryPropertiesParser {
+
+ private static Response EMPTY = new Response();
+
+ /**
+ * Immutable response of the parsed properties and options.
+ */
+ public static class Response {
+
+ final boolean readOnly;
+ final boolean cache;
+ final int queryFetchBatch;
+ final int lazyFetchBatch;
+ final String properties;
+ final LinkedHashSet included;
+
+ public Response(boolean readOnly, boolean cache, int queryFetchBatch, int lazyFetchBatch, String properties, LinkedHashSet included) {
+ this.readOnly = readOnly;
+ this.cache = cache;
+ this.queryFetchBatch = queryFetchBatch;
+ this.lazyFetchBatch = lazyFetchBatch;
+ this.properties = properties;
+ this.included = included;
+ }
+
+ public Response() {
+ this.readOnly = false;
+ this.cache = false;
+ this.queryFetchBatch = -1;
+ this.lazyFetchBatch = -1;
+ this.properties = "";
+ this.included = null;
+ }
+ }
+
+ /**
+ * Parses the path properties string returning the parsed properties and options.
+ * In general it is comma delimited with some special strings like +lazy(20).
+ */
+ public static Response parse(String rawProperties) {
+ return new OrmQueryPropertiesParser(rawProperties).parse();
+ }
+
+ private String inputProperties;
+
+ private String outputProperties = "";
+ private boolean allProperties;
+ private boolean readOnly;
+ private boolean cache;
+ private int queryFetchBatch = -1;
+ private int lazyFetchBatch = -1;
+
+ private OrmQueryPropertiesParser(String inputProperties) {
+ this.inputProperties = inputProperties;
+ }
+
+ /**
+ * Parse the raw string properties input.
+ */
+ private Response parse() {
+
+ if (inputProperties == null || inputProperties.isEmpty()) {
+ return EMPTY;
+ }
+ int pos = inputProperties.indexOf("+readonly");
+ if (pos > -1) {
+ inputProperties = StringHelper.replaceString(inputProperties, "+readonly", "");
+ readOnly = true;
+ }
+ pos = inputProperties.indexOf("+cache");
+ if (pos > -1) {
+ inputProperties = StringHelper.replaceString(inputProperties, "+cache", "");
+ cache = true;
+ }
+ pos = inputProperties.indexOf("+query");
+ if (pos > -1) {
+ queryFetchBatch = parseBatchHint(pos, "+query");
+ }
+ pos = inputProperties.indexOf("+lazy");
+ if (pos > -1) {
+ lazyFetchBatch = parseBatchHint(pos, "+lazy");
+ }
+
+ LinkedHashSet included = parseIncluded();
+ String properties = (allProperties) ? "*" : outputProperties;
+ return new Response(readOnly, cache, queryFetchBatch, lazyFetchBatch, properties, included);
+ }
+
+ /**
+ * Parse the include separating by comma or semicolon.
+ */
+ private LinkedHashSet parseIncluded() {
+
+ inputProperties = inputProperties.trim();
+ if (inputProperties.isEmpty()) {
+ // default properties
+ return null;
+ }
+ if (inputProperties.equals("*")) {
+ // explicit all properties
+ allProperties = true;
+ return null;
+ }
+
+ String[] res = inputProperties.split(",");
+
+ StringBuilder sb = new StringBuilder(70);
+ LinkedHashSet propertySet = new LinkedHashSet(res.length * 2);
+
+ int count = 0;
+ String temp;
+ for (int i = 0; i < res.length; i++) {
+ temp = res[i].trim();
+ if (temp.length() > 0) {
+ if (count > 0) {
+ sb.append(",");
+ }
+ sb.append(temp);
+ propertySet.add(temp);
+ count++;
+ }
+ }
+
+ if (propertySet.isEmpty()) {
+ // default properties
+ return null;
+ }
+
+ if (propertySet.contains("*")) {
+ // explicit all properties
+ allProperties = true;
+ return null;
+ }
+
+ // partial properties
+ outputProperties = sb.toString();
+ return propertySet;
+ }
+
+ private int parseBatchHint( int pos, String option) {
+
+ int startPos = pos + option.length();
+ int endPos = findEndPos(startPos, inputProperties);
+ if (endPos == -1) {
+ inputProperties = StringHelper.replaceString(inputProperties, option, "");
+ return 0;
+
+ } else {
+
+ String batchParam = inputProperties.substring(startPos + 1, endPos);
+
+ if (endPos + 1 >= inputProperties.length()) {
+ inputProperties = inputProperties.substring(0, pos);
+ } else {
+ inputProperties = inputProperties.substring(0, pos) + inputProperties.substring(endPos + 1);
+ }
+ return Integer.parseInt(batchParam);
+ }
+ }
+
+ private int findEndPos(int pos, String props) {
+
+ if (pos < props.length()) {
+ if (props.charAt(pos) == '(') {
+ int endPara = props.indexOf(')', pos + 1);
+ if (endPara == -1) {
+ throw new RuntimeException("Error could not find ')' in " + props + " after position " + pos);
+ }
+ return endPara;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/SimpleTextParser.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/SimpleTextParser.java
index d65a24f97..345503966 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/SimpleTextParser.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/SimpleTextParser.java
@@ -16,6 +16,10 @@ public class SimpleTextParser {
this.eof = oql.length();
}
+ public boolean isEmpty() {
+ return oql.isEmpty();
+ }
+
public int getPos() {
return pos;
}
diff --git a/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java b/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java
new file mode 100644
index 000000000..fb98c62d8
--- /dev/null
+++ b/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java
@@ -0,0 +1,126 @@
+package com.avaje.ebeaninternal.server.core;
+
+
+import com.avaje.ebean.BaseTestCase;
+import com.avaje.ebean.Ebean;
+import com.avaje.ebean.FetchConfig;
+import com.avaje.ebean.Query;
+import com.avaje.ebeaninternal.api.SpiQuery;
+import com.avaje.ebeaninternal.server.querydefn.DefaultOrmQuery;
+import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
+import com.avaje.tests.model.basic.Order;
+import org.junit.Test;
+
+import static org.assertj.core.api.StrictAssertions.assertThat;
+
+public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
+
+ static DefaultServer defaultServer = (DefaultServer)Ebean.getDefaultServer();
+
+ Query query() {
+ return defaultServer.find(Order.class);
+ }
+
+ OrmQueryRequest queryRequest(Query query) {
+ return (OrmQueryRequest)defaultServer.createQueryRequest(SpiQuery.Type.LIST, query, null);
+ }
+
+ OrmQueryDetail detail(Query query) {
+ return queryRequest(query).getQuery().getDetail();
+ }
+
+ @Test
+ public void when_empty_then_same() {
+
+ assertSame(detail(query()), detail(query()));
+ }
+
+ @Test
+ public void select_all_then_same() {
+
+ assertSame(detail(query().select("*")), detail(query().select("*")));
+ }
+
+ @Test
+ public void when_propertiesInOrder_then_same() {
+
+ assertSame(detail(query().select("id,name")), detail(query().select("id,name")));
+ }
+
+ @Test
+ public void when_propertiesInDifferentOrder_then_different() {
+
+ assertDifferent(detail(query().select("id,name")), detail(query().select("name, id")));
+
+ // but same from autotune perspective
+ assertThat(detail(query().select("id,name")).isAutoTuneEqual(detail(query().select("name, id")))).isTrue();
+ }
+
+ @Test
+ public void when_additional_fetch_then_different() {
+
+ assertDifferent(detail(query().select("id,name")), detail(query().select("id,name").fetch("details")));
+ }
+
+ @Test
+ public void when_same_fetch_then_same() {
+
+ assertSame(detail(query().select("id,name").fetch("details")), detail(query().select("id,name").fetch("details")));
+ }
+
+ @Test
+ public void when_fetch_order_different_then_different() {
+
+ assertDifferent(detail(query().select("id,name").fetch("details").fetch("customer")),
+ detail(query().select("id,name").fetch("customer").fetch("details")));
+ }
+
+ @Test
+ public void when_extra_queryFetchToMany_then_same() {
+
+ assertDifferent(detail(query().select("id,name").fetch("customer")),
+ detail(query().select("id,name").fetch("customer").fetch("details", new FetchConfig().query())));
+ }
+
+ @Test
+ public void when_extra_queryToOne_fetch_then_different() {
+
+ // with the fetch of customer the foreign key must be added to the root query
+ assertDifferent(detail(query().select("id,name")),
+ detail(query().select("id,name").fetch("customer",new FetchConfig().query())));
+ }
+
+ @Test
+ public void when_additional_fetch_V2_then_different() {
+
+ assertDifferent(detail(query().select("id,name")), detail(query().select("id,name").fetch("customer","id")));
+ }
+
+
+ @Test
+ public void when_fetchConfig_then_differentPlan() throws Exception {
+
+ DefaultOrmQuery query1 = (DefaultOrmQuery)Ebean.find(Order.class)
+ .select("status, shipDate")
+ .fetch("details", "orderQty, unitPrice", new FetchConfig().query())
+ .fetch("details.product", "sku, name");
+
+
+ DefaultOrmQuery query2 = (DefaultOrmQuery)Ebean.find(Order.class)
+ .select("status, shipDate")
+ .fetch("details", "orderQty, unitPrice")
+ .fetch("details.product", "sku, name");
+
+ assertDifferent(detail(query1), detail(query2));
+ }
+
+ private void assertSame(OrmQueryDetail detail1, OrmQueryDetail detail2) {
+ assertThat(detail1.isSameByPlan(detail2)).isTrue();
+ assertThat(detail1.queryPlanHash()).isEqualTo(detail2.queryPlanHash());
+ }
+
+ private void assertDifferent(OrmQueryDetail detail1, OrmQueryDetail detail2) {
+ assertThat(detail1.isSameByPlan(detail2)).isFalse();
+ assertThat(detail1.queryPlanHash()).isNotEqualTo(detail2.queryPlanHash());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java
index 50b4f558a..d3016e706 100644
--- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java
@@ -40,24 +40,6 @@ public class DefaultOrmQueryTest {
assertThat(q1.queryBindHash()).isEqualTo(q2.queryBindHash());
}
-
- @Test
- public void when_FetchConfig_then_differentPlan() throws Exception {
-
- DefaultOrmQuery> query1 = (DefaultOrmQuery>)Ebean.find(Order.class)
- .select("status, shipDate")
- .fetch("details", "orderQty, unitPrice", new FetchConfig().query())
- .fetch("details.product", "sku, name");
-
-
- DefaultOrmQuery> query2 = (DefaultOrmQuery>)Ebean.find(Order.class)
- .select("status, shipDate")
- .fetch("details", "orderQty, unitPrice")
- .fetch("details.product", "sku, name");
-
- assertThat(query1.createQueryPlanKey()).isNotEqualTo(query2.createQueryPlanKey());
- }
-
@Test
public void when_diffFirstMaxRows_then_differentPlan() throws Exception {
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailParserTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailParserTest.java
index 0e877728c..3be9f7943 100644
--- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailParserTest.java
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailParserTest.java
@@ -5,114 +5,111 @@ import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
public class OrmQueryDetailParserTest extends BaseTestCase {
+ OrmQueryDetail parse(String query) {
+ return new OrmQueryDetailParser(query).parse();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void parse_when_nullString() throws Exception {
+ parse(null);
+ }
+
+ @Test
+ public void parse_when_emptyString() throws Exception {
+ assertTrue(parse("").isEmpty());
+ }
+
@Test
public void testParseBasic() throws Exception {
+ OrmQueryDetail detail = parse("select (id,name)");
- OrmQueryDetail other = new OrmQueryDetail();
- other.select("id,name");
-
- OrmQueryProperties root = other.getChunk(null, false);
+ OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
-
- OrmQueryDetailParser p = new OrmQueryDetailParser("select (id,name)");
- OrmQueryDetail detail = p.parse();
-
- root = detail.getChunk(null, false);
- assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
+ assertThat(root.getIncluded()).containsExactly("id", "name");
}
@Test
public void testParseEmptySelect() throws Exception {
- OrmQueryDetailParser p = new OrmQueryDetailParser("select fetch customer (email)");
- OrmQueryDetail detail = p.parse();
+ OrmQueryDetail detail = parse("select fetch customer (email)");
OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).isNull();
+ assertThat(root.getIncluded()).isNull();
OrmQueryProperties chunk = detail.getChunk("customer", false);
assertThat(chunk.getPath()).isEqualTo("customer");
- assertThat(chunk.getAllIncludedProperties()).contains("email");
+ assertThat(chunk.getIncluded()).contains("email");
}
@Test
public void testParseSelectFetch() throws Exception {
- OrmQueryDetailParser p = new OrmQueryDetailParser("select (id,name) fetch customer (email)");
- OrmQueryDetail detail = p.parse();
+ OrmQueryDetail detail = parse("select (id,name) fetch customer (email)");
OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
+ assertThat(root.getIncluded()).contains("id", "name");
OrmQueryProperties chunk = detail.getChunk("customer", false);
assertThat(chunk.getPath()).isEqualTo("customer");
- assertThat(chunk.getAllIncludedProperties()).contains("email");
+ assertThat(chunk.getIncluded()).contains("email");
}
@Test
public void testParseSelectFetchMore() throws Exception {
- OrmQueryDetailParser p = new OrmQueryDetailParser("select (id,name) fetch customer (email) fetch details.product (sku,description)");
- OrmQueryDetail detail = p.parse();
+ OrmQueryDetail detail = parse("select (id,name) fetch customer (email) fetch details.product (sku,description)");
OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
+ assertThat(root.getIncluded()).contains("id", "name");
OrmQueryProperties chunk = detail.getChunk("customer", false);
assertThat(chunk.getPath()).isEqualTo("customer");
- assertThat(chunk.getAllIncludedProperties()).contains("email");
+ assertThat(chunk.getIncluded()).contains("email");
chunk = detail.getChunk("details.product", false);
assertThat(chunk.getPath()).isEqualTo("details.product");
- assertThat(chunk.getAllIncludedProperties()).contains("sku","description");
+ assertThat(chunk.getIncluded()).contains("sku","description");
}
@Test
public void testParseWithPlusQuery() throws Exception {
- OrmQueryDetailParser p = new OrmQueryDetailParser("select (id,name) fetch customer (+query,id,name,email)");
- OrmQueryDetail detail = p.parse();
+ OrmQueryDetail detail = parse("select (id,name) fetch customer (+query,id,name,email)");
OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
+ assertThat(root.getIncluded()).contains("id", "name");
OrmQueryProperties chunk = detail.getChunk("customer", false);
assertThat(chunk.getPath()).isEqualTo("customer");
- assertThat(chunk.getAllIncludedProperties()).contains("id", "name", "email");
+ assertThat(chunk.getIncluded()).contains("id", "name", "email");
assertThat(chunk.isQueryFetch()).isTrue();
-
}
@Test
public void testTuneApply() {
- OrmQueryDetailParser p = new OrmQueryDetailParser("select (status) fetch customer (email)");
- OrmQueryDetail detail = p.parse();
-
- OrmQueryDetailParser p2 = new OrmQueryDetailParser("select (id,name) fetch customer (+query,id,name,email)");
- OrmQueryDetail tune = p2.parse();
-
+ OrmQueryDetail detail = parse("select (status) fetch customer (email)");
+ OrmQueryDetail tune = parse("select (id,name) fetch customer (+query,id,name,email)");
detail.tuneFetchProperties(tune);
OrmQueryProperties root = detail.getChunk(null, false);
assertNull(root.getPath());
- assertThat(root.getAllIncludedProperties()).contains("id", "name");
+ assertThat(root.getIncluded()).contains("id", "name");
OrmQueryProperties chunk = detail.getChunk("customer", false);
assertThat(chunk.getPath()).isEqualTo("customer");
- assertThat(chunk.getAllIncludedProperties()).contains("id", "name", "email");
+ assertThat(chunk.getIncluded()).contains("id", "name", "email");
assertThat(chunk.isQueryFetch()).isTrue();
}
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailTest.java
index 3fa127b73..b12516431 100644
--- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailTest.java
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryDetailTest.java
@@ -2,20 +2,70 @@ package com.avaje.ebeaninternal.server.querydefn;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
public class OrmQueryDetailTest {
+ OrmQueryDetail parse(String query) {
+ return new OrmQueryDetailParser(query).parse();
+ }
@Test
- public void test_isAutoTuneEqual() {
+ public void isAutoTuneEqual_when_fetchOrderIsDifferent_then_stillEqual() {
- OrmQueryDetailParser parser1 = new OrmQueryDetailParser("select (id,name) fetch customer (name) fetch details (code)");
- OrmQueryDetail detail1 = parser1.parse();
-
- OrmQueryDetailParser parser2 = new OrmQueryDetailParser("select (id,name) fetch details (code) fetch customer (name)");
- OrmQueryDetail detail2 = parser2.parse();
+ OrmQueryDetail detail1 = parse("select (id,name) fetch customer (name) fetch details (code)");
+ OrmQueryDetail detail2 = parse("select (id,name) fetch details (code) fetch customer (name)");
assertTrue(detail1.isAutoTuneEqual(detail2));
}
+
+ @Test
+ public void isAutoTuneEqual_when_different_select() {
+
+ OrmQueryDetail detail1 = parse("select (id,name) fetch customer (name) fetch details (code)");
+ OrmQueryDetail detail2 = parse("select (id) fetch details (code) fetch customer (name)");
+
+ assertFalse(detail1.isAutoTuneEqual(detail2));
+ }
+
+ @Test
+ public void isAutoTuneEqual_when_different_selectInFetch() {
+
+ OrmQueryDetail detail1 = parse("select (id,name) fetch customer (name) fetch details (code)");
+ OrmQueryDetail detail2 = parse("select (id,name) fetch customer (id,name) fetch details (code)");
+
+ assertFalse(detail1.isAutoTuneEqual(detail2));
+ }
+
+ @Test
+ public void isAutoTuneEqual_when_different_additionalFetch() {
+
+ OrmQueryDetail detail1 = parse("select (id,name) fetch customer (name) fetch details (code)");
+ OrmQueryDetail detail2 = parse("select (id,name) fetch customer (name) fetch details (code) fetch customer.contacts");
+
+ assertFalse(detail1.isAutoTuneEqual(detail2));
+ }
+
+ @Test
+ public void select_whenMultiple() throws Exception {
+
+ OrmQueryDetail other = new OrmQueryDetail();
+ other.select("id,name");
+
+ OrmQueryProperties root = other.getChunk(null, false);
+ assertNull(root.getPath());
+ assertThat(root.getIncluded()).containsExactly("id", "name");
+ }
+
+ @Test
+ public void select_whenOne() throws Exception {
+
+ OrmQueryDetail other = new OrmQueryDetail();
+ other.select("name");
+
+ OrmQueryProperties root = other.getChunk(null, false);
+ assertNull(root.getPath());
+ assertThat(root.getIncluded()).containsExactly("name");
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java
new file mode 100644
index 000000000..ab519e1bb
--- /dev/null
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java
@@ -0,0 +1,132 @@
+package com.avaje.ebeaninternal.server.querydefn;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class OrmQueryPropertiesParserTest {
+
+ @Test
+ public void when_null() {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse(null);
+ assertAllDefaults(res);
+ assertThat(res.properties).isEqualTo("");
+ }
+
+ @Test
+ public void when_empty() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("");
+ assertAllDefaults(res);
+ assertThat(res.properties).isEqualTo("");
+ }
+
+ @Test
+ public void when_hasStar() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("*");
+ assertAllDefaults(res);
+ assertThat(res.properties).isEqualTo("*");
+ }
+
+ @Test
+ public void when_hasCache() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache");
+ assertThat(res.cache).isTrue();
+ assertThat(res.included).isNull();
+ }
+
+ @Test
+ public void when_hasCache_first() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache,id");
+ assertThat(res.cache).isTrue();
+ assertThat(res.included).containsExactly("id");
+ }
+
+ @Test
+ public void when_hasCache_last() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache");
+ assertThat(res.cache).isTrue();
+ assertThat(res.included).containsExactly("name");
+ }
+
+ @Test
+ public void when_hasCache_middle() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache, id");
+ assertThat(res.cache).isTrue();
+ assertThat(res.included).containsExactly("name", "id");
+ }
+
+ @Test
+ public void when_hasReadOnly() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+readonly");
+ assertThat(res.readOnly).isTrue();
+ assertThat(res.included).isNull();
+ }
+
+ @Test
+ public void when_hasLazy() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy");
+ assertThat(res.lazyFetchBatch).isEqualTo(0);
+ assertThat(res.included).isNull();
+ }
+
+ @Test
+ public void when_hasLazyValue() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20)");
+ assertThat(res.lazyFetchBatch).isEqualTo(20);
+ assertThat(res.included).isNull();
+ }
+
+ @Test
+ public void when_hasLazyValue_last() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+lazy(20)");
+ assertThat(res.lazyFetchBatch).isEqualTo(20);
+ assertThat(res.included).containsExactly("name");
+ }
+
+ @Test
+ public void when_hasLazyValue_first() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20),id,name");
+ assertThat(res.lazyFetchBatch).isEqualTo(20);
+ assertThat(res.included).containsExactly("id", "name");
+ }
+
+ @Test
+ public void when_allProperties() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+query(4),+lazy(5)");
+ assertThat(res.lazyFetchBatch).isEqualTo(5);
+ assertThat(res.included).isNull();
+ }
+
+
+ @Test
+ public void when_everything_set() throws Exception {
+
+ OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id, name +readonly +lazy(20) +query(30) +cache");
+ assertThat(res.lazyFetchBatch).isEqualTo(20);
+ assertThat(res.queryFetchBatch).isEqualTo(30);
+ assertThat(res.readOnly).isTrue();
+ assertThat(res.cache).isTrue();
+ assertThat(res.included).containsExactly("id", "name");
+ }
+
+ private void assertAllDefaults(OrmQueryPropertiesParser.Response res) {
+ assertThat(res.cache).isFalse();
+ assertThat(res.readOnly).isFalse();
+ assertThat(res.lazyFetchBatch).isEqualTo(-1);
+ assertThat(res.queryFetchBatch).isEqualTo(-1);
+ assertThat(res.included).isNull();
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java
new file mode 100644
index 000000000..b1cc03494
--- /dev/null
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java
@@ -0,0 +1,50 @@
+package com.avaje.ebeaninternal.server.querydefn;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class OrmQueryPropertiesTest {
+
+ String append(String prefix, OrmQueryProperties p1) {
+ StringBuilder sb = new StringBuilder();
+ p1.append(prefix, sb);
+ return sb.toString();
+ }
+
+ @Test
+ public void append_when_empty() {
+
+ OrmQueryProperties p1 = new OrmQueryProperties();
+ assertThat(append("select ",p1)).isEqualTo("select ");
+ }
+
+ @Test
+ public void append_when_someProperties() {
+
+ OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name");
+ assertThat(append("select ",p1)).isEqualTo("select (id,name) ");
+ }
+
+ @Test
+ public void append_when_somePropertiesWithOptions() {
+
+ OrmQueryProperties p1 = new OrmQueryProperties(null, "id,name +cache");
+ assertThat(append("select ",p1)).isEqualTo("select (id,name +cache) ");
+ }
+
+ @Test
+ public void append_when_path_and_emptyProperties() {
+
+ OrmQueryProperties p1 = new OrmQueryProperties("customer", "");
+ assertThat(append("fetch ",p1)).isEqualTo("fetch customer ");
+ }
+
+ @Test
+ public void append_when_path_and_somePropertiesWithOptions() {
+
+ OrmQueryProperties p1 = new OrmQueryProperties("customer", "id,name +cache");
+ assertThat(append("fetch ",p1)).isEqualTo("fetch customer (id,name +cache) ");
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/TestQueryLanguage.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/TestQueryLanguage.java
index fb0cc9a26..36f9abb03 100644
--- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/TestQueryLanguage.java
+++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/TestQueryLanguage.java
@@ -1,15 +1,14 @@
package com.avaje.ebeaninternal.server.querydefn;
-import java.util.Set;
-
-import org.junit.Assert;
-import org.junit.Test;
-
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
import com.avaje.tests.model.basic.Order;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Set;
public class TestQueryLanguage extends BaseTestCase {
@@ -19,7 +18,7 @@ public class TestQueryLanguage extends BaseTestCase {
DefaultOrmQuery q = check("find order join customer (id, name)");
OrmQueryDetail detail = q.getDetail();
OrmQueryProperties chunk = detail.getChunk("customer", false);
- Set props = chunk.getAllIncludedProperties();
+ Set props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
@@ -27,7 +26,7 @@ public class TestQueryLanguage extends BaseTestCase {
q = check("find order join customer(id, name)");
detail = q.getDetail();
chunk = detail.getChunk("customer", false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
@@ -37,7 +36,7 @@ public class TestQueryLanguage extends BaseTestCase {
q = check("find order join customer(+cache +readonly, id, name)");
detail = q.getDetail();
chunk = detail.getChunk("customer", false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
Assert.assertTrue(chunk.isCache());
@@ -46,7 +45,7 @@ public class TestQueryLanguage extends BaseTestCase {
q = check("find order join customer(+cache +readonly,id,name)");
detail = q.getDetail();
chunk = detail.getChunk("customer", false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
Assert.assertTrue(chunk.isCache());
@@ -55,14 +54,14 @@ public class TestQueryLanguage extends BaseTestCase {
q = check("find order(id,status) join customer(+cache +readonly,id,name)");
detail = q.getDetail();
chunk = detail.getChunk("customer", false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
Assert.assertTrue(chunk.isCache());
Assert.assertTrue(chunk.isReadOnly());
chunk = detail.getChunk(null, false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("status"));
Assert.assertFalse(props.contains("orderDate"));
@@ -70,7 +69,7 @@ public class TestQueryLanguage extends BaseTestCase {
q = check("find order(id,status) join customer(+cache +readonly,id,name) where id > :minId order by status");
detail = q.getDetail();
chunk = detail.getChunk("customer", false);
- props = chunk.getAllIncludedProperties();
+ props = chunk.getIncluded();
Assert.assertTrue(props.contains("id"));
Assert.assertTrue(props.contains("name"));
Assert.assertTrue(chunk.isCache());
diff --git a/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java b/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java
index 99a0ead5f..2d0cc5fcb 100644
--- a/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java
+++ b/src/test/java/com/avaje/tests/autofetch/TunedQueryInfoTest.java
@@ -101,7 +101,7 @@ public class TunedQueryInfoTest extends BaseTestCase {
@NotNull
private TunedQueryInfo createTunedQueryInfo(OrmQueryDetail tunedDetail) {
Origin origin = new Origin();
- origin.setDetail(tunedDetail.toString());
+ origin.setDetail(tunedDetail.asString());
return new TunedQueryInfo(origin);
}
diff --git a/src/test/java/com/avaje/tests/query/TestQueryParsing.java b/src/test/java/com/avaje/tests/query/TestQueryParsing.java
index 3b7c35d68..626dec929 100644
--- a/src/test/java/com/avaje/tests/query/TestQueryParsing.java
+++ b/src/test/java/com/avaje/tests/query/TestQueryParsing.java
@@ -1,37 +1,40 @@
package com.avaje.tests.query;
-import org.junit.Assert;
-import org.junit.Test;
-
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
import com.avaje.tests.model.basic.Order;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
public class TestQueryParsing extends BaseTestCase {
@Test
public void test() {
- String oq = "find order join customer join customer.contacts join details (+query(4),+lazy(5))";
+ String oq = "find order join customer (id, name) join customer.contacts join details (+query(4),+lazy(5))";
Query q = Ebean.createQuery(Order.class, oq);
checkQuery(q);
- String oq1 = "find order join customer join customer.contacts join details ( +query(4), +lazy(5) )";
+ String oq1 = "find order join customer (id, name) join customer.contacts join details ( +query(4), +lazy(5) )";
SpiQuery> q1 = (SpiQuery>) Ebean.createQuery(Order.class, oq1);
checkQuery(q1);
- String oq2 = "find order join customer join customer.contacts join details ( +query(4), +lazy(5) , *)";
+ String oq2 = "find order join customer (id, name) join customer.contacts join details ( +query(4), +lazy(5) , *)";
SpiQuery> q2 = (SpiQuery>) Ebean.createQuery(Order.class, oq2);
checkQuery(q2);
- String oq3 = "find order join customer join customer.contacts join details (+query(4),+lazy(5),*)";
+ String oq3 = "find order join customer (id, name) join customer.contacts join details (+query(4),+lazy(5),*)";
SpiQuery> q3 = (SpiQuery>) Ebean.createQuery(Order.class, oq3);
checkQuery(q3);
- String oq4 = "find order join customer join customer.contacts join details (+query(4) +lazy(5) *)";
+ String oq4 = "find order join customer (id, name) join customer.contacts join details (+query(4) +lazy(5) *)";
SpiQuery> q4 = (SpiQuery>) Ebean.createQuery(Order.class, oq4);
checkQuery(q4);
@@ -41,23 +44,25 @@ public class TestQueryParsing extends BaseTestCase {
SpiQuery> sq = (SpiQuery>) q;
OrmQueryDetail detail = sq.getDetail();
+ assertTrue(detail.getChunk(null, false).allProperties());
- Assert.assertNotNull(detail.getChunk("customer", false));
- Assert.assertFalse(detail.getChunk("customer", false).isQueryFetch());
- Assert.assertFalse(detail.getChunk("customer", false).isLazyFetch());
+ assertNotNull(detail.getChunk("customer", false));
+ assertFalse(detail.getChunk("customer", false).isQueryFetch());
+ assertFalse(detail.getChunk("customer", false).isLazyFetch());
+ assertFalse(detail.getChunk("customer", false).allProperties());
+ assertEquals("id, name",detail.getChunk("customer", false).getProperties());
- Assert.assertNotNull(detail.getChunk("customer.contacts", false));
- Assert.assertFalse(detail.getChunk("customer.contacts", false).isQueryFetch());
- Assert.assertFalse(detail.getChunk("customer.contacts", false).isLazyFetch());
+ assertNotNull(detail.getChunk("customer.contacts", false));
+ assertFalse(detail.getChunk("customer.contacts", false).isQueryFetch());
+ assertFalse(detail.getChunk("customer.contacts", false).isLazyFetch());
+ assertTrue(detail.getChunk("customer.contacts", false).allProperties());
- Assert.assertNotNull(detail.getChunk("details", false));
- Assert.assertTrue(detail.getChunk("details", false).isQueryFetch());
- Assert.assertTrue(detail.getChunk("details", false).isLazyFetch());
-
- Assert.assertEquals(4, detail.getChunk("details", false).getQueryFetchBatch());
- Assert.assertEquals(5, detail.getChunk("details", false).getLazyFetchBatch());
-
- Assert.assertTrue(detail.getChunk("details", false).allProperties());
+ assertNotNull(detail.getChunk("details", false));
+ assertTrue(detail.getChunk("details", false).isQueryFetch());
+ assertTrue(detail.getChunk("details", false).isLazyFetch());
+ assertEquals(4, detail.getChunk("details", false).getQueryFetchBatch());
+ assertEquals(5, detail.getChunk("details", false).getLazyFetchBatch());
+ assertTrue(detail.getChunk("details", false).allProperties());
}