mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 21:15:52 +00:00
Merge branch 'Tests-for-Queries-With-Formula-Properties' of https://github.com/FOCONIS/ebean into FOCONIS-Tests-for-Queries-With-Formula-Properties
This commit is contained in:
@@ -7,7 +7,9 @@ import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@@ -21,9 +23,7 @@ public class ManyWhereJoins implements Serializable {
|
||||
|
||||
private final TreeMap<String, PropertyJoin> joins = new TreeMap<>();
|
||||
|
||||
private StringBuilder formulaProperties = new StringBuilder();
|
||||
|
||||
private boolean formulaWithJoin;
|
||||
private List<String> formulaJoinProperties;
|
||||
|
||||
private boolean aggregation;
|
||||
|
||||
@@ -125,27 +125,24 @@ public class ManyWhereJoins implements Serializable {
|
||||
* specifically for the findCount query.
|
||||
*/
|
||||
public void addFormulaWithJoin(String propertyName) {
|
||||
if (formulaWithJoin) {
|
||||
formulaProperties.append(",");
|
||||
} else {
|
||||
formulaProperties = new StringBuilder();
|
||||
formulaWithJoin = true;
|
||||
if (formulaJoinProperties == null) {
|
||||
formulaJoinProperties = new ArrayList<>();
|
||||
}
|
||||
formulaProperties.append(propertyName);
|
||||
formulaJoinProperties.add(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query select includes a formula with join.
|
||||
*/
|
||||
public boolean isFormulaWithJoin() {
|
||||
return formulaWithJoin;
|
||||
return formulaJoinProperties != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the formula properties to build the select clause for a findCount query.
|
||||
*/
|
||||
public String getFormulaProperties() {
|
||||
return formulaProperties.toString();
|
||||
public List<String> getFormulaJoinProperties() {
|
||||
return formulaJoinProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,8 +136,7 @@ public class ElPropertyChain implements ElPropertyValue {
|
||||
|
||||
@Override
|
||||
public boolean containsFormulaWithJoin() {
|
||||
// Not cascading the check at this stage
|
||||
return false;
|
||||
return lastBeanProperty.containsFormulaWithJoin();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -265,7 +265,9 @@ class CQueryBuilder {
|
||||
if (!countDistinct) {
|
||||
// minimise select clause for standard count
|
||||
if (manyWhereJoins.isFormulaWithJoin()) {
|
||||
query.select(manyWhereJoins.getFormulaProperties());
|
||||
// FIXME: we join the strings here and on the other side we split them again
|
||||
// this is not yet optimal
|
||||
query.select(String.join(",",manyWhereJoins.getFormulaJoinProperties()));
|
||||
} else {
|
||||
query.setSelectId();
|
||||
}
|
||||
|
||||
@@ -296,6 +296,13 @@ public final class SqlTreeBuilder {
|
||||
SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp.getProperty(), beanProperty, joinProp.getSqlJoinType());
|
||||
myJoinList.add(nodeJoin);
|
||||
}
|
||||
if (manyWhereJoins.isFormulaWithJoin()) {
|
||||
for (String property: manyWhereJoins.getFormulaJoinProperties()) {
|
||||
STreeProperty beanProperty = desc.findPropertyFromPath(property);
|
||||
SqlTreeNodeFormulaWhereJoin nodeJoin = new SqlTreeNodeFormulaWhereJoin(beanProperty, SqlJoinType.OUTER);
|
||||
myJoinList.add(nodeJoin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> myList, SqlTreeProperties props) {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.Version;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.deploy.DbReadContext;
|
||||
import io.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Join to Many (or child of a many) to support where clause predicates on many properties.
|
||||
*/
|
||||
class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode {
|
||||
|
||||
private final STreeProperty nodeBeanProp;
|
||||
|
||||
/**
|
||||
* The many where join which is either INNER or OUTER.
|
||||
*/
|
||||
private final SqlJoinType manyJoinType;
|
||||
|
||||
SqlTreeNodeFormulaWhereJoin(STreeProperty prop, SqlJoinType manyJoinType) {
|
||||
this.nodeBeanProp = prop;
|
||||
this.manyJoinType = manyJoinType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleProperty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getSingleAttributeReader() {
|
||||
throw new IllegalStateException("No expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAsOfTableAlias(SpiQuery<?> query) {
|
||||
// do nothing here ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSoftDeletePredicate(SpiQuery<?> query) {
|
||||
// do nothing here ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAggregation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDistinctOn(DbSqlContext ctx, boolean subQuery) {
|
||||
// do nothing here ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendGroupBy(DbSqlContext ctx, boolean subQuery) {
|
||||
// do nothing here
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the FROM clause for this node.
|
||||
*/
|
||||
@Override
|
||||
public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
|
||||
|
||||
// always use the join type as per this many where join
|
||||
// (OUTER for disjunction and otherwise INNER)
|
||||
nodeBeanProp.appendFrom(ctx, manyJoinType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void dependentTables(Set<String> tables) {
|
||||
//FIXME: we cannot easily determine the dependent tables, this would require an enhancement
|
||||
//of the @Formula(dependentTables=...) annotation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildRawSqlSelectChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendWhere(DbSqlContext ctx) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
|
||||
// nothing to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Version<T> loadVersion(DbReadContext ctx) {
|
||||
// nothing to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMany() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package org.tests.query.joins;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.family.ChildPerson;
|
||||
import org.tests.model.family.ParentPerson;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestQueryJoinOnFormula extends BaseTestCase {
|
||||
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
ResetBasicData.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OrderFindIds() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<Integer> orderIds = Ebean.find(Order.class)
|
||||
.where().eq("totalItems", 3)
|
||||
.findIds();
|
||||
assertThat(orderIds).hasSize(2);
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql.get(0)).contains("join (select order_id, count(*) as total_items,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OrderFindList() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<Order> orders = Ebean.find(Order.class)
|
||||
.where().eq("totalItems", 3)
|
||||
.findList();
|
||||
assertThat(orders).hasSize(2);
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql.get(0)).contains("join (select order_id, count(*) as total_items,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OrderFindCount() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
int orders = Ebean.find(Order.class)
|
||||
.where().eq("totalItems", 3)
|
||||
.findCount();
|
||||
assertThat(orders).isEqualTo(2);
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql.get(0)).contains("join (select order_id, count(*) as total_items,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OrderFindSingleAttributeList() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<Date> orderDates = Ebean.find(Order.class)
|
||||
.select("orderDate")
|
||||
.where().eq("totalItems", 3)
|
||||
.findSingleAttributeList();
|
||||
assertThat(orderDates).hasSize(2);
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql.get(0)).contains("join (select order_id, count(*) as total_items,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OrderFindOne() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Order order = Ebean.find(Order.class)
|
||||
.select("totalItems")
|
||||
.where().eq("totalItems", 3)
|
||||
.setMaxRows(1)
|
||||
.orderById(true)
|
||||
.findOne();
|
||||
|
||||
assertThat(order.getTotalItems()).isEqualTo(3);
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
assertThat(loggedSql.get(0)).contains("join (select order_id, count(*) as total_items,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ParentPersonFindIds() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<ParentPerson> orderIds = Ebean.find(ParentPerson.class)
|
||||
.where().eq("totalAge", 3)
|
||||
.findIds();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ParentPersonFindList() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ParentPerson.class)
|
||||
.select("identifier")
|
||||
//.where().eq("totalAge", 3)
|
||||
.where().eq("familyName", "foo")
|
||||
.findList();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ParentPersonFindCount() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ParentPerson.class)
|
||||
.where().eq("totalAge", 3)
|
||||
.findCount();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ParentPersonFindSingleAttributeList() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ParentPerson.class)
|
||||
.select("address") // .select("address, totalAge") would work
|
||||
.where().eq("totalAge", 3)
|
||||
.findSingleAttributeList();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ParentPersonFindOne() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ParentPerson.class)
|
||||
.where().eq("totalAge", 3)
|
||||
.setMaxRows(1)
|
||||
.orderById(true)
|
||||
.findOne();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ChildPersonParentFindIds() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ChildPerson.class)
|
||||
.where().eq("parent.totalAge", 3)
|
||||
.findIds();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ChildPersonParentFindCount() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(ChildPerson.class)
|
||||
.where().eq("parent.totalAge", 3)
|
||||
.findCount();
|
||||
// TODO: There are no beans in database, so for now only the query must run.
|
||||
|
||||
List<String> loggedSql = LoggedSqlCollector.stop();
|
||||
assertEquals(1, loggedSql.size());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user