mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1645 - ENH: Add expression rawOrEmpty() ... as a convenience for conditionally added a raw expression
This commit is contained in:
@@ -1282,6 +1282,68 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
/**
|
||||
* Only add the raw expression if the values is not null or empty.
|
||||
* <p>
|
||||
* This is a pure convenience expression to make it nicer to deal with the pattern where we use
|
||||
* raw() expression with a subquery and only want to add the subquery predicate when the collection
|
||||
* of values is not empty.
|
||||
* </p>
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* // common pattern - we can use rawOrEmpty() instead
|
||||
* if (orderIds != null && !orderIds.isEmpty()) {
|
||||
* query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using rawOrEmpty()</h3>
|
||||
* Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion"
|
||||
* for each element in the collection.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* // only add the expression if orderIds is not empty
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Postgres ANY</h3>
|
||||
* With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
|
||||
* rather than <code>IN</code>.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* " ... = any(?::uuid[])"
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param values The values which is typically a list or set of id values.
|
||||
*/
|
||||
ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values);
|
||||
|
||||
/**
|
||||
* Add a match expression.
|
||||
*
|
||||
|
||||
@@ -914,7 +914,9 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) {
|
||||
add(expr.inOrEmpty(propertyName, values));
|
||||
if (notEmpty(values)) {
|
||||
add(expr.in(propertyName, values));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1074,6 +1076,18 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values) {
|
||||
if (notEmpty(values)) {
|
||||
add(expr.raw(raw, values));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean notEmpty(Collection<?> values) {
|
||||
return values != null && !values.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> startsWith(String propertyName, String value) {
|
||||
add(expr.startsWith(propertyName, value));
|
||||
|
||||
@@ -807,6 +807,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.raw(raw, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> rawOrEmpty(String raw, Collection<Object> values) {
|
||||
return exprList.rawOrEmpty(raw, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> raw(String raw) {
|
||||
return exprList.raw(raw);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class TestWhereIn extends BaseTestCase {
|
||||
.where().inOrEmpty("customer.billingAddress.id", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id from o_order t0 where 1=1");
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id from o_order t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,10 +79,9 @@ public class TestWhereIn extends BaseTestCase {
|
||||
.where().inOrEmpty("code", null).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=1");
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInOrEmpty_when_empty() {
|
||||
|
||||
@@ -92,7 +91,7 @@ public class TestWhereIn extends BaseTestCase {
|
||||
.where().inOrEmpty("code", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=1");
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.ebean.Expr;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
@@ -13,6 +14,7 @@ import org.tests.model.basic.OrderDetail;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
@@ -65,6 +67,54 @@ public class TestWhereRawClause extends BaseTestCase {
|
||||
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_notEmpty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_null() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", null)
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_empty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", Collections.emptySet())
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaw_bindExpansion() {
|
||||
|
||||
@@ -94,6 +144,33 @@ public class TestWhereRawClause extends BaseTestCase {
|
||||
assertThat(list).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(Platform.POSTGRES)
|
||||
public void testRawOrEmpty_PostgresArray() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", asList("Rob", "Fiona", "Jack"))
|
||||
.findList();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", asList())
|
||||
.findList();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", null)
|
||||
.findList();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql.get(0)).isEqualTo("select t0.id, t0.name from o_customer t0 where t0.name = any(?); --bind(Array[3]={Rob,Fiona,Jack})");
|
||||
assertThat(sql.get(1)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
|
||||
assertThat(sql.get(2)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawWithBindParams() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user