package io.ebean; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.persistence.NonUniqueResultException; import java.sql.Connection; import java.sql.Timestamp; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; /** * Object relational query for finding a List, Set, Map or single entity bean. *

* Example: Create the query using the API. *

*

*

{@code
 *
 * List orderList = DB.find(Order.class)
 *     .where()
 *       .like("customer.name","rob%")
 *       .gt("orderDate",lastWeek)
 *     .order("customer.id, id desc")
 *     .setMaxRows(50)
 *     .findList();
 *
 * ...
 * }
*

* Example: The same query using the query language *

*
{@code
 *
 * String oql =
 *   	+" where customer.name like :custName and orderDate > :minOrderDate "
 *   	+" order by customer.id, id desc "
 *   	+" limit 50 ";
 *
 * List orderList = DB.createQuery(Order.class, oql)
 *   .setParameter("custName", "Rob%")
 *   .setParameter("minOrderDate", lastWeek)
 *   .findList();
 * ...
 * }
*

AutoTune

*

* Ebean has built in support for "AutoTune". This is a mechanism where a query * can be automatically tuned based on profiling information that is collected. *

*

* This is effectively the same as automatically using select() and fetch() to * build a query that will fetch all the data required by the application and no * more. *

*

* It is expected that AutoTune will be the default approach for many queries * in a system. It is possibly not as useful where the result of a query is sent * to a remote client or where there is some requirement for "Read Consistency" * guarantees. *

*

Query Language

*

* Partial Objects *

*

* The find and fetch clauses support specifying a list of * properties to fetch. This results in objects that are "partially populated". * If you try to get a property that was not populated a "lazy loading" query * will automatically fire and load the rest of the properties of the bean (This * is very similar behaviour as a reference object being "lazy loaded"). *

*

* Partial objects can be saved just like fully populated objects. If you do * this you should remember to include the "Version" property in the * initial fetch. If you do not include a version property then optimistic * concurrency checking will occur but only include the fetched properties. * Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking. *

*
{@code
 * [ select [ ( * | {fetch properties} ) ] ]
 * [ fetch {path} [ ( * | {fetch properties} ) ] ]
 * [ where {predicates} ]
 * [ order by {order by properties} ]
 * [ limit {max rows} [ offset {first row} ] ]
 * }
*

* SELECT [ ( * | {fetch properties} ) ] *

*

* With the select you can specify a list of properties to fetch. *

*

* FETCH {path} [ ( * | {fetch properties} ) ] *

*

* With the fetch you specify the associated property to fetch and populate. The * path is a OneToOne, ManyToOne, OneToMany or ManyToMany property. *

*

* For fetch of a path we can optionally specify a list of properties to fetch. * If you do not specify a list of properties ALL the properties for that bean * type are fetched. *

*

* WHERE {list of predicates} *

*

* The list of predicates which are joined by AND OR NOT ( and ). They can * include named (or positioned) bind parameters. These parameters will need to * be bound by {@link Query#setParameter(String, Object)}. *

*

* ORDER BY {order by properties} *

*

* The list of properties to order the result. You can include ASC (ascending) * and DESC (descending) in the order by clause. *

*

* LIMIT {max rows} [ OFFSET {first row} ] *

*

* The limit offset specifies the max rows and first row to fetch. The offset is * optional. *

*

Examples of Ebean's Query Language

*

* Find orders fetching its id, shipDate and status properties. Note that the id * property is always fetched even if it is not included in the list of fetch * properties. *

*
{@code
 *
 * select (shipDate, status)
 *
 * }
*

* Find orders with a named bind variable (that will need to be bound via * {@link Query#setParameter(String, Object)}). *

*
{@code
 *
 * where customer.name like :custLike
 *
 * }
*

* Find orders and also fetch the customer with a named bind parameter. This * will fetch and populate both the order and customer objects. *

*
{@code
 *
 * fetch customer
 * where customer.id = :custId
 *
 * }
*

* Find orders and also fetch the customer, customer shippingAddress, order * details and related product. Note that customer and product objects will be * "Partial Objects" with only some of their properties populated. The customer * objects will have their id, name and shipping address populated. The product * objects (associated with each order detail) will have their id, sku and name * populated. *

*
{@code
 *
 * fetch customer (name)
 * fetch customer.shippingAddress
 * fetch details
 * fetch details.product (sku, name)
 *
 * }
* * @param the type of Entity bean this query will fetch. */ public interface Query { /** * The lock type (strength) to use with query FOR UPDATE row locking. */ enum LockType { /** * The default lock type being either UPDATE or NO_KEY_UPDATE based on * PlatformConfig.forUpdateNoKey configuration (Postgres option). */ DEFAULT, /** * FOR UPDATE. */ UPDATE, /** * FOR NO KEY UPDATE (Postgres only). */ NO_KEY_UPDATE, /** * FOR SHARE (Postgres only). */ SHARE, /** * FOR KEY SHARE (Postgres only). */ KEY_SHARE } /** * FOR UPDATE wait mode. */ enum LockWait { /** * Standard For update clause. */ WAIT, /** * For update with No Wait option. */ NOWAIT, /** * For update with Skip Locked option. */ SKIPLOCKED } /** * Set RawSql to use for this query. */ Query setRawSql(RawSql rawSql); /** * 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); /** * Convert the query to a 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(); /** * Cancel the query execution if supported by the underlying database and * driver. *

* This must be called from a different thread to the query executor. *

*/ void cancel(); /** * Return a copy of the query. *

* This is so that you can use a Query as a "prototype" for creating other * query instances. You could create a Query with various where expressions * and use that as a "prototype" - using this copy() method to create a new * instance that you can then add other expressions then execute. *

*/ Query copy(); /** * Specify the PersistenceContextScope to use for this query. *

* When this is not set the 'default' configured on {@link io.ebean.config.DatabaseConfig#setPersistenceContextScope(PersistenceContextScope)} * is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}. *

* Note that the same persistence Context is used for subsequent lazy loading and query join queries. *

* Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for * queries executed as #findIterate, #findEach, #findEachWhile. * * @param scope The scope to use for this query and subsequent lazy loading. */ Query setPersistenceContextScope(PersistenceContextScope scope); /** * 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. *

*
{@code
   *
   *   // explicitly specify the indexes to search
   *   query.setDocIndexName("logstash-2016.11.5,logstash-2016.11.6")
   *
   *   // search today's index
   *   query.setDocIndexName("$today")
   *
   *   // search the last 3 days
   *   query.setDocIndexName("$last-3")
   *
   * }
*

* If the indexName is specified with ${daily} e.g. "logstash-${daily}" ... then we can use * $today and $last-x as the search docIndexName like the examples below. *

*
{@code
   *
   *   // search today's index
   *   query.setDocIndexName("$today")
   *
   *   // search the last 3 days
   *   query.setDocIndexName("$last-3")
   *
   * }
* * @param indexName The index or indexes to search against * @return This query */ Query setDocIndexName(String indexName); /** * Return the ExpressionFactory used by this query. */ ExpressionFactory getExpressionFactory(); /** * Returns true if this query was tuned by autoTune. */ boolean isAutoTuned(); /** * Explicitly specify whether to use AutoTune for this query. *

* If you do not call this method on a query the "Implicit AutoTune mode" is * used to determine if AutoTune should be used for a given query. *

*

* AutoTune can add additional fetch paths to the query and specify which * properties are included for each path. If you have explicitly defined some * fetch paths AutoTune will not remove them. *

*/ Query setAutoTune(boolean autoTune); /** * Execute the query allowing properties with invalid JSON to be collected and not fail the query. *
{@code
   *
   *   // fetch a bean with JSON content
   *   EBasicJsonList bean= DB.find(EBasicJsonList.class)
   *       .setId(42)
   *       .setAllowLoadErrors()  // collect errors into bean state if we have invalid JSON
   *       .findOne();
   *
   *
   *   // get the invalid JSON errors from the bean state
   *   Map errors = server().getBeanState(bean).getLoadErrors();
   *
   *   // If this map is not empty tell we have invalid JSON
   *   // and should try and fix the JSON content or inform the user
   *
   * }
*/ Query setAllowLoadErrors(); /** * Set the default lazy loading batch size to use. *

* When lazy loading is invoked on beans loaded by this query then this sets the * batch size used to load those beans. * * @param lazyLoadBatchSize the number of beans to lazy load in a single batch */ Query setLazyLoadBatchSize(int lazyLoadBatchSize); /** * Execute the query including soft deleted rows. *

* This means that Ebean will not add any predicates to the query for filtering out * soft deleted rows. You can still add your own predicates for the deleted properties * and effectively you have full control over the query to include or exclude soft deleted * rows as needed for a given use case. *

*/ Query setIncludeSoftDeletes(); /** * 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(); /** * Specify the properties to fetch on the root level entity bean in comma delimited format. *

* The Id property is automatically included in the properties to fetch unless setDistinct(true) * is set on the query. *

*

* Use {@link #fetch(String, String)} to specify specific properties to fetch * on other non-root level paths of the object graph. *

*
{@code
   *
   * List customers = DB.find(Customer.class)
   *     // Only fetch the customer id, name and status.
   *     // This is described as a "Partial Object"
   *     .select("name, status")
   *     .where.ilike("name", "rob%")
   *     .findList();
   *
   * }
* * @param fetchProperties the properties to fetch for this bean (* = all properties). */ Query select(String fetchProperties); /** * Apply the fetchGroup which defines what part of the object graph to load. */ Query select(FetchGroup fetchGroup); /** * Specify a path to fetch eagerly including specific properties. *

* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can * not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean * will automatically convert this fetch query into a "query join" - i.e. use fetchQuery(). *

*
{@code
   *
   * // query orders...
   * List orders = DB.find(Order.class)
   *       // fetch the customer...
   *       // ... getting the customers name and phone number
   *       .fetch("customer", "name, phoneNumber")
   *
   *       // ... also fetch the customers billing address (* = all properties)
   *       .fetch("customer.billingAddress", "*")
   *       .findList();
   * }
*

* If columns is null or "*" then all columns/properties for that path are fetched. *

*
{@code
   *
   * // fetch customers (their id, name and status)
   * List customers = DB.find(Customer.class)
   *     .select("name, status")
   *     .fetch("contacts", "firstName,lastName,email")
   *     .findList();
   *
   * }
* * @param path the property path we wish to fetch eagerly. * @param fetchProperties properties of the associated bean that you want to include in the * fetch (* means all properties, null also means all properties). */ Query fetch(String path, String fetchProperties); /** * Fetch the path and properties using a "query join" (separate SQL query). *

* This is the same as: *

*
{@code
   *
   *  fetch(path, fetchProperties, FetchConfig.ofQuery())
   *
   * }
*

* This would be used instead of a fetch() when we use a separate SQL query to fetch this * part of the object graph rather than a SQL join. *

*

* We might typically get a performance benefit when the path to fetch is a OneToMany * or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many * is high. *

* * @param path the property path we wish to fetch eagerly. * @param fetchProperties properties of the associated bean that you want to include in the * fetch (* means all properties, null also means all properties). */ Query fetchQuery(String path, String fetchProperties); /** * Fetch the path and properties using L2 bean cache. * * @param path The path of the beans we are fetching from L2 cache. * @param fetchProperties The properties that should be loaded. */ Query fetchCache(String path, String fetchProperties); /** * Fetch the path and properties lazily (via batch lazy loading). *

* This is the same as: *

*
{@code
   *
   *  fetch(path, fetchProperties, FetchConfig.ofLazy())
   *
   * }
*

* The reason for using fetchLazy() is to either: *

*
    *
  • Control/tune what is fetched as part of lazy loading
  • *
  • Make use of the L2 cache, build this part of the graph from L2 cache
  • *
* * @param path the property path we wish to fetch lazily. * @param fetchProperties properties of the associated bean that you want to include in the * fetch (* means all properties, null also means all properties). */ Query fetchLazy(String path, String fetchProperties); /** * Additionally specify a FetchConfig to use a separate query or lazy loading * to load this path. *
{@code
   *
   * // fetch customers (their id, name and status)
   * List customers = DB.find(Customer.class)
   *     .select("name, status")
   *     .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
   *     .findList();
   *
   * }
* * @param path the property path we wish to fetch eagerly. */ Query fetch(String path, String fetchProperties, FetchConfig fetchConfig); /** * Specify a path to fetch eagerly including all its properties. *

* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can * not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean * will automatically convert this fetch query into a "query join" - i.e. use fetchQuery(). *

*
{@code
   *
   * // fetch customers (their id, name and status)
   * List customers = DB.find(Customer.class)
   *     // eager fetch the contacts
   *     .fetch("contacts")
   *     .findList();
   *
   * }
* * @param path the property path we wish to fetch eagerly. */ Query fetch(String path); /** * Fetch the path eagerly using a "query join" (separate SQL query). *

* This is the same as: *

*
{@code
   *
   *  fetch(path, FetchConfig.ofQuery())
   *
   * }
*

* This would be used instead of a fetch() when we use a separate SQL query to fetch this * part of the object graph rather than a SQL join. *

*

* We might typically get a performance benefit when the path to fetch is a OneToMany * or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many * is high. *

* * @param path the property path we wish to fetch eagerly */ Query fetchQuery(String path); /** * Fetch the path eagerly using L2 cache. */ Query fetchCache(String path); /** * Fetch the path lazily (via batch lazy loading). *

* This is the same as: *

*
{@code
   *
   *  fetch(path, FetchConfig.ofLazy())
   *
   * }
*

* The reason for using fetchLazy() is to either: *

*
    *
  • Control/tune what is fetched as part of lazy loading
  • *
  • Make use of the L2 cache, build this part of the graph from L2 cache
  • *
* * @param path the property path we wish to fetch lazily. */ Query fetchLazy(String path); /** * Additionally specify a JoinConfig to specify a "query join" and or define * the lazy loading query. *
{@code
   *
   * // fetch customers (their id, name and status)
   * List customers = DB.find(Customer.class)
   *     // lazy fetch contacts with a batch size of 100
   *     .fetch("contacts", FetchConfig.ofLazy(100))
   *     .findList();
   *
   * }
*/ Query fetch(String path, FetchConfig fetchConfig); /** * Apply the path properties replacing the select and fetch clauses. *

* This is typically used when the FetchPath is applied to both the query and the JSON output. *

*/ Query apply(FetchPath fetchPath); /** * Execute the query using the given transaction. */ Query usingTransaction(Transaction transaction); /** * Execute the query using the given connection. */ Query usingConnection(Connection connection); /** * Execute the query using the given database. */ Query usingDatabase(Database database); /** * Execute the query returning the list of Id's. *

* This query will execute against the Database that was used to create it. *

*/ @Nonnull List findIds(); /** * Execute the query iterating over the results. *

* Note that findIterate (and findEach and findEachWhile) uses a "per graph" * persistence context scope and adjusts jdbc fetch buffer size for large * queries. As such it is better to use findList for small queries. *

*

* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} * when you have finished iterating the results (typically in a finally block). *

*

* findEach() and findEachWhile() are preferred to findIterate() as they ensure * the jdbc statement and resultSet are closed at the end of the iteration. *

*

* This query will execute against the Database that was used to create it. *

*
{@code
   *
   *  Query query = DB.find(Customer.class)
   *     .where().eq("status", Status.NEW)
   *     .order().asc("id");
   *
   *  // use try with resources to ensure QueryIterator is closed
   *
   *  try (QueryIterator it = query.findIterate()) {
   *    while (it.hasNext()) {
   *      Customer customer = it.next();
   *      // do something with customer ...
   *    }
   *  }
   *
   * }
*/ @Nonnull QueryIterator findIterate(); /** * Execute the query returning the result as a Stream. *

* Note that this can support very large queries iterating * any number of results. To do so internally it can use * multiple persistence contexts. *

*
{@code
   *
   *  // use try with resources to ensure Stream is closed
   *
   *  try (Stream stream = query.findStream()) {
   *    stream
   *    .map(...)
   *    .collect(...);
   *  }
   *
   * }
*/ @Nonnull Stream findStream(); /** * Deprecated - migrate to findStream. *

* Execute the query returning the result as a Stream. *

* Note that this uses multiple persistence contexts such that we can use * it with a large number of results. *

*
{@code
   *
   *  // use try with resources to ensure Stream is closed
   *
   *  try (Stream stream = query.findLargeStream()) {
   *    stream
   *    .map(...)
   *    .collect(...);
   *  }
   *
   * }
*/ @Nonnull @Deprecated Stream findLargeStream(); /** * Execute the query processing the beans one at a time. *

* This method is appropriate to process very large query results as the * beans are consumed one at a time and do not need to be held in memory * (unlike #findList #findSet etc) *

*

* Note that findEach (and findEachWhile and findIterate) uses a "per graph" * persistence context scope and adjusts jdbc fetch buffer size for large * queries. As such it is better to use findList for small queries. *

*

* Note that internally Ebean can inform the JDBC driver that it is expecting larger * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver * from buffering the entire resultSet. As such, for smaller resultSets findList() is * generally preferable. *

*

* Compared with #findEachWhile this will always process all the beans where as * #findEachWhile provides a way to stop processing the query result early before * all the beans have been read. *

*

* This method is functionally equivalent to findIterate() but instead of using an * iterator uses the Consumer interface which is better suited to use with closures. *

*
{@code
   *
   *  DB.find(Customer.class)
   *     .where().eq("status", Status.NEW)
   *     .order().asc("id")
   *     .findEach((Customer customer) -> {
   *
   *       // do something with customer
   *       System.out.println("-- visit " + customer);
   *     });
   *
   * }
* * @param consumer the consumer used to process the queried beans. */ void findEach(Consumer consumer); /** * Execute findEach streaming query batching the results for consuming. *

* This query execution will stream the results and is suited to consuming * large numbers of results from the database. *

* Typically we use this batch consumer when we want to do further processing on * the beans and want to do that processing in batch form, for example - 100 at * a time. * * @param batch The number of beans processed in the batch * @param consumer Process the batch of beans */ void findEach(int batch, Consumer> consumer); /** * Execute the query using callbacks to a visitor to process the resulting * beans one at a time. *

* Note that findEachWhile (and findEach and findIterate) uses a "per graph" * persistence context scope and adjusts jdbc fetch buffer size for large * queries. As such it is better to use findList for small queries. *

*

* This method is functionally equivalent to findIterate() but instead of using an * iterator uses the Predicate interface which is better suited to use with closures. *

*
{@code
   *
   *  DB.find(Customer.class)
   *     .fetchQuery("contacts")
   *     .where().eq("status", Status.NEW)
   *     .order().asc("id")
   *     .setMaxRows(2000)
   *     .findEachWhile((Customer customer) -> {
   *
   *       // do something with customer
   *       System.out.println("-- visit " + customer);
   *
   *       // return true to continue processing or false to stop
   *       return (customer.getId() < 40);
   *     });
   *
   * }
* * @param consumer the consumer used to process the queried beans. */ void findEachWhile(Predicate consumer); /** * Execute the query returning the list of objects. *

* This query will execute against the Database that was used to create it. *

*
{@code
   *
   * List customers = DB.find(Customer.class)
   *     .where().ilike("name", "rob%")
   *     .findList();
   *
   * }
*/ @Nonnull List findList(); /** * Execute the query returning the set of objects. *

* This query will execute against the Database that was used to create it. *

*
{@code
   *
   * Set customers = DB.find(Customer.class)
   *     .where().ilike("name", "rob%")
   *     .findSet();
   *
   * }
*/ @Nonnull Set findSet(); /** * Execute the query returning a map of the objects. *

* This query will execute against the Database that was used to create it. *

*

* You can use setMapKey() so specify the property values to be used as keys * on the map. If one is not specified then the id property is used. *

*
{@code
   *
   * Map map = DB.find(Product.class)
   *     .setMapKey("sku")
   *     .findMap();
   *
   * }
*/ @Nonnull 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 */ @Nonnull
List findSingleAttributeList(); /** * 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();
   *
   * }
*/
A findSingleAttribute(); /** * Return true if this is countDistinct query. */ boolean isCountDistinct(); /** * 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 using a query bean:

*
{@code
   *
   *   boolean userExists =
   *     new QContact()
   *       .email.equalTo("rob@foo.com")
   *       .exists();
   *
   * }
* *

Example:

*
{@code
   *
   *   boolean userExists = query()
   *     .where().eq("email", "rob@foo.com")
   *     .exists();
   *
   * }
* * @return True if the query finds a matching row in the database */ boolean exists(); /** * Execute the query returning either 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. *

*

* This is useful when your predicates dictate that your query should only * return 0 or 1 results. *

*
{@code
   *
   * // assuming the sku of products is unique...
   * Product product = DB.find(Product.class)
   *         .where().eq("sku", "aa113")
   *         .findOne();
   * ...
   * }
*

* It is also useful with finding objects by their id when you want to specify * further join information. *

*
{@code
   *
   * // Fetch order 1 and additionally fetch join its order details...
   * Order order = DB.find(Order.class)
   *       .setId(1)
   *       .fetch("details")
   *       .findOne();
   *
   * // the order details were eagerly loaded
   * List details = order.getDetails();
   * ...
   * }
* * @throws NonUniqueResultException if more than one result was found */ @Nullable T findOne(); /** * Execute the query returning an optional bean. */ @Nonnull Optional findOneOrEmpty(); /** * Return versions of a @History entity bean. *

* Note that this query will work against view based history implementations * but not sql2011 standards based implementations that require a start and * end timestamp to be specified. *

*

* 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. *

*/ @Nonnull 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. *

*/ @Nonnull List> findVersionsBetween(Timestamp start, Timestamp end); /** * 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 beans/rows that were deleted. */ int delete(); /** * Execute as a delete query returning the number of rows deleted using the given transaction. *

* 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 beans/rows that were deleted. */ int delete(Transaction transaction); /** * Execute the UpdateQuery returning the number of rows updated. * * @return the number of beans/rows updated. */ int update(); /** * Execute the UpdateQuery returning the number of rows updated using the given transaction. * * @return the number of beans/rows updated. */ int update(Transaction transaction); /** * Return the count of entities this query should return. *

* This is the number of 'top level' or 'root level' entities. *

*/ int findCount(); /** * 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 */ @Nonnull 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 */ @Nonnull FutureIds findFutureIds(); /** * Execute find list query in a background thread. *

* This query will execute in it's own PersistenceContext and using its own transaction. * What that means is that it will not share any bean instances with other queries. *

* * @return a Future object for the list result of the query */ @Nonnull 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 */ @Nonnull PagedList findPagedList(); /** * Set a named bind parameter. Named parameters have a colon to prefix the name. *
{@code
   *
   * // a query with a named parameter
   * String oql = "find order where status = :orderStatus";
   *
   * List list = DB.find(Order.class, oql)
   *   .setParameter("orderStatus", OrderStatus.NEW)
   *   .findList();
   *
   * }
* * @param name the parameter name * @param value the parameter value */ Query setParameter(String name, Object value); /** * Set an ordered bind parameter according to its position. Note that the * position starts at 1 to be consistent with JDBC PreparedStatement. You need * to set a parameter value for each ? you have in the query. *
{@code
   *
   * // a query with a positioned parameter
   * String oql = "where status = ? order by id desc";
   *
   * List list = DB.createQuery(Order.class, oql)
   *   .setParameter(1, OrderStatus.NEW)
   *   .findList();
   *
   * }
* * @param position the parameter bind position starting from 1 (not 0) * @param value the parameter bind value. */ Query setParameter(int position, Object value); /** * Bind the next positioned parameter. * *
{@code
   *
   * // a query with a positioned parameters
   * String oql = "where status = ? and name = ?";
   *
   * List list = DB.createQuery(Order.class, oql)
   *   .setParameter(OrderStatus.NEW)
   *   .setParameter("Rob")
   *   .findList();
   *
   * }
*/ Query setParameter(Object value); /** * Bind all the positioned parameters. *

* A convenience for multiple calls to {@link #setParameter(Object)} */ Query setParameters(Object... values); /** * Set the Id value to query. This is used with findOne(). *

* You can use this to have further control over the query. For example adding * fetch joins. *

*
{@code
   *
   * Order order = DB.find(Order.class)
   *     .setId(1)
   *     .fetch("details")
   *     .findOne();
   *
   * // the order details were eagerly fetched
   * List details = order.getDetails();
   *
   * }
*/ Query setId(Object id); /** * Return the Id value. */ Object getId(); /** * Add a single Expression to the where clause returning the query. *
{@code
   *
   * List newOrders = DB.find(Order.class)
   * 		.where().eq("status", Order.NEW)
   * 		.findList();
   * ...
   *
   * }
*/ Query where(Expression expression); /** * Add Expressions to the where clause with the ability to chain on the * ExpressionList. You can use this for adding multiple expressions to the * where clause. *
{@code
   *
   * List orders = DB.find(Order.class)
   *     .where()
   *       .eq("status", Order.NEW)
   *       .ilike("customer.name","rob%")
   *     .findList();
   *
   * }
* * @return The ExpressionList for adding expressions to. * @see Expr */ ExpressionList where(); /** * Add Full text search expressions for Document store queries. *

* This is currently ElasticSearch only and provides the full text * expressions such as Match and Multi-Match. *

*

* This automatically makes this query a "Doc Store" query and will execute * against the document store (ElasticSearch). *

*

* Expressions added here are added to the "query" section of an ElasticSearch * query rather than the "filter" section. *

*

* Expressions added to the where() are added to the "filter" section of an * ElasticSearch query. *

*/ ExpressionList text(); /** * This applies a filter on the 'many' property list rather than the root * level objects. *

* Typically you will use this in a scenario where the cardinality is high on * the 'many' property you wish to join to. Say you want to fetch customers * and their associated orders... but instead of getting all the orders for * each customer you only want to get the new orders they placed since last * week. In this case you can use filterMany() to filter the orders. *

*
{@code
   *
   * List list = DB.find(Customer.class)
   *     .fetch("orders")
   *     .where().ilike("name", "rob%")
   *     .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
   *     .findList();
   *
   * }
*

* Please note you have to be careful that you add expressions to the correct * expression list - as there is one for the 'root level' and one for each * filterMany that you have. *

* * @param propertyName the name of the many property that you want to have a filter on. * @return the expression list that you add filter expressions for the many to. */ ExpressionList filterMany(String propertyName); /** * Add Expressions to the Having clause return the ExpressionList. *

* Currently only beans based on raw sql will use the having clause. *

*

* Note that this returns the ExpressionList (so you can add multiple * expressions to the query in a fluent API way). *

* * @return The ExpressionList for adding more expressions to. * @see Expr */ ExpressionList having(); /** * Add an expression to the having clause returning the query. *

* Currently only beans based on raw sql will use the having clause. *

*

* This is similar to {@link #having()} except it returns the query rather * than the ExpressionList. This is useful when you want to further specify * something on the query. *

* * @param addExpressionToHaving the expression to add to the having clause. * @return the Query object */ Query having(Expression addExpressionToHaving); /** * 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. */ Query orderBy(String 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. */ Query order(String orderByClause); /** * 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 orderBy() */ OrderBy order(); /** * 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(); /** * Set an OrderBy object to replace any existing OrderBy clause. */ Query setOrder(OrderBy orderBy); /** * Set an OrderBy object to replace any existing OrderBy clause. */ Query setOrderBy(OrderBy orderBy); /** * 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")
   *          .findList();
   *
   * }
*/ Query setDistinct(boolean isDistinct); /** * 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); /** * Return the first row value. */ int getFirstRow(); /** * Set the first row to return for this query. * * @param firstRow the first row to include in the query result. */ Query setFirstRow(int firstRow); /** * Return the max rows for this query. */ int getMaxRows(); /** * Set the maximum number of rows to return in the query. * * @param maxRows the maximum number of rows to return in the query. */ Query setMaxRows(int maxRows); /** * Set the property to use as keys for a map. *

* If no property is set then the id property is used. *

*
{@code
   *
   * // Assuming sku is unique for products...
   *
   * Map productMap = DB.find(Product.class)
   *     .setMapKey("sku")  // sku map keys...
   *     .findMap();
   *
   * }
* * @param mapKey the property to use as keys for a map. */ Query setMapKey(String mapKey); /** * Set this to false to not use the bean cache. *

* This method is now superseded by {@link #setBeanCacheMode(CacheMode)} * which provides more explicit options controlled bean cache use. *

*

* This method is likely to be deprecated in the future with migration * over to setUseBeanCache(). *

*/ default Query setUseCache(boolean useCache) { return setBeanCacheMode(useCache ? CacheMode.ON : CacheMode.OFF); } /** * Set the mode to use the bean cache when executing this query. *

* By default "find by id" and "find by natural key" will use the bean cache * when bean caching is enabled. Setting this to false means that the query * will not use the bean cache and instead hit the database. *

*

* By default findList() with natural keys will not use the bean cache. In that * case we need to explicitly use the bean cache. *

*/ Query setBeanCacheMode(CacheMode beanCacheMode); /** * Set the {@link CacheMode} to use the query for executing this query. */ Query setUseQueryCache(CacheMode queryCacheMode); /** * Calls {@link #setUseQueryCache(CacheMode)} with ON or OFF. */ default Query setUseQueryCache(boolean enabled) { return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF); } /** * Set the profile location of this query. This is used to relate query execution metrics * back to a location like a specific line of code. */ Query setProfileLocation(ProfileLocation profileLocation); /** * Set a label on the query. *

* This label can be used to help identify query performance metrics but we can also use * profile location enhancement on Finders so for some that would be a better option. *

*/ Query setLabel(String label); /** * 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 useDocStore); /** * When set to true when you want the returned beans to be read only. */ Query setReadOnly(boolean readOnly); /** * Will be deprecated - migrate to use setBeanCacheMode(CacheMode.RECACHE). *

* When set to true all the beans from this query are loaded into the bean cache. */ Query setLoadBeanCache(boolean loadBeanCache); /** * Set a timeout on this query. *

* This will typically result in a call to setQueryTimeout() on a * preparedStatement. If the timeout occurs an exception will be thrown - this * will be a SQLException wrapped up in a PersistenceException. *

* * @param secs the query timeout limit in seconds. Zero means there is no limit. */ Query setTimeout(int secs); /** * A hint which for JDBC translates to the Statement.fetchSize(). *

* Gives the JDBC driver a hint as to the number of rows that should be * fetched from the database when more rows are needed for ResultSet. *

*

* Note that internally findEach and findEachWhile will set the fetch size * if it has not already as these queries expect to process a lot of rows. * If we didn't then Postgres and MySql for example would eagerly pull back * all the row data and potentially consume a lot of memory in the process. *

*

* As findEach and findEachWhile automatically set the fetch size we don't have * to do so generally but we might still wish to for tuning a specific use case. *

*/ Query setBufferFetchSizeHint(int fetchSize); /** * Return the sql that was generated for executing this query. *

* This is only available after the query has been executed and provided only * for informational purposes. *

*/ String getGeneratedSql(); /** * 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(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(LockType lockType, LockWait lockWait); /** * Execute using "for update" clause which results in the DB locking the record. *

* The same as withLock(LockType.UPDATE, LockWait.WAIT). */ Query forUpdate(); /** * Execute using "for update" clause with "no wait" option. *

* This is typically a Postgres and Oracle only option at this stage. *

* The same as withLock(LockType.UPDATE, LockWait.NOWAIT). */ Query forUpdateNoWait(); /** * Execute using "for update" clause with "skip locked" option. *

* This is typically a Postgres and Oracle only option at this stage. *

* The same as withLock(LockType.UPDATE, LockWait.SKIPLOCKED). */ Query forUpdateSkipLocked(); /** * Return true if this query has forUpdate set. */ boolean isForUpdate(); /** * Return the "for update" wait mode to use. */ LockWait getForUpdateLockWait(); /** * Return the lock type (strength) to use with "for update". */ LockType getForUpdateLockType(); /** * Set root table alias. */ Query alias(String alias); /** * Set the base table to use for this query. *

* Typically this is used when a table has partitioning and we wish to specify a specific * partition/table to query against. *

*
{@code
   *
   *   QOrder()
   *   .setBaseTable("order_2019_05")
   *   .status.equalTo(Status.NEW)
   *   .findList();
   *
   * }
*/ Query setBaseTable(String baseTable); /** * Return the type of beans being queried. */ Class getBeanType(); /** * Restrict the query to only return subtypes of the given inherit type. * *
{@code
   *
   *   List animals =
   *     new QAnimal()
   *       .name.startsWith("Fluffy")
   *       .setInheritType(Cat.class)
   *       .findList();
   *
   * }
* * @param type An inheritance subtype of the */ Query setInheritType(Class type); /** * Returns the inherit type. This is normally the same as getBeanType() returns as long as no other type is set. */ Class getInheritType(); /** * Return the type of query being executed. */ QueryType getQueryType(); /** * 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); /** * Returns the set of properties or paths that are unknown (do not map to known properties or paths). *

* Validate the query checking the where and orderBy expression paths to confirm if * they represent valid properties or paths for the given bean type. *

*/ Set validate(); /** * 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); }