package io.ebean;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
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;
/**
* Object relational query for finding a List, Set, Map or single entity bean.
* <p>
* Example: Create the query using the API.
* </p>
* <p>
* <pre>{@code
*
* List<Order> orderList =
* ebeanServer.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .where()
* .like("customer.name","rob%")
* .gt("orderDate",lastWeek)
* .orderBy("customer.id, id desc")
* .setMaxRows(50)
* .findList();
*
* ...
* }</pre>
* <p>
* Example: The same query using the query language
* </p>
* <pre>{@code
*
* String oql =
* +" fetch customer "
* +" fetch details "
* +" where customer.name like :custName and orderDate > :minOrderDate "
* +" order by customer.id, id desc "
* +" limit 50 ";
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
* <p>
* Example: Using a named query called "with.cust.and.details"
* </p>
* <pre>{@code
*
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
* <h3>AutoTune</h3>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <h3>Query Language</h3>
* <p>
* <b>Partial Objects</b>
* </p>
* <p>
* The <em>find</em> and <em>fetch</em> 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").
* </p>
* <p>
* Partial objects can be saved just like fully populated objects. If you do
* this you should remember to include the <em>"Version"</em> 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.
* </p>
* <pre>{@code
* [ select [ ( * | {fetch properties} ) ] ]
* [ fetch {path} [ ( * | {fetch properties} ) ] ]
* [ where {predicates} ]
* [ order by {order by properties} ]
* [ limit {max rows} [ offset {first row} ] ]
* }</pre>
* <p>
* <b>SELECT</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* With the select you can specify a list of properties to fetch.
* </p>
* <p>
* <b>FETCH</b> <b>{path}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* With the fetch you specify the associated property to fetch and populate. The
* path is a OneToOne, ManyToOne, OneToMany or ManyToMany property.
* </p>
* <p>
* 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.
* </p>
* <p>
* <b>WHERE</b> <b>{list of predicates}</b>
* </p>
* <p>
* 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)}.
* </p>
* <p>
* <b>ORDER BY</b> <b>{order by properties}</b>
* </p>
* <p>
* The list of properties to order the result. You can include ASC (ascending)
* and DESC (descending) in the order by clause.
* </p>
* <p>
* <b>LIMIT</b> <b>{max rows}</b> [ OFFSET <i>{first row}</i> ]
* </p>
* <p>
* The limit offset specifies the max rows and first row to fetch. The offset is
* optional.
* </p>
* <h4>Examples of Ebean's Query Language</h4>
* <p>
* 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.
* </p>
* <pre>{@code
*
* select (shipDate, status)
*
* }</pre>
* <p>
* Find orders with a named bind variable (that will need to be bound via
* {@link Query#setParameter(String, Object)}).
* </p>
* <pre>{@code
*
* where customer.name like :custLike
*
* }</pre>
* <p>
* Find orders and also fetch the customer with a named bind parameter. This
* will fetch and populate both the order and customer objects.
* </p>
* <pre>{@code
*
* fetch customer
* where customer.id = :custId
*
* }</pre>
* <p>
* 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.
* </p>
* <pre>{@code
*
* fetch customer (name)
* fetch customer.shippingAddress
* fetch details
* fetch details.product (sku, name)
*
* }</pre>
*
* @param <T> the type of Entity bean this query will fetch.
*/
public interface Query<T> {
/**
* For update mode.
*/
enum ForUpdate {
/**
* Standard For update clause.
*/
BASE,
/**
* For update with No Wait option.
*/
NOWAIT,
/**
* For update with Skip Locked option.
*/
SKIPLOCKED
}
/**
* Return the RawSql that was set to use for this query.
*/
RawSql getRawSql();
/**
* Set RawSql to use for this query.
*/
Query<T> setRawSql(RawSql rawSql);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
* </p>
*
* @param asOf the date time in the past at which you want to view the data
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
Query<T> asDraft();
/**
* Cancel the query execution if supported by the underlying database and
* driver.
* <p>
* This must be called from a different thread to the query executor.
* </p>
*/
void cancel();
/**
* Return a copy of the query.
* <p>
* 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.
* </p>
*/
Query<T> copy();
/**
* 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)}
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
* <p/>
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
* <p/>
* 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<T> setPersistenceContextScope(PersistenceContextScope scope);
/**
* Set the index(es) to search for a document store which uses partitions.
* <p>
* For example, when executing a query against ElasticSearch with daily indexes we can
* explicitly specify the indexes to search against.
* </p>
* <pre>{@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")
*
* }</pre>
* <p>
* 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.
* </p>
* <pre>{@code
*
* // search today's index
* query.setDocIndexName("$today")
*
* // search the last 3 days
* query.setDocIndexName("$last-3")
*
* }</pre>
*
* @param indexName The index or indexes to search against
* @return This query
*/
Query<T> 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.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*/
Query<T> setAutoTune(boolean autoTune);
/**
* Set the default lazy loading batch size to use.
* <p>
* 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<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
/**
* Execute the query including soft deleted rows.
* <p>
* 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.
* </p>
*/
Query<T> setIncludeSoftDeletes();
/**
* Disable read auditing for this query.
* <p>
* 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.
* </p>
*/
Query<T> setDisableReadAuditing();
/**
* Specify the properties to fetch on the root level entity bean in comma delimited format.
* <p>
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
* is set on the query.
* </p>
* <p>
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* ebeanServer.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();
*
* }</pre>
*
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
Query<T> select(String fetchProperties);
/**
* Specify a path to fetch eagerly including specific properties.
* <p>
* 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().
* </p>
* <pre>{@code
*
* // query orders...
* List<Order> orders =
* ebeanServer.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();
* }</pre>
* <p>
* If columns is null or "*" then all columns/properties for that path are fetched.
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email")
* .findList();
*
* }</pre>
*
* @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<T> fetch(String path, String fetchProperties);
/**
* Fetch the path and properties using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().query())
*
* }</pre>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @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<T> fetchQuery(String path, String fetchProperties);
/**
* Fetch the path and properties lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @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<T> fetchLazy(String path, String fetchProperties);
/**
* Additionally specify a FetchConfig to use a separate query or lazy loading
* to load this path.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
Query<T> fetch(String path, String fetchProperties, FetchConfig fetchConfig);
/**
* Specify a path to fetch eagerly including all its properties.
* <p>
* 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().
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* // eager fetch the contacts
* .fetch("contacts")
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
Query<T> fetch(String path);
/**
* Fetch the path eagerly using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().query())
*
* }</pre>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @param path the property path we wish to fetch eagerly
*/
Query<T> fetchQuery(String path);
/**
* Fetch the path lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
*/
Query<T> fetchLazy(String path);
/**
* Additionally specify a JoinConfig to specify a "query join" and or define
* the lazy loading query.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* // lazy fetch contacts with a batch size of 100
* .fetch("contacts", new FetchConfig().lazy(100))
* .findList();
*
* }</pre>
*/
Query<T> fetch(String path, FetchConfig fetchConfig);
/**
* Apply the path properties replacing the select and fetch clauses.
* <p>
* This is typically used when the FetchPath is applied to both the query and the JSON output.
* </p>
*/
Query<T> apply(FetchPath fetchPath);
/**
* Execute the query returning the list of Id's.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
* @see EbeanServer#findIds(Query, Transaction)
*/
<A> List<A> findIds();
/**
* Execute the query iterating over the results.
* <p>
* 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.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
* <p>
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
* </p>
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* ebeanServer.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
*/
QueryIterator<T> findIterate();
/**
* Execute the query processing the beans one at a time.
* <p>
* 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)
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* </p>
* <pre>{@code
*
* ebeanServer.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id")
* .findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEach(Consumer<T> consumer);
/**
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
* <p>
* 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.
* </p>
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* </p>
* <pre>{@code
*
* ebeanServer.find(Customer.class)
* .fetch("contacts", new FetchConfig().query(2))
* .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);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(Predicate<T> consumer);
/**
* Execute the query returning the list of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* .where().ilike("name", "rob%")
* .findList();
*
* }</pre>
*
* @see EbeanServer#findList(Query, Transaction)
*/
List<T> findList();
/**
* Execute the query returning the set of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Set<Customer> customers =
* ebeanServer.find(Customer.class)
* .where().ilike("name", "rob%")
* .findSet();
*
* }</pre>
*
* @see EbeanServer#findSet(Query, Transaction)
*/
Set<T> findSet();
/**
* Execute the query returning a map of the objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <p>
* 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.
* </p>
* <pre>{@code
*
* Map<String, Product> map =
* ebeanServer.find(Product.class)
* .setMapKey("sku")
* .findMap();
*
* }</pre>
*
* @see EbeanServer#findMap(Query, Transaction)
*/
<K> Map<K, T> findMap();
/**
* Execute the query returning a list of values for a single property.
* <p>
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
* <p>
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
* <p>
* If more than 1 row is found for this query then a NonUniqueResultException is
* thrown.
* </p>
* <p>
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
* </p>
* <pre>{@code
*
* // assuming the sku of products is unique...
* Product product =
* ebeanServer.find(Product.class)
* .where().eq("sku", "aa113")
* .findUnique();
* ...
* }</pre>
* <p>
* It is also useful with finding objects by their id when you want to specify
* further join information.
* </p>
* <pre>{@code
*
* // Fetch order 1 and additionally fetch join its order details...
* Order order =
* ebeanServer.find(Order.class)
* .setId(1)
* .fetch("details")
* .findUnique();
*
* // the order details were eagerly loaded
* List<OrderDetail> details = order.getDetails();
* ...
* }</pre>
*
* @throws NonUniqueResultException if more than one result was found
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
T findUnique();
/**
* Return versions of a @History entity bean.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*/
List<Version<T>> findVersions();
/**
* Return versions of a @History entity bean between the 2 timestamps.
* <p>
* 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.
* </p>
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @return the number of beans/rows that were deleted.
*/
int delete();
/**
* Execute the UpdateQuery returning the number of rows updated.
*/
int update();
/**
* Return the count of entities this query should return.
* <p>
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findCount();
/**
* Execute find row count query in a background thread.
* <p>
* 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).
* </p>
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
* <p>
* 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).
* </p>
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
/**
* Execute find list query in a background thread.
* <p>
* 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.
* </p>
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* </p>
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*/
PagedList<T> findPagedList();
/**
* Set a named bind parameter. Named parameters have a colon to prefix the name.
* <pre>{@code
*
* // a query with a named parameter
* String oql = "find order where status = :orderStatus";
*
* Query<Order> query = ebeanServer.find(Order.class, oql);
*
* // bind the named parameter
* query.bind("orderStatus", OrderStatus.NEW);
* List<Order> list = query.findList();
*
* }</pre>
*
* @param name the parameter name
* @param value the parameter value
*/
Query<T> 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.
* <pre>{@code
*
* // a query with a positioned parameter
* String oql = "where status = ? order by id desc";
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
*
* // bind the parameter
* query.setParameter(1, OrderStatus.NEW);
*
* List<Order> list = query.findList();
*
* }</pre>
*
* @param position the parameter bind position starting from 1 (not 0)
* @param value the parameter bind value.
*/
Query<T> setParameter(int position, Object value);
/**
* Set the Id value to query. This is used with findUnique().
* <p>
* You can use this to have further control over the query. For example adding
* fetch joins.
* </p>
* <pre>{@code
*
* Order order =
* ebeanServer.find(Order.class)
* .setId(1)
* .fetch("details")
* .findUnique();
*
* // the order details were eagerly fetched
* List<OrderDetail> details = order.getDetails();
*
* }</pre>
*/
Query<T> setId(Object id);
/**
* Return the Id value.
*/
Object getId();
/**
* Add a single Expression to the where clause returning the query.
* <pre>{@code
*
* List<Order> newOrders =
* ebeanServer.find(Order.class)
* .where().eq("status", Order.NEW)
* .findList();
* ...
*
* }</pre>
*/
Query<T> 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.
* <pre>{@code
*
* List<Order> orders =
* ebeanServer.find(Order.class)
* .where()
* .eq("status", Order.NEW)
* .ilike("customer.name","rob%")
* .findList();
*
* }</pre>
*
* @return The ExpressionList for adding expressions to.
* @see Expr
*/
ExpressionList<T> where();
/**
* Add Full text search expressions for Document store queries.
* <p>
* This is currently ElasticSearch only and provides the full text
* expressions such as Match and Multi-Match.
* </p>
* <p>
* This automatically makes this query a "Doc Store" query and will execute
* against the document store (ElasticSearch).
* </p>
* <p>
* Expressions added here are added to the "query" section of an ElasticSearch
* query rather than the "filter" section.
* </p>
* <p>
* Expressions added to the where() are added to the "filter" section of an
* ElasticSearch query.
* </p>
*/
ExpressionList<T> text();
/**
* This applies a filter on the 'many' property list rather than the root
* level objects.
* <p>
* 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.
* </p>
* <pre>{@code
*
* List<Customer> list =
* ebeanServer.find(Customer.class)
* // .fetch("orders", new FetchConfig().lazy())
* // .fetch("orders", new FetchConfig().query())
* .fetch("orders")
* .where().ilike("name", "rob%")
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
* .findList();
*
* }</pre>
* <p>
* 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.
* </p>
*
* @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<T> filterMany(String propertyName);
/**
* Add Expressions to the Having clause return the ExpressionList.
* <p>
* Currently only beans based on raw sql will use the having clause.
* </p>
* <p>
* Note that this returns the ExpressionList (so you can add multiple
* expressions to the query in a fluent API way).
* </p>
*
* @return The ExpressionList for adding more expressions to.
* @see Expr
*/
ExpressionList<T> having();
/**
* Add an expression to the having clause returning the query.
* <p>
* Currently only beans based on raw sql will use the having clause.
* </p>
* <p>
* 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.
* </p>
*
* @param addExpressionToHaving the expression to add to the having clause.
* @return the Query object
*/
Query<T> having(Expression addExpressionToHaving);
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
* <p>
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
* </p>
* <p>
* This is EXACTLY the same as {@link #order(String)}.
* </p>
*/
Query<T> orderBy(String orderByClause);
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
* <p>
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
* </p>
* <p>
* This is EXACTLY the same as {@link #orderBy(String)}.
* </p>
*/
Query<T> order(String orderByClause);
/**
* Return the OrderBy so that you can append an ascending or descending
* property to the order by clause.
* <p>
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
* </p>
* <p>
* This is EXACTLY the same as {@link #orderBy()}.
* </p>
*/
OrderBy<T> order();
/**
* Return the OrderBy so that you can append an ascending or descending
* property to the order by clause.
* <p>
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
* </p>
* <p>
* This is EXACTLY the same as {@link #order()}.
* </p>
*/
OrderBy<T> orderBy();
/**
* Set an OrderBy object to replace any existing OrderBy clause.
* <p>
* This is EXACTLY the same as {@link #setOrderBy(OrderBy)}.
* </p>
*/
Query<T> setOrder(OrderBy<T> orderBy);
/**
* Set an OrderBy object to replace any existing OrderBy clause.
* <p>
* This is EXACTLY the same as {@link #setOrder(OrderBy)}.
* </p>
*/
Query<T> setOrderBy(OrderBy<T> orderBy);
/**
* Set whether this query uses DISTINCT.
* <p>
* 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.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .findList();
*
* }</pre>
*/
Query<T> setDistinct(boolean isDistinct);
/**
* 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<T> 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<T> setMaxRows(int maxRows);
/**
* Set the property to use as keys for a map.
* <p>
* If no property is set then the id property is used.
* </p>
* <pre>{@code
*
* // Assuming sku is unique for products...
*
* Map<?,Product> productMap =
* ebeanServer.find(Product.class)
* // use sku for keys...
* .setMapKey("sku")
* .findMap();
*
* }</pre>
*
* @param mapKey the property to use as keys for a map.
*/
Query<T> setMapKey(String mapKey);
/**
* Set this to false to not use the bean cache.
* <p>
* 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.
* </p>
* <p>
* In the case of other queries (findList(), findEach() etc) then setting this to
* false beans that the if lazy loading is invoked that lazy loading will not try
* to use the bean cache.
* </p>
*/
Query<T> setUseCache(boolean useCache);
/**
* Set this to true to use the query cache.
*/
Query<T> setUseQueryCache(boolean useQueryCache);
/**
* Set to true if this query should execute against the doc store.
* <p>
* When setting this you may also consider disabling lazy loading.
* </p>
*/
Query<T> setUseDocStore(boolean useDocStore);
/**
* When set to true when you want the returned beans to be read only.
*/
Query<T> setReadOnly(boolean readOnly);
/**
* When set to true all the beans from this query are loaded into the bean
* cache.
*/
Query<T> setLoadBeanCache(boolean loadBeanCache);
/**
* Set a timeout on this query.
* <p>
* 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.
* </p>
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
Query<T> setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*/
Query<T> setBufferFetchSizeHint(int fetchSize);
/**
* Return the sql that was generated for executing this query.
* <p>
* This is only available after the query has been executed and provided only
* for informational purposes.
* </p>
*/
String getGeneratedSql();
/**
* executed the select with "for update" which should lock the record
* "on read"
*/
Query<T> setForUpdate(boolean forUpdate);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Return the "for update" mode to use.
*/
ForUpdate getForUpdateMode();
/**
* Set root table alias.
*/
Query<T> alias(String alias);
/**
* Return the type of beans being queried.
*/
Class<T> getBeanType();
/**
* Set true if you want to disable lazy loading.
* <p>
* That is, once the object graph is returned further lazy loading is disabled.
* </p>
*/
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
/**
* Returns the set of properties or paths that are unknown (do not map to known properties or paths).
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties or paths for the given bean type.
* </p>
*/
Set<String> validate();
}