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 47b2415d7..c21867998 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpression.java @@ -14,6 +14,8 @@ 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; /** * A "Query By Example" type of expression. @@ -207,25 +209,41 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio OrmQueryRequest r = (OrmQueryRequest) request; BeanDescriptor beanDescriptor = r.getBeanDescriptor(); - for (BeanProperty beanProperty : beanDescriptor.propertiesAll()) { - - String propName = beanProperty.getName(); - Object value = beanProperty.getValue(entity); + addExpressions(list, beanDescriptor, entity, null); - if (beanProperty.isScalar() && value != null) { - if (value instanceof String) { - list.add(new LikeExpression(propName, (String) value, caseInsensitive, likeType)); - } else { - // exclude the zero values typically to weed out - // primitive int and long that initialise to 0 - if (includeZeros || !isZero(value)) { - list.add(new SimpleExpression(propName, Op.EQ, value)); + return list; + } + + /** + * Add expressions to the list for all the non-null properties (and do this recursively). + */ + private void addExpressions(ArrayList list, BeanDescriptor beanDescriptor, EntityBean bean, String prefix) { + + for (BeanProperty beanProperty : beanDescriptor.propertiesAll()) { + + if (!beanProperty.isTransient()) { + Object value = beanProperty.getValue(bean); + if (value != null) { + String propName = SplitName.add(prefix, beanProperty.getName()); + if (beanProperty.isScalar()) { + if (value instanceof String) { + list.add(new LikeExpression(propName, (String) value, caseInsensitive, likeType)); + } else { + // exclude the zero values typically to weed out + // primitive int and long that initialise to 0 + if (includeZeros || !isZero(value)) { + list.add(new SimpleExpression(propName, Op.EQ, value)); + } + } + + } else if ((beanProperty instanceof BeanPropertyAssocOne) && (value instanceof EntityBean)) { + BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne)beanProperty; + BeanDescriptor targetDescriptor = assocOne.getTargetDescriptor(); + addExpressions(list, targetDescriptor, (EntityBean)value, propName); } } } } - - return list; } /** diff --git a/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java b/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java new file mode 100644 index 000000000..978785305 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/expression/DefaultExampleExpressionTest.java @@ -0,0 +1,72 @@ +package com.avaje.ebeaninternal.server.expression; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.LikeType; +import com.avaje.ebean.Query; +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.event.BeanQueryRequest; +import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; +import com.avaje.ebeaninternal.api.SpiEbeanServer; +import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.server.core.OrmQueryRequest; +import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; +import com.avaje.tests.model.basic.Address; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class DefaultExampleExpressionTest extends BaseTestCase { + + + @Test + public void test() { + + SpiEbeanServer server = (SpiEbeanServer)Ebean.getDefaultServer(); + BeanDescriptor desc = server.getBeanDescriptor(Customer.class); + + SpiQuery query = (SpiQuery)server.find(Customer.class); + + Address address = new Address(); + address.setCity("billingAddress.city"); + + Customer customer = new Customer(); + customer.setName("name"); + customer.setBillingAddress(address); + + + DefaultExampleExpression expr = new DefaultExampleExpression((EntityBean)customer, false, LikeType.EQUAL_TO); + + + BeanQueryRequest request = create(query, desc); + HashQueryPlanBuilder builder = new HashQueryPlanBuilder(); + expr.queryPlanHash(request, builder); + + TDSpiExpressionRequest req = new TDSpiExpressionRequest(desc); + expr.addBindValues(req); + + assertThat(req.bindValues).contains("name", "billingAddress.city"); + + address.setCity("Auckland"); + customer.setName("Rob"); + + ResetBasicData.reset(); + + Query query1 = server.find(Customer.class) + .where().exampleLike(customer) + .query(); + + query1.findList(); + + assertThat(query1.getGeneratedSql()).contains("(t0.name like ? and t1.city like ? )"); + + } + + private OrmQueryRequest create(SpiQuery query, BeanDescriptor desc) { + return new OrmQueryRequest(null, null, query, desc, null); + } + +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/src/test/java/com/avaje/ebeaninternal/server/expression/TDSpiExpressionRequest.java new file mode 100644 index 000000000..478897e38 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -0,0 +1,78 @@ +package com.avaje.ebeaninternal.server.expression; + +import com.avaje.ebeaninternal.api.SpiExpressionRequest; +import com.avaje.ebeaninternal.server.core.JsonExpressionHandler; +import com.avaje.ebeaninternal.server.core.SpiOrmQueryRequest; +import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test double for testing with SpiExpressionRequest. + */ +public class TDSpiExpressionRequest implements SpiExpressionRequest { + + List bindValues = new ArrayList(); + + final BeanDescriptor descriptor; + + public TDSpiExpressionRequest(BeanDescriptor descriptor) { + this.descriptor = descriptor; + } + + @Override + public JsonExpressionHandler getJsonHandler() { + return null; + } + + @Override + public String parseDeploy(String logicalProp) { + return null; + } + + @Override + public BeanDescriptor getBeanDescriptor() { + return descriptor; + } + + @Override + public SpiOrmQueryRequest getQueryRequest() { + return null; + } + + @Override + public SpiExpressionRequest append(String sql) { + return null; + } + + @Override + public void addBindEncryptKey(Object encryptKey) { + + } + + @Override + public void addBindValue(Object bindValue) { + bindValues.add(bindValue); + } + + @Override + public String getSql() { + return null; + } + + @Override + public ArrayList getBindValues() { + return null; + } + + @Override + public int nextParameter() { + return 0; + } + + @Override + public void appendLike() { + + } +}