createPathMap(String prefix, BeanDescriptor> desc) {
BeanPropertyAssocMany>[] manys = desc.propertiesMany();
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
index ae5862267..2a7fd0cfb 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.api.SpiQuery;
+import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
@@ -55,6 +56,11 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
// nothing to do here
}
+ @Override
+ public BeanProperty getSingleProperty() {
+ throw new IllegalStateException("No expected");
+ }
+
/**
* Return true if the extra join is a many join.
*
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
index 46c793428..b3c390761 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.api.SpiQuery;
+import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
@@ -39,6 +40,11 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
this.parentPrefix = split[0];
}
+ @Override
+ public BeanProperty getSingleProperty() {
+ throw new IllegalStateException("No expected");
+ }
+
@Override
public void addAsOfTableAlias(SpiQuery> query) {
// do nothing here ...
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 24bdea098..b3d3622db 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -192,6 +192,8 @@ public class DefaultOrmQuery implements SpiQuery {
*/
private boolean forUpdate;
+ private boolean singleAttribute;
+
/**
* Set to true if this query has been tuned by autoTune.
*/
@@ -534,6 +536,26 @@ public class DefaultOrmQuery implements SpiQuery {
select(beanDescriptor.getIdBinder().getIdProperty());
}
+ @Override
+ public void setSingleAttribute() {
+ this.singleAttribute = true;
+ }
+
+ /**
+ * Return true if this is a single attribute query.
+ */
+ public boolean isSingleAttribute() {
+ return singleAttribute;
+ }
+
+ /**
+ * Return true if the Id should be included in the query.
+ */
+ @Override
+ public boolean isWithId() {
+ return !distinct && !singleAttribute;
+ }
+
@Override
public NaturalKeyBindParam getNaturalKeyBindParam() {
NaturalKeyBindParam namedBind = null;
@@ -1133,6 +1155,11 @@ public class DefaultOrmQuery implements SpiQuery {
return (Map) findMap();
}
+ @Override
+ public List findSingleAttributeList() {
+ return (List)server.findSingleAttributeList(this, null);
+ }
+
@Override
public T findUnique() {
return server.findUnique(this, null);
diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
index 345a4472f..030abb658 100644
--- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
+++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
@@ -520,6 +520,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return null;
}
+ @Override
+ public List findSingleAttributeList(Query> query, Transaction transaction) {
+ return null;
+ }
+
@Override
public T findUnique(Query query, Transaction transaction) {
return null;
diff --git a/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java b/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java
new file mode 100644
index 000000000..7fddbceb3
--- /dev/null
+++ b/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java
@@ -0,0 +1,128 @@
+package com.avaje.tests.query.other;
+
+import com.avaje.ebean.BaseTestCase;
+import com.avaje.ebean.Ebean;
+import com.avaje.ebean.Query;
+import com.avaje.tests.model.basic.Customer;
+import com.avaje.tests.model.basic.ResetBasicData;
+import org.junit.Test;
+
+import java.sql.Date;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestQuerySingleAttribute extends BaseTestCase {
+
+
+ @Test
+ public void exampleUsage() {
+
+ ResetBasicData.reset();
+
+ List names =
+ Ebean.find(Customer.class)
+ .setDistinct(true)
+ .select("name")
+ .where().eq("status", Customer.Status.NEW)
+ .orderBy().asc("name")
+ .setMaxRows(100)
+ .findSingleAttributeList();
+
+ assertThat(names).isNotNull();
+ }
+
+ @Test
+ public void exampleUsage_otherType() {
+
+ ResetBasicData.reset();
+
+ List dates =
+ Ebean.find(Customer.class)
+ .setDistinct(true)
+ .select("anniversary")
+ .where().isNotNull("anniversary")
+ .orderBy().asc("anniversary")
+ .findSingleAttributeList();
+
+ assertThat(dates).isNotNull();
+ }
+
+ @Test
+ public void withOrderBy() {
+
+ Query query =
+ Ebean.find(Customer.class)
+ .setDistinct(true)
+ .select("name")
+ .where().eq("status", Customer.Status.NEW)
+ .orderBy().asc("name")
+ .setMaxRows(100);
+
+ query.findSingleAttributeList();
+ assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 where t0.status = ? order by t0.name ");
+ }
+
+ @Test
+ public void basic() {
+
+ ResetBasicData.reset();
+
+ Query query = Ebean.find(Customer.class).select("name");
+
+ List names = query.findSingleAttributeList();//String.class);
+
+ assertThat(query.getGeneratedSql()).contains("select t0.name c0 from o_customer t0");
+ assertThat(names).isNotNull();
+ }
+
+ @Test
+ public void distinctAndWhere() {
+
+ ResetBasicData.reset();
+
+ Query query = Ebean.find(Customer.class)
+ .setDistinct(true)
+ .select("name")
+ .where().eq("status", Customer.Status.NEW)
+ .query();
+
+ List names = query.findSingleAttributeList();
+
+ assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 where t0.status = ? ");
+ assertThat(names).isNotNull();
+ }
+
+ @Test
+ public void distinctWhereWithJoin() {
+
+ ResetBasicData.reset();
+
+ Query query = Ebean.find(Customer.class)
+ .setDistinct(true)
+ .select("name")
+ .where().eq("status", Customer.Status.NEW)
+ .istartsWith("billingAddress.city", "auck")
+ .query();
+
+ List names = query.findSingleAttributeList();
+
+ assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 left outer join o_address t1 on t1.id = t0.billing_address_id where t0.status = ? and lower(t1.city) like ?");
+ assertThat(names).isNotNull();
+ }
+
+
+ @Test
+ public void queryPlan_expect_differentPlans() {
+
+ ResetBasicData.reset();
+
+ Query query = Ebean.find(Customer.class).select("name");
+ query.findSingleAttributeList();
+ assertThat(query.getGeneratedSql()).contains("select t0.name c0 from o_customer t0");
+
+ Query query2 = Ebean.find(Customer.class).select("name");
+ query2.findList();
+ assertThat(query2.getGeneratedSql()).contains("select t0.id c0, t0.name c1 from o_customer t0");
+ }
+}