Merge branch 'feature/1186-MultiValueBind'

This commit is contained in:
rob bygrave
2017-10-31 22:11:30 +13:00
54 changed files with 817 additions and 168 deletions
+34 -2
View File
@@ -3,15 +3,20 @@ package io.ebean;
import io.ebean.annotation.Platform;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.HelpCreateQueryRequest;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import org.tests.model.basic.Country;
import org.avaje.agentloader.AgentLoader;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tests.model.basic.Country;
import java.sql.Types;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(ConditionalTestRunner.class)
public abstract class BaseTestCase {
@@ -81,7 +86,7 @@ public abstract class BaseTestCase {
public boolean isDb2() {
return Platform.DB2 == platform();
}
public boolean isPostgres() {
return Platform.POSTGRES == platform();
}
@@ -127,4 +132,31 @@ public abstract class BaseTestCase {
.setLoadBeanCache(true)
.findList();
}
/**
* Platform specific IN clause assert.
*/
protected void platformAssertIn(String sql, String containsIn) {
if (isPostgres()) {
assertThat(sql).contains(containsIn+" = any(");
} else {
assertThat(sql).contains(containsIn+" in ");
}
// H2 contains("where t0.name in (select * from table(x varchar = ?)");
}
/**
* Platform specific NOT IN clause assert.
*/
protected void platformAssertNotIn(String sql, String containsIn) {
if (isPostgres()) {
assertThat(sql).contains(containsIn+" != all(");
} else {
assertThat(sql).contains(containsIn+" not in ");
}
}
protected <T> OrmQueryRequest<T> createQueryRequest(SpiQuery.Type type, Query<T> query, Transaction t) {
return HelpCreateQueryRequest.create(server(), type, query, t);
}
}
@@ -1,8 +1,8 @@
package io.ebean;
import org.tests.model.basic.EBasicVer;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.basic.EBasicVer;
import java.util.ArrayList;
import java.util.List;
@@ -29,7 +29,7 @@ public class EbeanServer_deleteAllByIdTest extends BaseTestCase {
List<String> loggedSql = LoggedSqlCollector.stop();
assertThat(loggedSql).hasSize(1);
assertThat(loggedSql.get(0)).contains("delete from e_basicver where id in (?,?,?)");
platformAssertIn(loggedSql.get(0), "delete from e_basicver where id ");
}
@Test
@@ -55,7 +55,7 @@ public class EbeanServer_deleteAllByIdTest extends BaseTestCase {
}
List<String> loggedSql = LoggedSqlCollector.stop();
assertThat(loggedSql).hasSize(1);
assertThat(loggedSql.get(0)).contains("delete from e_basicver where id in (?,?,?)");
platformAssertIn(loggedSql.get(0), "delete from e_basicver where id ");
}
@Test
@@ -75,7 +75,7 @@ public class EbeanServer_deleteAllByIdTest extends BaseTestCase {
List<String> loggedSql = LoggedSqlCollector.stop();
assertThat(loggedSql).hasSize(1);
assertThat(loggedSql.get(0)).contains("delete from e_basicver where id in (?,?,?)");
platformAssertIn(loggedSql.get(0), "delete from e_basicver where id ");
}
@@ -102,7 +102,7 @@ public class EbeanServer_deleteAllByIdTest extends BaseTestCase {
}
List<String> loggedSql = LoggedSqlCollector.stop();
assertThat(loggedSql).hasSize(1);
assertThat(loggedSql.get(0)).contains("delete from e_basicver where id in (?,?,?)");
platformAssertIn(loggedSql.get(0), "delete from e_basicver where id ");
}
private List<EBasicVer> beans(int count) {
@@ -0,0 +1,15 @@
package io.ebeaninternal.server.core;
import io.ebean.EbeanServer;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebeaninternal.api.SpiQuery;
public class HelpCreateQueryRequest {
public static <T> OrmQueryRequest<T> create(EbeanServer server, SpiQuery.Type type, Query<T> query, Transaction t) {
DefaultServer defaultServer = (DefaultServer) server;
return (OrmQueryRequest<T>)defaultServer.createQueryRequest(type, query, t);
}
}
@@ -28,7 +28,7 @@ public class IdInExpressionTest extends BaseExpressionTest {
}
@Test
public void isSameByPlan_when_diffBindCount() {
public void isSameByPlan_when_diffBindCount_notPrepared() {
different(exp(10), exp(10, 20));
}
@@ -1,6 +1,11 @@
package io.ebeaninternal.server.expression;
import io.ebean.EbeanServer;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.event.BeanQueryRequest;
import org.junit.Test;
import org.tests.model.basic.Customer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -10,6 +15,19 @@ import static org.assertj.core.api.StrictAssertions.assertThat;
public class InExpressionTest extends BaseExpressionTest {
/**
* Request with Multi-Value support.
*/
private TDQueryRequest<Customer> multi() {
return MULTI_VALUE;
}
/**
* Request with NO Multi-Value support.
*/
private TDQueryRequest<Customer> noMulti() {
return NO_MULTI_VALUE;
}
@Test
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() throws Exception {
@@ -19,8 +37,8 @@ public class InExpressionTest extends BaseExpressionTest {
InExpression ex1 = new InExpression("foo", values, false);
InExpression ex2 = new InExpression("bar", values, false);
ex1.prepareExpression(null);
ex2.prepareExpression(null);
ex1.prepareExpression(multi());
ex2.prepareExpression(multi());
different(ex1, ex2);
}
@@ -34,12 +52,25 @@ public class InExpressionTest extends BaseExpressionTest {
InExpression ex1 = new InExpression("foo", values1, false);
InExpression ex2 = new InExpression("foo", values2, false);
ex1.prepareExpression(null);
ex2.prepareExpression(null);
ex1.prepareExpression(noMulti());
ex2.prepareExpression(noMulti());
different(ex1, ex2);
}
@Test
public void queryPlanHash_given_diffBindCount_withMultiSupport_samePlanHash() throws Exception {
List<Integer> values1 = values(42, 92);
List<Integer> values2 = values(42, 92, 82);
InExpression ex1 = new InExpression("foo", values1, false);
InExpression ex2 = new InExpression("foo", values2, false);
ex1.prepareExpression(multi());
ex2.prepareExpression(multi());
same(ex1, ex2);
}
@Test
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() throws Exception {
@@ -48,8 +79,8 @@ public class InExpressionTest extends BaseExpressionTest {
InExpression ex1 = new InExpression("foo", values, true);
InExpression ex2 = new InExpression("foo", values, false);
ex1.prepareExpression(null);
ex2.prepareExpression(null);
ex1.prepareExpression(multi());
ex2.prepareExpression(multi());
different(ex1, ex2);
}
@@ -62,8 +93,8 @@ public class InExpressionTest extends BaseExpressionTest {
InExpression ex1 = new InExpression("foo", values, true);
InExpression ex2 = new InExpression("foo", values, true);
ex1.prepareExpression(null);
ex2.prepareExpression(null);
ex1.prepareExpression(multi());
ex2.prepareExpression(multi());
same(ex1, ex2);
}
@@ -78,7 +109,13 @@ public class InExpressionTest extends BaseExpressionTest {
private InExpression exp(String propName, boolean not, Object... values) {
InExpression ex = new InExpression(propName, Arrays.asList(values), not);
ex.prepareExpression(null);
ex.prepareExpression(multi());
return ex;
}
private InExpression expNoMulti(String propName, boolean not, Object... values) {
InExpression ex = new InExpression(propName, Arrays.asList(values), not);
ex.prepareExpression(noMulti());
return ex;
}
@@ -103,13 +140,15 @@ public class InExpressionTest extends BaseExpressionTest {
@Test
public void isSameByPlan_when_diffBind_same() {
different(exp("a", false, 10), exp("a", false, 10, 20));
same(exp("a", false, 10), exp("a", false, 10, 20));
different(expNoMulti("a", false, 10), expNoMulti("a", false, 10, 20));
}
@Test
public void isSameByPlan_when_diffBindCount() {
different(exp("a", false, 10), exp("a", false, 10, 20));
same(exp("a", false, 10), exp("a", false, 10, 20));
different(expNoMulti("a", false, 10), expNoMulti("a", false, 10, 20));
}
@Test
@@ -142,4 +181,42 @@ public class InExpressionTest extends BaseExpressionTest {
assertThat(exp("a", false, 10, "ABC").isSameByBind(exp("a", false, 10, "ABC", 30))).isFalse();
}
private static final TDQueryRequest<Customer> MULTI_VALUE= new TDQueryRequest<>(true);
private static final TDQueryRequest<Customer> NO_MULTI_VALUE = new TDQueryRequest<>(false);
static class TDQueryRequest<T> implements BeanQueryRequest<T> {
final boolean supported;
TDQueryRequest(boolean supported) {
this.supported = supported;
}
@Override
public EbeanServer getEbeanServer() {
return null;
}
@Override
public Transaction getTransaction() {
return null;
}
@Override
public Query<T> getQuery() {
return null;
}
@Override
public boolean isMultiValueIdSupported() {
return supported;
}
@Override
public boolean isMultiValueSupported(Class<?> valueType) {
return supported;
}
}
}
@@ -78,9 +78,14 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest {
public void appendLike() {
}
@Override
public String escapeLikeString(String value) {
return value;
}
@Override
public void appendInExpression(boolean not, Object[] bindValues) {
}
}
@@ -4,9 +4,9 @@ import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Query;
import io.ebeaninternal.api.SpiQuery;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
@@ -167,7 +167,7 @@ public class EqlParserTest extends BaseTestCase {
Query<Customer> query = parse("where name in ('Rob','Jim')");
query.findList();
assertThat(query.getGeneratedSql()).contains("where t0.name in (?, ? )");
platformAssertIn(query.getGeneratedSql(),"where t0.name");
}
@Test
@@ -178,7 +178,7 @@ public class EqlParserTest extends BaseTestCase {
query.setParameter("two", "Bar");
query.findList();
assertThat(query.getGeneratedSql()).contains("where t0.name in (?, ? )");
platformAssertIn(query.getGeneratedSql(),"where t0.name");
}
@Test
@@ -189,7 +189,7 @@ public class EqlParserTest extends BaseTestCase {
query.setParameter("two", "Bar");
query.findList();
assertThat(query.getGeneratedSql()).contains("where t0.name in (?, ? )");
platformAssertIn(query.getGeneratedSql(),"where t0.name");
}
@Test
@@ -200,7 +200,7 @@ public class EqlParserTest extends BaseTestCase {
query.setParameter("two", "Bar");
query.findList();
assertThat(query.getGeneratedSql()).contains("where t0.name in (?, ? )");
platformAssertIn(query.getGeneratedSql(),"where t0.name");
}
@Test
@@ -210,7 +210,7 @@ public class EqlParserTest extends BaseTestCase {
query.setParameter("names", Arrays.asList("Baz", "Maz", "Jim"));
query.findList();
assertThat(query.getGeneratedSql()).contains("where t0.name in (?, ?, ? )");
platformAssertIn(query.getGeneratedSql(),"where t0.name");
}
@Test
@@ -3,9 +3,11 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -91,7 +93,11 @@ public class DefaultOrmQueryTest extends BaseTestCase {
}
private void prepare(DefaultOrmQuery<?> q1, DefaultOrmQuery<?> q2) {
q1.prepare(null);
q2.prepare(null);
OrmQueryRequest<?> r1 = createQueryRequest(SpiQuery.Type.LIST, q1, null);
q1.prepare(r1);
OrmQueryRequest<?> r2 = createQueryRequest(SpiQuery.Type.LIST, q2, null);
q2.prepare(r2);
}
}
@@ -79,7 +79,7 @@ public class TestBatchLazyWithCacheHits extends BaseTestCase {
// batch lazy loading into cache
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("from uuone t0 where t0.name like ");
assertThat(sql.get(1)).contains("from uuone t0 where t0.id in (?,");
platformAssertIn(sql.get(1), "from uuone t0 where t0.id");
statistics = beanCache.getStatistics(true);
assertThat(statistics.getSize()).isGreaterThan(3);
@@ -36,7 +36,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
String secondaryQuery = trimSql(loggedSql.get(1), 1);
assertThat(secondaryQuery).contains("select t0.order_id, t0.id,");
assertThat(secondaryQuery).contains(" from o_order_detail t0 left join o_product t1");
assertThat(secondaryQuery).contains(" (t0.order_id) in (?");
platformAssertIn(secondaryQuery, " (t0.order_id)");
assertThat(secondaryQuery).contains(" order by t0.order_id, t0.id");
}
@@ -63,7 +63,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
String secondaryQuery = trimSql(loggedSql.get(1), 1);
assertThat(secondaryQuery).contains("select t0.order_id, t0.id,");
assertThat(secondaryQuery).contains(" from o_order_detail t0 left join o_product t1");
assertThat(secondaryQuery).contains(" (t0.order_id) in (?");
platformAssertIn(secondaryQuery, " (t0.order_id)");
assertThat(secondaryQuery).contains(" order by t0.order_id, t0.id");
}
@@ -103,7 +103,7 @@ public class TestQueryJoinToAssocOne extends BaseTestCase {
String secondaryQuery = trimSql(loggedSql.get(1), 1);
assertThat(secondaryQuery).contains("select t0.order_id, t0.id,");
assertThat(secondaryQuery).contains(" from o_order_detail t0 left join o_product t1");
assertThat(secondaryQuery).contains(" (t0.order_id) in (?");
platformAssertIn(secondaryQuery, " (t0.order_id)");
assertThat(secondaryQuery).contains(" order by t0.order_id, t0.id");
}
@@ -36,7 +36,8 @@ public class TestSecondaryQueries extends BaseTestCase {
assertThat(sql).hasSize(2);
assertThat(trimSql(sql.get(0), 2)).contains("select t0.id, t0.status, t0.kcustomer_id from o_order t0");
assertThat(trimSql(sql.get(1), 2)).contains("select t0.id, t0.name from o_customer t0 where t0.id in");
assertThat(trimSql(sql.get(1), 2)).contains("select t0.id, t0.name from o_customer t0 where t0.id");
platformAssertIn(sql.get(1), " where t0.id");
}
@Test
@@ -71,7 +72,8 @@ public class TestSecondaryQueries extends BaseTestCase {
sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
assertThat(trimSql(sql.get(0), 1)).contains("select t0.id, t0.name from o_customer t0 where t0.id in");
assertThat(trimSql(sql.get(0), 1)).contains("select t0.id, t0.name from o_customer t0 where t0.id");
platformAssertIn(sql.get(0), " where t0.id");
}
@Test
@@ -123,7 +125,8 @@ public class TestSecondaryQueries extends BaseTestCase {
assertThat(generatedSql).contains("from o_customer t0 where t0.id = ?");
assertEquals(2, sql.size());
assertThat(sql.get(1)).contains("from contact t0 where (t0.customer_id) in (?)");
assertThat(sql.get(1)).contains("from contact t0 where (t0.customer_id) ");
platformAssertIn(sql.get(1), " where (t0.customer_id)");
}
@@ -179,7 +182,8 @@ public class TestSecondaryQueries extends BaseTestCase {
// from o_order_detail t0
// where (t0.order_id) in (?,?,?,?,?) ; --bind(1,4,1,1,1)
assertThat(ordSecondarySql).contains(" from o_order_detail t0 where t0.id > 0 and (t0.order_id) in (?");
assertThat(ordSecondarySql).contains(" from o_order_detail t0 where t0.id > 0 and (t0.order_id) ");
platformAssertIn(ordSecondarySql, "and (t0.order_id)");
}
}
@@ -118,9 +118,9 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
if (isPlatformBooleanNative()) {
assertThat(sql.get(0)).contains("update cover set deleted=true where id in (?,?)");
assertThat(sql.get(0)).contains("update cover set deleted=true where id ");
} else {
assertThat(sql.get(0)).contains("update cover set deleted=1 where id in (?,?)");
assertThat(sql.get(0)).contains("update cover set deleted=1 where id ");
}
}
@@ -144,9 +144,9 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
if (isPlatformBooleanNative()) {
assertThat(sql.get(0)).contains("update cover set deleted=true where id in (?,?)");
assertThat(sql.get(0)).contains("update cover set deleted=true where id");
} else {
assertThat(sql.get(0)).contains("update cover set deleted=1 where id in (?,?)");
assertThat(sql.get(0)).contains("update cover set deleted=1 where id");
}
}
@@ -162,7 +162,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("delete from cover where id in (?,?)");
platformAssertIn(sql.get(0), "delete from cover where id ");
}
@Test
@@ -178,7 +178,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("delete from cover where id in (?,?)");
platformAssertIn(sql.get(0), "delete from cover where id ");
}
@@ -201,7 +201,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("delete from cover where id in (?,?)");
platformAssertIn(sql.get(0), "delete from cover where id ");
}
@Test
@@ -57,7 +57,8 @@ public class TestQueryFetchManyTwoDeep extends BaseTestCase {
//SpiQuery<?> secondaryQuery = secondaryQueries.get(0);
String secondarySql = sql.get(1);
assertThat(secondarySql).contains("from o_order_detail t0 where t0.id > 0 and (t0.order_id) in");
assertThat(secondarySql).contains("from o_order_detail t0 where t0.id > 0 and (t0.order_id) ");
platformAssertIn(secondarySql, "(t0.order_id)");
// select t0.order_id c0, t0.id c1, t0.order_qty c2, t0.ship_qty c3, t0.unit_price c4, t0.cretime c5, t0.updtime c6, t0.order_id c7, t0.product_id c8
// from o_order_detail t0
@@ -76,9 +76,9 @@ public class TestQueryFilterMany extends BaseTestCase {
assertThat(sql).hasSize(3);
assertThat(sql.get(0)).contains(" from o_customer t0; --bind()");
assertThat(sql.get(1)).contains(" from contact t0 where (t0.customer_id) in");
platformAssertIn(sql.get(1), " from contact t0 where (t0.customer_id)");
assertThat(sql.get(1)).contains(" and t0.first_name is not null");
assertThat(sql.get(2)).contains(" from contact_note t0 where (t0.contact_id) in");
platformAssertIn(sql.get(2), " from contact_note t0 where (t0.contact_id)");
assertThat(sql.get(2)).contains(" and lower(t0.title) like");
}
}
@@ -27,7 +27,7 @@ public class TestQueryInAssocOne extends BaseTestCase {
String sql = query.getGeneratedSql();
assertThat(sql).contains("join o_customer t1 on t1.id = t0.kcustomer_id");
assertThat(sql).contains("t0.kcustomer_id in (?");
platformAssertIn(sql, "where t0.kcustomer_id");
}
@@ -44,7 +44,7 @@ public class TestQueryInAssocOne extends BaseTestCase {
String sql = query.getGeneratedSql();
assertThat(sql).contains("join o_customer t1 on t1.id = t0.kcustomer_id");
assertThat(sql).contains("t0.kcustomer_id in (?");
platformAssertIn(sql, "t0.kcustomer_id");
}
@@ -61,6 +61,6 @@ public class TestQueryInAssocOne extends BaseTestCase {
String sql = query.getGeneratedSql();
assertThat(sql).contains("join o_customer t1 on t1.id = t0.kcustomer_id");
assertThat(sql).contains("t0.kcustomer_id not in (?");
platformAssertNotIn(sql, "t0.kcustomer_id");
}
}
@@ -24,6 +24,8 @@ public class TestSubQuery extends BaseTestCase {
List<Integer> productIds = new ArrayList<>();
productIds.add(3);
productIds.add(4);
productIds.add(5);
Query<Order> sq = Ebean.createQuery(Order.class).select("id").where()
.in("details.product.id", productIds).query();
@@ -0,0 +1,45 @@
package org.tests.query;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.Country;
import org.tests.model.basic.ResetBasicData;
import static org.assertj.core.api.Assertions.assertThat;
public class TestWhereIn extends BaseTestCase {
@Test
public void testInVarchar() {
ResetBasicData.reset();
Query<Country> query = Ebean.find(Country.class)
.where().in("code", "NZ", "AU")
.query();
query.findList();
if (isPostgres()) {
assertThat(sqlOf(query)).contains(" = any(");
}
}
@Test
public void testNotInVarchar() {
ResetBasicData.reset();
Query<Country> query = Ebean.find(Country.class)
.where().notIn("code", "NZ", "SA", "US")
.query();
query.findList();
if (isPostgres()) {
assertThat(sqlOf(query)).contains(" != all(");
}
}
}
@@ -55,7 +55,8 @@ public class TestManyLazyLoadingQuery extends BaseTestCase {
beanProperty.addWhereParentIdIn(query0, parentIds, false);
query0.findList();
assertThat(query0.getGeneratedSql()).contains(" from o_order_detail t0 where (t0.order_id) in (");
assertThat(query0.getGeneratedSql()).contains(" from o_order_detail t0 where (t0.order_id) ");
platformAssertIn(query0.getGeneratedSql(), "where (t0.order_id)");
} finally {
Ebean.endTransaction();