mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 14:32:04 +00:00
Merge pull request #2985 from ebean-orm/feature/querybean-assoc-eqIfPresent
For querybean associated beans, add missing eqIfPresent() + in() + notIn() + expressions
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package io.ebean.typequery;
|
||||
|
||||
import io.avaje.lang.Nullable;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.FetchGroup;
|
||||
@@ -7,6 +8,7 @@ import io.ebeaninternal.api.SpiQueryFetch;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -193,6 +195,17 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R, Object> {
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is EQUAL TO if value is non-null and otherwise no expression is added to the query.
|
||||
* <p>
|
||||
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
|
||||
* effectively optional. We can use <code>eqIfPresent()</code> rather than having a separate if block.
|
||||
*/
|
||||
public final R eqIfPresent(@Nullable T other) {
|
||||
expr().eqIfPresent(_name, other);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is equal to by ID property.
|
||||
*/
|
||||
@@ -215,6 +228,95 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R, Object> {
|
||||
return ne(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is in a list of values.
|
||||
*
|
||||
* @param values the list of values for the predicate
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final R in(T... values) {
|
||||
expr().in(_name, (Object[]) values);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is in a list of values.
|
||||
*
|
||||
* @param values the list of values for the predicate
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
public final R in(Collection<T> values) {
|
||||
expr().in(_name, values);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* In where null or empty values means that no predicate is added to the query.
|
||||
* <p>
|
||||
* That is, only add the IN predicate if the values are not null or empty.
|
||||
* <p>
|
||||
* Without this we typically need to code an <code>if</code> block to only add
|
||||
* the IN predicate if the collection is not empty like:
|
||||
* </p>
|
||||
*
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names = Arrays.asList("foo", "bar");
|
||||
*
|
||||
* QCustomer query = new QCustomer()
|
||||
* .registered.before(LocalDate.now())
|
||||
*
|
||||
* // conditionally add the IN expression to the query
|
||||
* if (names != null && !names.isEmpty()) {
|
||||
* query.name.in(names)
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names = Arrays.asList("foo", "bar");
|
||||
*
|
||||
* new QCustomer()
|
||||
* .registered.before(LocalDate.now())
|
||||
* .name.inOrEmpty(names)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public final R inOrEmpty(Collection<T> values) {
|
||||
expr().inOrEmpty(_name, values);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is NOT in a list of values.
|
||||
*
|
||||
* @param values the list of values for the predicate
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
public final R notIn(Collection<T> values) {
|
||||
expr().notIn(_name, values);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is NOT in a list of values.
|
||||
*
|
||||
* @param values the list of values for the predicate
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final R notIn(T... values) {
|
||||
expr().notIn(_name, (Object[]) values);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a filter when fetching these beans.
|
||||
*/
|
||||
|
||||
@@ -930,7 +930,7 @@ public abstract class TQRootBean<T, R> {
|
||||
/**
|
||||
* Specify the PersistenceContextScope to use for this query.
|
||||
* <p>
|
||||
* When this is not set the 'default' configured on {@link io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* When this is not set the 'default' configured on {@link io.ebean.config.DatabaseConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* is used - this value defaults to {@link io.ebean.PersistenceContextScope#TRANSACTION}.
|
||||
* <p>
|
||||
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
|
||||
@@ -2117,12 +2117,10 @@ public abstract class TQRootBean<T, R> {
|
||||
* Return the current expression list that expressions should be added to.
|
||||
*/
|
||||
protected ExpressionList<T> peekExprList() {
|
||||
|
||||
if (textMode) {
|
||||
// return the current text expression list
|
||||
return _peekText();
|
||||
}
|
||||
|
||||
if (whereStack == null) {
|
||||
whereStack = new ArrayStack<>();
|
||||
whereStack.push(query.where());
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.querytest;
|
||||
|
||||
import io.ebean.*;
|
||||
import io.ebean.annotation.Transactional;
|
||||
import io.ebean.test.LoggedSql;
|
||||
import io.ebean.types.Inet;
|
||||
import org.example.domain.*;
|
||||
import org.example.domain.otherpackage.PhoneNumber;
|
||||
@@ -315,10 +316,11 @@ public class QCustomerTest {
|
||||
|
||||
@Test
|
||||
public void testAssocOne() {
|
||||
|
||||
DB.getDefault();
|
||||
Address address = new Address();
|
||||
address.setId(41L);
|
||||
|
||||
LoggedSql.start();
|
||||
new QCustomer()
|
||||
.billingAddress.eq(address)
|
||||
.findList();
|
||||
@@ -334,6 +336,85 @@ public class QCustomerTest {
|
||||
new QCustomer()
|
||||
.billingAddress.notEqualTo(address)
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.eqIfPresent(address)
|
||||
.name.isNull()
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.eqIfPresent(null)
|
||||
.name.isNull()
|
||||
.findList();
|
||||
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
|
||||
assertThat(sql).hasSize(6);
|
||||
assertThat(sql.get(0)).contains("where t0.billing_address_id = ?");
|
||||
assertThat(sql.get(1)).contains("where t0.billing_address_id = ?");
|
||||
assertThat(sql.get(2)).contains("where t0.billing_address_id <> ?");
|
||||
assertThat(sql.get(3)).contains("where t0.billing_address_id <> ?");
|
||||
assertThat(sql.get(4)).contains("where t0.billing_address_id = ? and t0.name is null");
|
||||
assertThat(sql.get(5)).contains("where t0.name is null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssocOne_in() {
|
||||
DB.getDefault();
|
||||
Address address = new Address();
|
||||
address.setId(41L);
|
||||
Address address2 = new Address();
|
||||
address2.setId(41L);
|
||||
|
||||
LoggedSql.start();
|
||||
new QCustomer()
|
||||
.billingAddress.in(address, address2)
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.in(List.of(address, address2))
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.inOrEmpty(List.of(address, address2))
|
||||
.name.isNull()
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.inOrEmpty(List.of())
|
||||
.name.isNull()
|
||||
.findList();
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(4);
|
||||
assertThat(sql.get(0)).contains("where t0.billing_address_id in (?,?)");
|
||||
assertThat(sql.get(1)).contains("where t0.billing_address_id in (?,?)");
|
||||
assertThat(sql.get(2)).contains("where t0.billing_address_id in (?,?) and t0.name is null");
|
||||
assertThat(sql.get(3)).contains("where t0.name is null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssocOne_notIn() {
|
||||
DB.getDefault();
|
||||
Address address = new Address();
|
||||
address.setId(41L);
|
||||
Address address2 = new Address();
|
||||
address2.setId(41L);
|
||||
|
||||
LoggedSql.start();
|
||||
new QCustomer()
|
||||
.billingAddress.notIn(address, address2)
|
||||
.findList();
|
||||
|
||||
new QCustomer()
|
||||
.billingAddress.notIn(List.of(address, address2))
|
||||
.findList();
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("where t0.billing_address_id not in (?,?)");
|
||||
assertThat(sql.get(1)).contains("where t0.billing_address_id not in (?,?)");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user