io.ebean.ExpressionList Maven / Gradle / Ivy
package io.ebean;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import io.ebean.search.*;
import javax.persistence.NonUniqueResultException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* List of Expressions that make up a where or having clause.
*
* An ExpressionList is returned from {@link Query#where()}.
*
*
* The ExpressionList has a list of convenience methods that create the standard
* expressions and add them to this list.
*
*
* The ExpressionList also duplicates methods that are found on the Query such
* as findList() and order(). The purpose of these methods is provide a fluid
* API. The upside of this approach is that you can build and execute a query
* via chained methods. The down side is that this ExpressionList object has
* more methods than you would initially expect (the ones duplicated from
* Query).
*
*
* @see Query#where()
*/
@NullMarked
public interface ExpressionList {
/**
* Return the query that owns this expression list.
*
* This is a convenience method solely to support a fluid API where the
* methods are chained together. Adding expressions returns this expression
* list and this method can be used after that to return back the original
* query so that further things can be added to it.
*
*/
Query query();
/**
* Controls, if paginated queries should always append an 'order by id' statement at the end to
* guarantee a deterministic sort result. This may affect performance.
* If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
* this query provides a deterministic result.
*/
Query orderById(boolean orderById);
/**
* @deprecated migrate to {@link #orderBy(String)}
*/
@Deprecated(since = "13.19", forRemoval = true)
default ExpressionList order(String orderByClause) {
return orderBy(orderByClause);
}
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
*
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
*/
ExpressionList orderBy(String orderBy);
/**
* @deprecated migrate to {@link #orderBy()}.
*/
@Deprecated(forRemoval = true)
default OrderBy order() {
return orderBy();
}
/**
* Return the OrderBy so that you can append an ascending or descending
* property to the order by clause.
*
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
*
* This is the same as order()
*/
OrderBy orderBy();
/**
* Apply the path properties to the query replacing the select and fetch clauses.
*/
Query apply(FetchPath fetchPath);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
*
* To perform this query the DB must have underlying history tables.
*
*
* @param asOf the date time in the past at which you want to view the data
*/
Query asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query asDraft();
/**
* Convert the query to a DTO bean query.
*
* We effectively use the underlying ORM query to build the SQL and then execute
* and map it into DTO beans.
*/
DtoQuery asDto(Class dtoClass);
/**
* Return the underlying query as an UpdateQuery.
*
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
*
*
* {@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }
*
* {@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }
*/
UpdateQuery asUpdate();
/**
* Execute the query with the given lock type and WAIT.
*
* Note that forUpdate()
is the same as
* withLock(LockType.UPDATE)
.
*
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query withLock(Query.LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
*
* Note that forUpdateNoWait()
is the same as
* withLock(LockType.UPDATE, LockWait.NOWAIT)
.
*
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query withLock(Query.LockType lockType, Query.LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query forUpdate();
/**
* Execute using "for update" clause with No Wait option.
*
* This is typically a Postgres and Oracle only option at this stage.
*
*/
Query forUpdateNoWait();
/**
* Execute using "for update" clause with Skip Locked option.
*
* This is typically a Postgres and Oracle only option at this stage.
*
*/
Query forUpdateSkipLocked();
/**
* Execute the query including soft deleted rows.
*/
Query setIncludeSoftDeletes();
/**
* Execute the query using the given transaction.
*/
Query usingTransaction(Transaction transaction);
/**
* Execute the query using the given connection.
*/
Query usingConnection(Connection connection);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
*
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
*
* @return the number of rows that were deleted.
*/
int delete();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then delete().
*
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
*
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
*
* @return the number of rows that were deleted.
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int delete(Transaction transaction);
/**
* Execute as a update query.
*
* @return the number of rows that were updated.
* @see UpdateQuery
*/
int update();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then update().
*
* Execute as a update query with the given transaction.
*
* @return the number of rows that were updated.
* @see UpdateQuery
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int update(Transaction transaction);
/**
* Execute the query returning true if a row is found.
*
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
*
*
* Example:
* {@code
*
* boolean userExists = query().where().eq("email", "[email protected]").exists();
*
* }
*
* Example using a query bean:
* {@code
*
* boolean userExists = new QContact().email.equalTo("[email protected]").exists();
*
* }
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query iterating over the results.
*
* @see Query#findIterate()
*/
QueryIterator findIterate();
/**
* Execute the query process the beans one at a time.
*
* @see Query#findEach(Consumer)
*/
void findEach(Consumer consumer);
/**
* Execute findEach with a batch consumer.
*
* @see Query#findEach(int, Consumer)
*/
void findEach(int batch, Consumer> consumer);
/**
* Execute the query processing the beans one at a time with the ability to
* stop processing before reading all the beans.
*
* @see Query#findEachWhile(Predicate)
*/
void findEachWhile(Predicate consumer);
/**
* Execute the query returning a list.
*
* @see Query#findList()
*/
List findList();
/**
* Execute the query returning the list of Id's.
*
* @see Query#findIds()
*/
List findIds();
/**
* Return the count of entities this query should return.
*
* This is the number of 'top level' or 'root level' entities.
*
*/
int findCount();
/**
* Execute the query returning a set.
*
* @see Query#findSet()
*/
Set findSet();
/**
* Execute the query returning a map.
*
* @see Query#findMap()
*/
Map findMap();
/**
* Execute the query returning a list of values for a single property.
*
* Example 1:
* {@code
*
* List names =
* DB.find(Customer.class)
* .select("name")
* .order().asc("name")
* .findSingleAttributeList();
*
* }
*
* Example 2:
* {@code
*
* List names =
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .order().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }
*
* @return the list of values for the selected property
*/
List findSingleAttributeList();
/**
* Executes the query returning a set of values for a single property.
*
* This can be used to cache sets.
*
* @return a HashSet of values for the selegted property
*/
Set findSingleAttributeSet();
/**
* Execute a query returning a single value of a single property/column.
* {@code
*
* String name =
* DB.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
*
* }
*/
@Nullable
default A findSingleAttribute() {
List list = findSingleAttributeList();
return !list.isEmpty() ? list.get(0) : null;
}
/**
* Execute the query returning a single bean or null (if no matching
* bean is found).
*
* If more than 1 row is found for this query then a NonUniqueResultException is
* thrown.
*
*
* @throws NonUniqueResultException if more than one result was found
* @see Query#findOne()
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional findOneOrEmpty();
/**
* Execute find row count query in a background thread.
*
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
*
* @return a Future object for the row count query
*/
FutureRowCount findFutureCount();
/**
* Execute find Id's query in a background thread.
*
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
*
* @return a Future object for the list of Id's
*/
FutureIds findFutureIds();
/**
* Execute find list query in a background thread.
*
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
*
* @return a Future object for the list result of the query
*/
FutureList findFutureList();
/**
* Return a PagedList for this query using firstRow and maxRows.
*
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
*
*
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
*
* {@code
*
* PagedList pagedList = DB.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }
*
* @return The PagedList
* @see Query#findPagedList()
*/
PagedList findPagedList();
/**
* Return versions of a @History entity bean.
*
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*
*/
List> findVersions();
/**
* Return versions of a @History entity bean between the 2 timestamps.
*
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*
*/
List> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Add some filter predicate expressions to the many property.
*/
ExpressionList filterMany(String manyProperty);
/**
* @deprecated for removal - migrate to {@link #filterManyRaw(String, String, Object...)}.
*
* Add filter expressions to the many property.
*
*
{@code
*
* DB.find(Customer.class)
* .where()
* .eq("name", "Rob")
* .filterMany("orders", "status = ?", Status.NEW)
* .findList();
*
* }
*
* @param manyProperty The many property
* @param expressions Filter expressions with and, or and ? or ?1 type bind parameters
* @param params Bind parameters used in the expressions
*/
@Deprecated(forRemoval = true)
ExpressionList filterMany(String manyProperty, String expressions, Object... params);
/**
* Add filter expressions for the many path. The expressions can include SQL functions if
* desired and the property names are translated to column names.
*
* The expressions can contain placeholders for bind values using ?
or ?1
style.
*
*
{@code
*
* new QCustomer()
* .name.startsWith("Postgres")
* .contacts.filterManyRaw("status = ? and firstName like ?", Contact.Status.NEW, "Rob%")
* .findList();
*
* }
*
* @param rawExpressions The raw expressions which can include ? and ?1 style bind parameter placeholders
* @param params The parameter values to bind
*/
ExpressionList filterManyRaw(String manyProperty, String rawExpressions, Object... params);
/**
* Specify specific properties to fetch on the main/root bean (aka partial
* object).
*
* @see Query#select(String)
*/
Query select(String properties);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
Query select(FetchGroup fetchGroup);
/**
* Set whether this query uses DISTINCT.
*
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
*
* {@code
*
* List customers =
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name") // only select the customer name
* .findList();
*
* }
*/
Query setDistinct(boolean distinct);
/**
* Set the index(es) to search for a document store which uses partitions.
*
* For example, when executing a query against ElasticSearch with daily indexes we can
* explicitly specify the indexes to search against.
*
*
* @param indexName The index or indexes to search against
* @return This query
* @see Query#setDocIndexName(String)
*/
Query setDocIndexName(String indexName);
/**
* Set the first row to fetch.
*
* @see Query#setFirstRow(int)
*/
ExpressionList setFirstRow(int firstRow);
/**
* Set the maximum number of rows to fetch.
*
* @see Query#setMaxRows(int)
*/
ExpressionList setMaxRows(int maxRows);
/**
* Set the name of the property which values become the key of a map.
*
* @see Query#setMapKey(String)
*/
Query setMapKey(String mapKey);
/**
* Set to true when this query should use the bean cache.
*
* This is now the same as setUseBeanCache(CacheMode.ON) and will be deprecated.
*
*
* @see Query#setUseCache(boolean)
*/
Query setUseCache(boolean useCache);
/**
* Set the mode to use the bean cache when executing this query.
*
* @see Query#setBeanCacheMode(CacheMode)
*/
Query setBeanCacheMode(CacheMode beanCacheMode);
/**
* Set the {@link CacheMode} to use the query cache for executing this query.
*
* @see Query#setUseQueryCache(boolean)
*/
Query setUseQueryCache(CacheMode useCache);
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
* {@code
*
* List> orderStatusCount =
*
* DB.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
*
* // fetch as single attribute with a COUNT
* .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
* .findSingleAttributeList();
*
* for (CountedValue entry : orderStatusCount) {
* System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
* }
*
* // produces
*
* count:3 orderStatus:NEW
* count:1 orderStatus:SHIPPED
* count:1 orderStatus:COMPLETE
*
* }
*/
Query setCountDistinct(CountDistinctOrder orderBy);
/**
* Calls {@link #setUseQueryCache(CacheMode)} with ON
or OFF
.
*
* @see Query#setUseQueryCache(CacheMode)
*/
default Query setUseQueryCache(boolean enabled) {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set to true if this query should execute against the doc store.
*
* When setting this you may also consider disabling lazy loading.
*
*/
Query setUseDocStore(boolean useDocsStore);
/**
* Set true if you want to disable lazy loading.
*
* That is, once the object graph is returned further lazy loading is disabled.
*
*/
Query setDisableLazyLoading(boolean disableLazyLoading);
/**
* Disable read auditing for this query.
*
* This is intended to be used when the query is not a user initiated query and instead
* part of the internal processing in an application to load a cache or document store etc.
* In these cases we don't want the query to be part of read auditing.
*
*/
Query setDisableReadAuditing();
/**
* Set a label on the query (to help identify query execution statistics).
*/
Query setLabel(String label);
/**
* Add expressions to the having clause.
*
* The having clause is only used for queries based on raw sql (via SqlSelect
* annotation etc).
*
*/
ExpressionList having();
/**
* Add another expression to the where clause.
*/
ExpressionList where();
/**
* Add the expressions to this expression list.
*
* @param expressions The expressions that are parsed and added to this expression list
* @param params Bind parameters to match ? or ?1 bind positions.
*/
ExpressionList where(String expressions, Object... params);
/**
* Path exists - for the given path in a JSON document.
* {@code
*
* where().jsonExists("content", "path.other")
*
* }
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
*/
ExpressionList jsonExists(String propertyName, String path);
/**
* Path does not exist - for the given path in a JSON document.
* {@code
*
* where().jsonNotExists("content", "path.other")
*
* }
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
*/
ExpressionList jsonNotExists(String propertyName, String path);
/**
* Equal to expression for the value at the given path in the JSON document.
* {@code
*
* where().jsonEqualTo("content", "path.other", 34)
*
* }
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
ExpressionList jsonEqualTo(String propertyName, String path, Object value);
/**
* Not Equal to - for the given path in a JSON document.
* {@code
*
* where().jsonNotEqualTo("content", "path.other", 34)
*
* }
*
* @param propertyName the property that holds a JSON document
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
ExpressionList jsonNotEqualTo(String propertyName, String path, Object value);
/**
* Greater than - for the given path in a JSON document.
* {@code
*
* where().jsonGreaterThan("content", "path.other", 34)
*
* }
*/
ExpressionList jsonGreaterThan(String propertyName, String path, Object value);
/**
* Greater than or equal to - for the given path in a JSON document.
* {@code
*
* where().jsonGreaterOrEqual("content", "path.other", 34)
*
* }
*/
ExpressionList jsonGreaterOrEqual(String propertyName, String path, Object value);
/**
* Less than - for the given path in a JSON document.
* {@code
*
* where().jsonLessThan("content", "path.other", 34)
*
* }
*/
ExpressionList jsonLessThan(String propertyName, String path, Object value);
/**
* Less than or equal to - for the given path in a JSON document.
* {@code
*
* where().jsonLessOrEqualTo("content", "path.other", 34)
*
* }
*/
ExpressionList jsonLessOrEqualTo(String propertyName, String path, Object value);
/**
* Between - for the given path in a JSON document.
* {@code
*
* where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
*
* }
*/
ExpressionList jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
/**
* Add an Expression to the list.
*/
ExpressionList add(Expression expr);
/**
* Add a list of Expressions to this ExpressionList.s
*/
ExpressionList addAll(ExpressionList exprList);
/**
* Equal To the result of a sub-query.
*/
ExpressionList eq(String propertyName, Query> subQuery);
/**
* Equal To - property is equal to a given value.
*/
ExpressionList eq(String propertyName, Object value);
/**
* Is EQUAL TO if value is non-null and otherwise no expression is added to the query.
*
* This is the EQUAL TO equivalent to {@link #inOrEmpty(String, Collection)} where the expression/predicate
* is only added when the value is non-null.
*
* 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 eqIfPresent()
rather than having a separate if block.
*
* Another option is to instead globally use {@link io.ebean.config.DatabaseConfig#setExpressionEqualsWithNullAsNoop(boolean)}
* but that is not always desirable.
*/
ExpressionList eqIfPresent(String propertyName, @Nullable Object value);
/**
* Equal To or Null - property is equal to a given value or null.
*/
ExpressionList eqOrNull(String propertyName, Object value);
/**
* Not Equal To the result of a sub-query.
*/
ExpressionList ne(String propertyName, Query> subQuery);
/**
* Not Equal To - property not equal to the given value.
*/
ExpressionList ne(String propertyName, Object value);
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
ExpressionList ieq(String propertyName, String value);
/**
* Case Insensitive Not Equal To - property not equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
ExpressionList ine(String propertyName, String value);
/**
* Value in Range between 2 properties.
*
* {@code
*
* .startDate.inRangeWith(endDate, now)
*
* // which equates to
* startDate <= now and (endDate > now or endDate is null)
*
* }
*
*
* This is a convenience expression combining a number of simple expressions.
* The most common use of this could be called "effective dating" where 2 date or
* timestamp columns represent the date range in which
*/
ExpressionList inRangeWith(String lowProperty, String highProperty, Object value);
/**
* A Property is in Range between 2 properties.
*
* {@code
*
* .orderDate.inRangeWith(QOrder.Alias.product.startDate, QOrder.Alias.product.endDate)
*
* // which equates to
* product.startDate <= orderDate and (orderDate < product.endDate or product.endDate is null)
*
* }
*
*
* This is a convenience expression combining a number of simple expressions.
*/
ExpressionList inRangeWithProperties(String propertyName, String lowProperty, String highProperty);
/**
* In Range - {@code property >= value1 and property < value2}.
*
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
*
*/
ExpressionList inRange(String propertyName, Object value1, Object value2);
/**
* Between - property between the two given values.
*/
ExpressionList between(String propertyName, Object value1, Object value2);
/**
* Between - value between the two properties.
*/
ExpressionList betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than the result of a sub-query.
*/
ExpressionList gt(String propertyName, Query> subQuery);
/**
* Greater Than - property greater than the given value.
*/
ExpressionList gt(String propertyName, Object value);
/**
* Greater Than or Null - property greater than the given value or null.
*/
ExpressionList gtOrNull(String propertyName, Object value);
/**
* Is GREATER THAN if value is non-null and otherwise no expression is added to the query.
*
* 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 gtIfPresent()
rather than having a separate if block.
*/
ExpressionList gtIfPresent(String propertyName, @Nullable Object value);
/**
* Greater Than or Equal to the result of a sub-query.
*/
ExpressionList ge(String propertyName, Query> subQuery);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
ExpressionList ge(String propertyName, Object value);
/**
* Greater Than or Equal to OR Null - ({@code >= or null }).
*/
ExpressionList geOrNull(String propertyName, Object value);
/**
* Is GREATER THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
*
* 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 geIfPresent()
rather than having a separate if block.
*/
ExpressionList geIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than the result of a sub-query.
*/
ExpressionList lt(String propertyName, Query> subQuery);
/**
* Less Than - property less than the given value.
*/
ExpressionList lt(String propertyName, Object value);
/**
* Less Than or Null - property less than the given value or null.
*/
ExpressionList ltOrNull(String propertyName, Object value);
/**
* Is LESS THAN if value is non-null and otherwise no expression is added to the query.
*
* 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 ltIfPresent()
rather than having a separate if block.
*/
ExpressionList ltIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than or Equal to the result of a sub-query.
*/
ExpressionList le(String propertyName, Query> subQuery);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
ExpressionList le(String propertyName, Object value);
/**
* Less Than or Equal to OR Null - ({@code <= or null }).
*/
ExpressionList leOrNull(String propertyName, Object value);
/**
* Is LESS THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
*
* 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 leIfPresent()
rather than having a separate if block.
*/
ExpressionList leIfPresent(String propertyName, @Nullable Object value);
/**
* Is Null - property is null.
*/
ExpressionList isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
ExpressionList isNotNull(String propertyName);
/**
* A "Query By Example" type of expression.
*
* Pass in an example entity and for each non-null scalar properties an
* expression is added.
*
*
* By Default this case sensitive, will ignore numeric zero values and will
* use a Like for string values (you must put in your own wildcards).
*
*
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
*
* {@code
*
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
* List list =
* DB.find(Customer.class)
* .where().exampleLike(example)
* .findList();
*
* }
*
* Similarly you can create an ExampleExpression
*
* {@code
*
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
*
* List list = DB.find(Customer.class).where().add(qbe).findList();
*
* }
*/
ExpressionList exampleLike(Object example);
/**
* Case insensitive version of {@link #exampleLike(Object)}
*/
ExpressionList iexampleLike(Object example);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
ExpressionList like(String propertyName, String value);
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
ExpressionList ilike(String propertyName, String value);
/**
* Starts With - property like value%.
*/
ExpressionList startsWith(String propertyName, String value);
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
ExpressionList istartsWith(String propertyName, String value);
/**
* Ends With - property like %value.
*/
ExpressionList endsWith(String propertyName, String value);
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
ExpressionList iendsWith(String propertyName, String value);
/**
* Contains - property like %value%.
*/
ExpressionList contains(String propertyName, String value);
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
ExpressionList icontains(String propertyName, String value);
/**
* In expression using pairs of value objects.
*/
ExpressionList inPairs(Pairs pairs);
/**
* In expression using multiple columns.
*/
ExpressionList inTuples(InTuples pairs);
/**
* EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList exists(String sqlSubQuery, Object... bindValues);
/**
* Not EXISTS a raw SQL SubQuery.
*
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList notExists(String sqlSubQuery, Object... bindValues);
/**
* IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not IN a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Not Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Greater Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* Less Than or Equal To a raw SQL SubQuery.
*
* @param propertyName The bean property
* @param sqlSubQuery The SQL SubQuery
* @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
*/
ExpressionList leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues);
/**
* In - using a subQuery.
*/
ExpressionList in(String propertyName, Query> subQuery);
/**
* In - property has a value in the array of values.
*/
ExpressionList in(String propertyName, Object... values);
/**
* In - property has a value in the collection of values.
*/
ExpressionList in(String propertyName, Collection> values);
/**
* In where null or empty values means that no predicate is added to the query.
*
* That is, only add the IN predicate if the values are not null or empty.
*
* Without this we typically need to code an if
block to only add
* the IN predicate if the collection is not empty like:
*
*
* Without inOrEmpty()
* {@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }
*
* Using inOrEmpty()
* {@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }
*/
ExpressionList inOrEmpty(String propertyName, Collection> values);
/**
* In - using a subQuery.
*
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList isIn(String propertyName, Query> subQuery) {
return in(propertyName, subQuery);
}
/**
* In - property has a value in the array of values.
*
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList isIn(String propertyName, Object... values) {
return in(propertyName, values);
}
/**
* In - property has a value in the collection of values.
*
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList isIn(String propertyName, Collection> values) {
return in(propertyName, values);
}
/**
* Not In - property has a value in the array of values.
*/
ExpressionList notIn(String propertyName, Object... values);
/**
* Not In - property has a value in the collection of values.
*/
ExpressionList notIn(String propertyName, Collection> values);
/**
* Not In - using a subQuery.
*/
ExpressionList notIn(String propertyName, Query> subQuery);
/**
* Is empty expression for collection properties.
*/
ExpressionList isEmpty(String propertyName);
/**
* Is not empty expression for collection properties.
*/
ExpressionList isNotEmpty(String propertyName);
/**
* Exists expression
*/
ExpressionList exists(Query> subQuery);
/**
* Not exists expression
*/
ExpressionList notExists(Query> subQuery);
/**
* Id IN a list of id values.
*/
ExpressionList idIn(Object... idValues);
/**
* Id IN a collection of id values.
*/
ExpressionList idIn(Collection> idValues);
/**
* Id Equal to - ID property is equal to the value.
*/
ExpressionList idEq(Object value);
/**
* All Equal - Map containing property names and their values.
*
* Expression where all the property names in the map are equal to the
* corresponding value.
*
*
* @param propertyMap a map keyed by property names.
*/
ExpressionList allEq(Map propertyMap);
/**
* Array property contains entries with the given values.
*/
ExpressionList arrayContains(String propertyName, Object... values);
/**
* Array does not contain the given values.
*
* Array support is effectively limited to Postgres at this time.
*
*/
ExpressionList arrayNotContains(String propertyName, Object... values);
/**
* Array is empty - for the given array property.
*
* Array support is effectively limited to Postgres at this time.
*
*/
ExpressionList arrayIsEmpty(String propertyName);
/**
* Array is not empty - for the given array property.
*
* Array support is effectively limited to Postgres at this time.
*
*/
ExpressionList arrayIsNotEmpty(String propertyName);
/**
* Add expression for ANY of the given bit flags to be set.
* {@code
*
* where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
*
* }
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList bitwiseAny(String propertyName, long flags);
/**
* Add expression for ALL of the given bit flags to be set.
* {@code
*
* where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
*
* }
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList bitwiseAll(String propertyName, long flags);
/**
* Add expression for the given bit flags to be NOT set.
* {@code
*
* where().bitwiseNot("flags", BwFlags.HAS_COLOUR)
*
* }
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList bitwiseNot(String propertyName, long flags);
/**
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
*
*
{@code
*
* // Flags Bulk + Size = Size
* // ... meaning Bulk is not set and Size is set
*
* long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
* long mask = BwFlags.HAS_SIZE; // Only Size flag set
*
* where().bitwiseAnd("flags", selectedFlags, mask)
*
* }
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList bitwiseAnd(String propertyName, long flags, long match);
/**
* Add raw expression with a single parameter.
*
* The raw expression should contain a single ? or ?1
* at the location of the parameter. We use ?1 when binding a
* collection for an IN expression.
*
* When properties in the clause are fully qualified as table-column names
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
*
*
Examples:
* {@code
*
* // use a database function
* raw("add_days(orderDate, 10) < ?", someDate)
*
* raw("name like ?", "Rob%")
*
* raw("name in (?1)", asList("Rob", "Fiona", "Jack"))
*
* raw("name = any(?)", asList("Rob", "Fiona", "Jack"))
*
* }
*
* Subquery examples:
* {@code
*
* // Bind collection using ?1
* .raw("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
*
* // Using Postgres ANY expression
* .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
*
* }
*/
ExpressionList raw(String raw, Object value);
/**
* Add raw expression with an array of parameters.
*
* The raw expression should contain the same number of ? or ?1, ?2 ... bind parameters
* as there are values. We use ?1, ?2 etc when binding a collection for an IN expression.
*
* When properties in the clause are fully qualified as table-column names
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
*
*
* Examples:
* {@code
*
* raw("unitPrice > ? and product.id > ?", 2, 3)
*
* raw("(status = ? or (orderDate < ? and shipDate is null) or customer.name like ?)",
* Order.Status.APPROVED,
* new Timestamp(System.currentTimeMillis()),
* "Rob")
*
* }
*/
ExpressionList* When properties in the clause are fully qualified as table-column names * then they are not translated. logical property name names (not fully * qualified) will still be translated to their physical name. *
*{@code * * raw("orderQty < shipQty") * * }* *
Subquery example:
*{@code * * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds) * * }*/ ExpressionList
* 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. *
*Without inOrEmpty()
*{@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(); * * }* *
Using rawOrEmpty()
* Note that in the example below we use the?1
bind parameter to get "parameter expansion"
* for each element in the collection.
*
* {@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(); * * }* *
Postgres ANY
* With Postgres we would often use the SQLANY
expression and array parameter binding
* rather than IN
.
*
* {@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(); * * }*
* Note that we need to cast the Postgres array for UUID types like: *
*{@code * * " ... = any(?::uuid[])" * * }* * @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
* This is exactly the same as conjunction(); *
** Use endAnd() or endJunction() to end the AND junction. *
** Note that a where() clause defaults to an AND junction so * typically you only explicitly need to use the and() junction * when it is nested inside an or() or not() junction. *
*{@code * * // Example: Nested and() * * .where() * .or() * .and() // nested and * .startsWith("name", "r") * .eq("anniversary", onAfter) * .endAnd() * .and() * .eq("status", Customer.Status.ACTIVE) * .gt("id", 0) * .endAnd() * .order().asc("name") * .findList(); * }*/ Junction
* Use endOr() or endJunction() to end the OR junction. *
* *{@code * * // Example: (status active OR anniversary is null) * * .where() * .or() * .eq("status", Customer.Status.ACTIVE) * .isNull("anniversary") * .order().asc("name") * .findList(); * * }* *
{@code * * // Example: Use or() to join * // two nested and() expressions * * .where() * .or() * .and() * .startsWith("name", "r") * .eq("anniversary", onAfter) * .endAnd() * .and() * .eq("status", Customer.Status.ACTIVE) * .gt("id", 0) * .endAnd() * .order().asc("name") * .findList(); * * }*/ Junction
* Use endNot() or endJunction() to end expressions being added to the * NOT expression list. *
* *{@code * * .where() * .not() * .gt("id", 1) * .eq("anniversary", onAfter) * .endNot() * * }* *
{@code * * // Example: nested not() * * .where() * .eq("status", Customer.Status.ACTIVE) * .not() * .gt("id", 1) * .eq("anniversary", onAfter) * .endNot() * .order() * .asc("name") * .findList(); * * }*/ Junction
* This is the same as and(). *
*/ Junction* This is the same as or(). *
*/ Junction* This automatically makes the query a useDocStore(true) query that * will execute against the document store (ElasticSearch etc). *
** This is logically similar to and(). *
*/ Junction* This automatically makes the query a useDocStore(true) query that * will execute against the document store (ElasticSearch etc). *
** This is logically similar to or(). *
*/ Junction* This automatically makes the query a useDocStore(true) query that * will execute against the document store (ElasticSearch etc). *
** This is logically similar to not(). *
*/ Junction* Ends a and(), or(), not(), must(), mustNot() or should() junction * such that you get the parent expression. *
** Alternatively you can always use where() to return the top level expression list. *
*/ ExpressionList