From c793d6652fa9edb8d35ec039023a1d936c094c3e Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 20 Jun 2016 22:29:38 +1200 Subject: [PATCH] #745 - ElasticSearch - internally translate where().id.eq(42) ... to where().setId(42) --- .../ebeaninternal/api/SpiExpression.java | 4 ++ .../com/avaje/ebeaninternal/api/SpiQuery.java | 5 ++ .../server/core/DefaultServer.java | 9 ++-- .../server/deploy/BeanDescriptor.java | 7 +++ .../server/expression/AbstractExpression.java | 6 +++ .../expression/AbstractTextExpression.java | 6 +++ .../expression/DefaultExampleExpression.java | 51 ++++++++++--------- .../expression/DefaultExpressionList.java | 13 +++++ .../expression/ExistsQueryExpression.java | 6 +++ .../server/expression/JunctionExpression.java | 6 +++ .../server/expression/LogicExpression.java | 6 +++ .../NestedPathWrapperExpression.java | 6 +++ .../expression/NonPrepareExpression.java | 6 +++ .../server/expression/NoopExpression.java | 6 +++ .../server/expression/NotExpression.java | 6 +++ .../server/expression/SimpleExpression.java | 8 +++ .../server/querydefn/DefaultOrmQuery.java | 10 ++++ .../server/querydefn/DefaultOrmQueryTest.java | 23 ++++++++- 18 files changed, 153 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java b/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java index 4969e186f..c96ad7332 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiExpression.java @@ -94,4 +94,8 @@ public interface SpiExpression extends Expression { */ SpiExpression copyForPlanKey(); + /** + * Return the bind Id value if this is a "equal to" expression for the id property. + */ + Object getIdEqualTo(String idName); } diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index b41d51e0a..d8020a540 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -133,6 +133,11 @@ public interface SpiQuery extends Query { } } + /** + * Check for a single "equal to" expression for the Id. + */ + void checkIdEqualTo(); + /** * Return true if AutoTune should be attempted on this query. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index bedd6ecd4..dad4acb29 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -1043,21 +1043,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { public T findUnique(Query query, Transaction transaction) { - Object id = query.getId(); + SpiQuery spiQuery = (SpiQuery) query; + spiQuery.checkIdEqualTo(); + Object id = spiQuery.getId(); if (id != null) { // actually a find by Id query return findId(query, transaction); } - SpiQuery spiQuery = (SpiQuery) query; - BeanDescriptor desc = spiQuery.getBeanDescriptor(); - SpiTransaction t = (SpiTransaction) transaction; if (t == null) { t = getCurrentServerTransaction(); } if (t == null || !t.isSkipCache()) { - id = desc.cacheNaturalKeyIdLookup(spiQuery); + id = spiQuery.getBeanDescriptor().cacheNaturalKeyIdLookup(spiQuery); if (id != null) { T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id); if (bean != null) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index a86c15811..4a1173860 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1768,6 +1768,13 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { pc.deleted(rootBeanType, idValue); } + /** + * Return the Id property name or null if no Id property exists. + */ + public String getIdName() { + return (idProperty == null) ? null : idProperty.getName(); + } + /** * Helper method to return the unique property. If only one property makes up * the unique id then it's value is returned. If there is a concatenated diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java index 374596ace..8b156c92b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractExpression.java @@ -21,6 +21,12 @@ public abstract class AbstractExpression implements SpiExpression { this.propName = propName; } + @Override + public Object getIdEqualTo(String idName) { + // override on SimpleExpression + return null; + } + @Override public SpiExpression copyForPlanKey() { return this; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java index 78535986c..87fe3bdbf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java @@ -16,6 +16,12 @@ public abstract class AbstractTextExpression extends AbstractExpression { super(propName); } + @Override + public Object getIdEqualTo(String idName) { + // always null for this expression + return null; + } + @Override public void addSql(SpiExpressionRequest request) { // do nothing, only execute against document store diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java index 07d296abf..3033e4c09 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java @@ -1,8 +1,5 @@ package com.avaje.ebeaninternal.server.expression; -import java.io.IOException; -import java.util.ArrayList; - import com.avaje.ebean.ExampleExpression; import com.avaje.ebean.LikeType; import com.avaje.ebean.bean.EntityBean; @@ -12,33 +9,34 @@ import com.avaje.ebeaninternal.api.ManyWhereJoins; import com.avaje.ebeaninternal.api.SpiExpression; import com.avaje.ebeaninternal.api.SpiExpressionRequest; import com.avaje.ebeaninternal.api.SpiExpressionValidation; -import com.avaje.ebeaninternal.server.core.OrmQueryRequest; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; import com.avaje.ebeaninternal.server.query.SplitName; +import java.io.IOException; +import java.util.ArrayList; + /** * A "Query By Example" type of expression. *

* Pass in an example entity and for each non-null scalar properties an * expression is added. *

- * - *
+ * 

+ *

{@code
  * // create an example bean and set the properties
  * // with the query parameters you want
  * Customer example = new Customer();
- * example.setName("Rob%");
- * example.setNotes("%something%");
- * 
- * List<Customer> list = Ebean.find(Customer.class).where()
- * // pass the bean into the where() clause
- *     .exampleLike(example)
- *     // you can add other expressions to the same query
- *     .gt("id", 2).findList();
- * 
- * 
+ * example.setName("Rob%"); + * example.setNotes("%something%"); + * + * List list = Ebean.find(Customer.class) + * .where() + * .exampleLike(example) + * .findList(); + * + * }
*/ public class DefaultExampleExpression implements SpiExpression, ExampleExpression { @@ -71,13 +69,10 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio /** * Construct the query by example expression. - * - * @param entity - * the example entity with non null property values - * @param caseInsensitive - * if true use case insensitive expressions - * @param likeType - * the type of Like wild card used + * + * @param entity the example entity with non null property values + * @param caseInsensitive if true use case insensitive expressions + * @param likeType the type of Like wild card used */ public DefaultExampleExpression(EntityBean entity, boolean caseInsensitive, LikeType likeType) { this.entity = entity; @@ -104,6 +99,12 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio } } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public SpiExpression copyForPlanKey() { return new DefaultExampleExpression(list); @@ -295,9 +296,9 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio } } else if ((beanProperty instanceof BeanPropertyAssocOne) && (value instanceof EntityBean)) { - BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne)beanProperty; + BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne) beanProperty; BeanDescriptor targetDescriptor = assocOne.getTargetDescriptor(); - addExpressions(list, targetDescriptor, (EntityBean)value, propName); + addExpressions(list, targetDescriptor, (EntityBean) value, propName); } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index 63ae797fe..2d6f3e033 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -204,6 +204,12 @@ public class DefaultExpressionList implements SpiExpressionList { return copy; } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + /** * Return true if one of the expressions is related to a Many property. */ @@ -1027,4 +1033,11 @@ public class DefaultExpressionList implements SpiExpressionList { public void prepareDocNested(BeanDescriptor beanDescriptor) { PrepareDocNested.prepare(this, beanDescriptor); } + + public Object idEqualTo(String idName) { + if (list.size() == 1) { + return list.get(0).getIdEqualTo(idName); + } + return null; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsQueryExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsQueryExpression.java index a34110abf..fdc8467a2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsQueryExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/ExistsQueryExpression.java @@ -41,6 +41,12 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress throw new IllegalStateException("Not supported"); } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public void prepareExpression(BeanQueryRequest request) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 55fa7ce29..3736665cc 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -80,6 +80,12 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression context.endBoolGroupList(); } + @Override + public Object getIdEqualTo(String idName) { + // always null for this expression + return null; + } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java index 3efb7cb65..86074d3f8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/LogicExpression.java @@ -88,6 +88,12 @@ abstract class LogicExpression implements SpiExpression { return null; } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public void containsMany(BeanDescriptor desc, ManyWhereJoins manyWhereJoin) { expOne.containsMany(desc, manyWhereJoin); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NestedPathWrapperExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NestedPathWrapperExpression.java index 92a730a20..2f67b008a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NestedPathWrapperExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NestedPathWrapperExpression.java @@ -31,6 +31,12 @@ class NestedPathWrapperExpression implements SpiExpression { context.endNested(); } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public String nestedPath(BeanDescriptor desc) { return nestedPath; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java index 40dc0b66d..aa8e33b46 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NonPrepareExpression.java @@ -13,6 +13,12 @@ abstract class NonPrepareExpression implements SpiExpression { // do nothing } + @Override + public Object getIdEqualTo(String idName) { + // always null in this expression + return null; + } + @Override public SpiExpression copyForPlanKey() { return this; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java index e771e7916..813ccf244 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NoopExpression.java @@ -26,6 +26,12 @@ class NoopExpression implements SpiExpression { public void writeDocQuery(DocQueryContext context) throws IOException { } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public String nestedPath(BeanDescriptor desc) { return null; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java index 4024a43c9..b5945927f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/NotExpression.java @@ -29,6 +29,12 @@ final class NotExpression implements SpiExpression { context.endBool(); } + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + @Override public SpiExpression copyForPlanKey() { return new NotExpression(exp.copyForPlanKey()); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java index 7cfe71ec6..044b446e6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/SimpleExpression.java @@ -21,6 +21,14 @@ public class SimpleExpression extends AbstractExpression { this.value = value; } + @Override + public Object getIdEqualTo(String idName) { + if (type == Op.EQ && idName.equals(propName)) { + return value; + } + return null; + } + @Override public void writeDocQuery(DocQueryContext context) throws IOException { if (type == Op.BETWEEN) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index aea04264f..ec89dbbff 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -236,6 +236,16 @@ public class DefaultOrmQuery implements SpiQuery { return beanDescriptor; } + @Override + public void checkIdEqualTo() { + if (id == null && whereExpressions != null) { + id = whereExpressions.idEqualTo(beanDescriptor.getIdName()); + if (id != null) { + whereExpressions = null; + } + } + } + @Override public boolean isAutoTunable() { return beanDescriptor.isAutoTunable(); 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 d3016e706..43c8770e8 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java @@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.querydefn; import com.avaje.ebean.Ebean; -import com.avaje.ebean.FetchConfig; import com.avaje.tests.model.basic.Order; import org.junit.Test; @@ -10,6 +9,28 @@ import static org.assertj.core.api.Assertions.assertThat; public class DefaultOrmQueryTest { + @Test + public void checkForId_when_eqId_then_translatedTo_setId() { + + DefaultOrmQuery q1 = (DefaultOrmQuery)Ebean.find(Order.class).where().eq("id", 42).query(); + assertThat(q1.getWhereExpressions()).isNotNull(); + assertThat(q1.getId()).isNull(); + + q1.checkIdEqualTo(); + + assertThat(q1.getId()).isEqualTo(42); + assertThat(q1.getWhereExpressions()).isNull(); + } + + @Test + public void checkForId_when_idEq_ok() { + + DefaultOrmQuery q1 = (DefaultOrmQuery)Ebean.find(Order.class).where().idEq(42).query(); + assertThat(q1.getId()).isEqualTo(42); + q1.checkIdEqualTo(); + assertThat(q1.getId()).isEqualTo(42); + } + @Test public void when_addWhere_then_planChanges() {