For querybean associated beans, add missing eqIfPresent() + in() + notIn() + expressions

This commit is contained in:
Rob Bygrave
2023-02-26 19:24:00 +13:00
parent e6b0306bde
commit 25416a3cda
3 changed files with 185 additions and 4 deletions
@@ -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());