diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/QueryBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/QueryBean.java new file mode 100644 index 000000000..00ad8fadf --- /dev/null +++ b/ebean-querybean/src/main/java/io/ebean/typequery/QueryBean.java @@ -0,0 +1,1680 @@ +package io.ebean.typequery; + +import io.avaje.lang.Nullable; +import io.ebean.*; +import io.ebean.search.MultiMatch; +import io.ebean.search.TextCommonTerms; +import io.ebean.search.TextQueryString; +import io.ebean.search.TextSimple; +import io.ebean.text.PathProperties; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.Timestamp; +import java.util.*; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Query bean for strongly typed query construction and execution. + *
+ * For each entity bean querybean-generator generates a query bean that implements QueryBean. + * + *
{@code
+ *
+ * Date fiveDaysAgo = ...
+ *
+ * List customers =
+ * new QCustomer()
+ * .name.ilike("rob")
+ * .status.equalTo(Customer.Status.GOOD)
+ * .registered.after(fiveDaysAgo)
+ * .contacts.email.endsWith("@foo.com")
+ * .orderBy()
+ * .name.asc()
+ * .registered.desc()
+ * .findList();
+ *
+ * }
+ * + *
{@code
+ *
+ * where lower(t0.name) like ? and t0.status = ? and t0.registered > ? and u1.email like ?
+ * order by t0.name, t0.registered desc;
+ *
+ * --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com)
+ *
+ * }
+ *
+ * @param
+ * Generally it is not expected that you will need to do this but typically use
+ * the find methods available on this 'root query bean' instance like findList().
+ */
+ Query
+ * You use {@link #fetch(String, String)} to specify specific properties to fetch
+ * on other non-root level paths of the object graph.
+ *
+ *
+ * FetchGroup is immutable and threadsafe. We expect to create and store
+ * FetchGroup to a static final field and reuse the instance.
+ *
+ * FetchGroup is an alternative to using select() and fetch() providing a nice
+ * clean separation between what a query should load and the query predicates.
+ *
+ *
+ * The resulting entities with be "partially loaded" aka partial objects.
+ *
+ * Alternatively we can use a {@link #select(FetchGroup)} to specify all properties
+ * to load on all parts of the graph.
+ *
+ *
+ * When you specify a join this means that property (associated bean(s)) will
+ * be fetched and populated. If you specify "*" then all the properties of the
+ * associated bean will be fetched and populated. You can specify a comma
+ * delimited list of the properties of that associated bean which means that
+ * only those properties are fetched and populated resulting in a
+ * "Partial Object" - a bean that only has some of its properties populated.
+ *
+ *
+ * If columns is null or "*" then all columns/properties for that path are fetched.
+ *
+ *
+ *
+ *
+ * This is typically used when the PathProperties is applied to both the query and the JSON output.
+ */
+ R apply(PathProperties pathProperties);
+
+ /**
+ * Apply changes to the query conditional on the supplied predicate.
+ *
+ * Typically, the changes are extra predicates etc.
+ *
+ * @param predicate The predicate which when true the changes are applied
+ * @param apply The changes to apply to the query
+ */
+ R alsoIf(BooleanSupplier predicate, Consumer
+ * 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
+ */
+ R asOf(Timestamp asOf);
+
+ /**
+ * Execute the query against the draft set of tables.
+ */
+ R asDraft();
+
+ /**
+ * Execute the query including soft deleted rows.
+ */
+ R setIncludeSoftDeletes();
+
+ /**
+ * Add an expression to the WHERE or HAVING clause.
+ */
+ R add(Expression expression);
+
+ /**
+ * Set root table alias.
+ */
+ R alias(String alias);
+
+ /**
+ * Set the maximum number of rows to return in the query.
+ *
+ * @param maxRows the maximum number of rows to return in the query.
+ */
+ R setMaxRows(int maxRows);
+
+ /**
+ * Set the first row to return for this query.
+ *
+ * @param firstRow the first row to include in the query result.
+ */
+ R setFirstRow(int firstRow);
+
+ /**
+ * Execute the query allowing properties with invalid JSON to be collected and not fail the 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.
+ */
+ R setAutoTune(boolean autoTune);
+
+ /**
+ * 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.
+ */
+ R setBufferFetchSizeHint(int fetchSize);
+
+ /**
+ * Set whether this query uses DISTINCT.
+ */
+ R 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.
+ *
+ *
+ * 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.
+ *
+ * Typically this is used when a table has partitioning and we wish to specify a specific
+ * partition/table to query against.
+ *
+ * Note that
+ * Provides us with the ability to explicitly use Postgres
+ * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
+ */
+ R withLock(Query.LockType lockType);
+
+ /**
+ * Execute the query with the given lock type and lock wait.
+ *
+ * Note that
+ * Provides us with the ability to explicitly use Postgres
+ * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
+ */
+ R withLock(Query.LockType lockType, Query.LockWait lockWait);
+
+ /**
+ * Add EXISTS sub-query predicate.
+ */
+ R exists(Query> subQuery);
+
+ /**
+ * Add NOT EXISTS sub-query predicate.
+ */
+ R notExists(Query> subQuery);
+
+ /**
+ * EXISTS using a SQL SubQuery.
+ *
+ * @param sqlSubQuery The SQL SubQuery
+ * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
+ */
+ R exists(String sqlSubQuery, Object... bindValues);
+
+ /**
+ * Not EXISTS using a SQL SubQuery.
+ *
+ * @param sqlSubQuery The SQL SubQuery
+ * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
+ */
+ R notExists(String sqlSubQuery, Object... bindValues);
+
+ /**
+ * Execute using "for update" clause which results in the DB locking the record.
+ */
+ R forUpdate();
+
+ /**
+ * Execute using "for update" clause with "no wait" option.
+ *
+ * This is typically a Postgres and Oracle only option at this stage.
+ */
+ R forUpdateNoWait();
+
+ /**
+ * Execute using "for update" clause with "skip locked" option.
+ *
+ * This is typically a Postgres and Oracle only option at this stage.
+ */
+ R forUpdateSkipLocked();
+
+ /**
+ * Return this query as an UpdateQuery.
+ *
+ *
+ * We effectively use the underlying ORM query to build the SQL and then execute
+ * and map it into DTO beans.
+ */
+
+ * You can use this to have further control over the query. For example adding fetch joins.
+ *
+ *
+ *
+ *
+ * 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.
+ */
+ R setLabel(String label);
+
+ /**
+ * Set a SQL query hint.
+ *
+ * This results in an inline comment that immediately follows
+ * after the select keyword in the form: {@code /*+ hint *\/ }
+ */
+ R setHint(String hint);
+
+ /**
+ * Set the profile location.
+ *
+ * This is typically set automatically via enhancement when profile location enhancement
+ * is turned on. It is generally not set by application code.
+ */
+ R setProfileLocation(ProfileLocation profileLocation);
+
+ /**
+ * 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
+ */
+ R setLazyLoadBatchSize(int lazyLoadBatchSize);
+
+ /**
+ * Set the property to use as keys for a map.
+ *
+ * If no property is set then the id property is used.
+ *
+ *
+ * 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.
+ */
+ R setPersistenceContextScope(PersistenceContextScope scope);
+
+ /**
+ * Set RawSql to use for this query.
+ */
+ R setRawSql(RawSql rawSql);
+
+ /**
+ * When set to true when you want the returned beans to be read only.
+ */
+ R setReadOnly(boolean readOnly);
+
+ /**
+ * Set this to true to use the bean cache.
+ *
+ * If the query result is in cache then by default this same instance is
+ * returned. In this sense it should be treated as a read only object graph.
+ */
+ R setUseCache(boolean useCache);
+
+ /**
+ * 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.
+ */
+ R setBeanCacheMode(CacheMode beanCacheMode);
+
+ /**
+ * Set to true if this query should execute against the doc store.
+ *
+ * When setting this you may also consider disabling lazy loading.
+ */
+ R setUseDocStore(boolean useDocStore);
+
+ /**
+ * Set true if you want to disable lazy loading.
+ *
+ * That is, once the object graph is returned further lazy loading is disabled.
+ */
+ R 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.
+ */
+ R setDisableReadAuditing();
+
+ /**
+ * Set this to true to use the query cache.
+ */
+ R setUseQueryCache(boolean useCache);
+
+ /**
+ * Set the {@link CacheMode} to use the query for executing this query.
+ */
+ R setUseQueryCache(CacheMode cacheMode);
+
+ /**
+ * 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.
+ */
+ R setTimeout(int secs);
+
+ /**
+ * 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
+ * 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.
+ *
+ *
+ * The raw expression should contain the same number of ? as there are
+ * parameters.
+ *
+ * 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.
+ */
+ R raw(String rawExpression, Object... bindValues);
+
+ /**
+ * Only add the raw expression if the values is not null or empty.
+ *
+ * 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.
+ *
+ *
+ * Note that we need to cast the Postgres array for UUID types like:
+ *
+ * The raw expression should contain a single ? at the location of the
+ * parameter.
+ *
+ * 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.
+ *
+ *
+ *
+ * This follows SQL syntax using commas between each property with the
+ * optional asc and desc keywords representing ascending and descending order
+ * respectively.
+ */
+ R orderBy(String orderByClause);
+
+ /**
+ * @deprecated migrate to {@link #orderBy(String)}
+ */
+ @Deprecated(since = "13.19", forRemoval = true)
+ R order(String orderByClause);
+
+ /**
+ * Begin a list of expressions added by 'OR'.
+ *
+ * Use endOr() or endJunction() to stop added to OR and 'pop' to the parent expression list.
+ *
+ *
+ * This example uses an 'OR' expression list with an inner 'AND' expression list.
+ *
+ * Use endAnd() or endJunction() to stop added to AND and 'pop' to the parent expression list.
+ *
+ * Note that typically the AND expression is only used inside an outer 'OR' expression.
+ * This is because the top level expression list defaults to an 'AND' expression list.
+ *
+ *
+ * This example uses an 'OR' expression list with an inner 'AND' expression list.
+ *
+ * Use endNot() or endJunction() to stop added to NOT and 'pop' to the parent expression list.
+ */
+ R not();
+
+ /**
+ * Begin a list of expressions added by MUST.
+ *
+ * This automatically makes this query a document store query.
+ *
+ * Use endJunction() to stop added to MUST and 'pop' to the parent expression list.
+ */
+ R must();
+
+ /**
+ * Begin a list of expressions added by MUST NOT.
+ *
+ * This automatically makes this query a document store query.
+ *
+ * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list.
+ */
+ R mustNot();
+
+ /**
+ * Begin a list of expressions added by SHOULD.
+ *
+ * This automatically makes this query a document store query.
+ *
+ * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list.
+ */
+ R should();
+
+ /**
+ * End a list of expressions added by 'OR'.
+ */
+ R endJunction();
+
+ /**
+ * End OR junction - synonym for endJunction().
+ */
+ R endOr();
+
+ /**
+ * End AND junction - synonym for endJunction().
+ */
+ R endAnd();
+
+ /**
+ * End NOT junction - synonym for endJunction().
+ */
+ R endNot();
+
+ /**
+ * Add expression after this to the WHERE expression list.
+ *
+ * For queries against the normal database (not the doc store) this has no effect.
+ *
+ * This is intended for use with Document Store / ElasticSearch where expressions can be put into either
+ * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the
+ * "query" section but many expression can be in either - expressions after the where() are put into the
+ * "filter" section which means that they don't add to the relevance and are also cache-able.
+ */
+ R where();
+
+ /**
+ * Begin added expressions to the 'Text' expression list.
+ *
+ * This automatically makes the query a document store query.
+ *
+ * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context'
+ * and expressions added to 'where' go into the ElasticSearch 'filter context'.
+ */
+ R text();
+
+ /**
+ * Add a Text Multi-match expression (document store only).
+ *
+ * This automatically makes the query a document store query.
+ */
+ R multiMatch(String query, MultiMatch multiMatch);
+
+ /**
+ * Add a Text Multi-match expression (document store only).
+ *
+ * This automatically makes the query a document store query.
+ */
+ R multiMatch(String query, String... properties);
+
+ /**
+ * Add a Text common terms expression (document store only).
+ *
+ * This automatically makes the query a document store query.
+ */
+ R textCommonTerms(String query, TextCommonTerms options);
+
+ /**
+ * Add a Text simple expression (document store only).
+ *
+ * This automatically makes the query a document store query.
+ */
+ R textSimple(String query, TextSimple options);
+
+ /**
+ * Add a Text query string expression (document store only).
+ *
+ * This automatically makes the query a document store query.
+ */
+ R textQueryString(String query, TextQueryString options);
+
+ /**
+ * Execute the query using the given transaction.
+ */
+ R usingTransaction(Transaction transaction);
+
+ /**
+ * Execute the query using the given connection.
+ */
+ R usingConnection(Connection connection);
+
+ /**
+ * Ensure that the master DataSource is used if there is a read only data source
+ * being used (that is using a read replica database potentially with replication lag).
+ *
+ * When the database is configured with a read-only DataSource via
+ * say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
+ * by default when a query is run without an active transaction, it uses the read-only data
+ * source. We we use {@code usingMaster()} to instead ensure that the query is executed
+ * against the master data source.
+ */
+ R usingMaster();
+
+ /**
+ * 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.
+ *
+ *
+ * If more than 1 row is found for this query then a PersistenceException is
+ * thrown.
+ *
+ * This is useful when your predicates dictate that your query should only
+ * return 0 or 1 results.
+ *
+ *
+ * It is also useful with finding objects by their id when you want to specify
+ * further join information to optimise the query.
+ *
+ *
+ * This query will execute against the EbeanServer that was used to create it.
+ *
+ *
+ * Note that this can support very large queries iterating
+ * any number of results. To do so internally it can use
+ * multiple persistence contexts.
+ *
+ * This query will execute against the EbeanServer that was used to create it.
+ *
+ *
+ * This query will execute against the EbeanServer that was used to create it.
+ *
+ * @see Query#findIds()
+ */
+ List findIds();
+
+ /**
+ * Execute the query returning a map of the objects.
+ *
+ * This query will execute against the EbeanServer that was used to create it.
+ *
+ * You can use setMapKey() or asMapKey() to specify the property to be used as keys
+ * on the map. If one is not specified then the id property is used.
+ *
+ *
+ * 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 EbeanServer that was used to create it.
+ *
+ *
+ *
+ *
+ * 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 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.
+ *
+ *
+ * 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
+ * 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.
+ *
+ *
+ * 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
+ * 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
+ * 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
+ */
+ FutureRowCount
+ * 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
+ * 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
+ */
+ FutureList
+ * 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.
+ *
+ *
+ * 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();
+
+ /**
+ * 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();
+
+ /**
+ * Return the type of beans being queried.
+ */
+ Class
+ * Note that after this we no longer have the query bean so typically we use this right
+ * at the end of the query.
+ *
+ *
* For each entity bean querybean-generator generates a query bean that extends TQRootBean.
- *
*
- *
- * Generally it is not expected that you will need to do this but typically use
- * the find methods available on this 'root query bean' instance like findList().
- *
- * You use {@link #fetch(String, String)} to specify specific properties to fetch
- * on other non-root level paths of the object graph.
- *
- *
- * FetchGroup is immutable and threadsafe. We expect to create and store
- * FetchGroup to a static final field and reuse the instance.
- *
- * FetchGroup is an alternative to using select() and fetch() providing a nice
- * clean separation between what a query should load and the query predicates.
- *
- *
- * The resulting entities with be "partially loaded" aka partial objects.
- *
- * Alternatively we can use a {@link #select(FetchGroup)} to specify all properties
- * to load on all parts of the graph.
- *
- *
- * When you specify a join this means that property (associated bean(s)) will
- * be fetched and populated. If you specify "*" then all the properties of the
- * associated bean will be fetched and populated. You can specify a comma
- * delimited list of the properties of that associated bean which means that
- * only those properties are fetched and populated resulting in a
- * "Partial Object" - a bean that only has some of its properties populated.
- *
- *
- * If columns is null or "*" then all columns/properties for that path are fetched.
- *
- *
- *
- * This is typically used when the PathProperties is applied to both the query and the JSON output.
- *
- * Typically, the changes are extra predicates etc.
- *
- * @param predicate The predicate which when true the changes are applied
- * @param apply The changes to apply to the query
- */
+ @Override
public final R alsoIf(BooleanSupplier predicate, Consumer
- * To perform this query the DB must have underlying history tables.
- *
- * 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.
- *
- * 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.
- *
- * For example, when executing a query against ElasticSearch with daily indexes we can
- * explicitly specify the indexes to search against.
- *
- * 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.
- *
- * Typically this is used when a table has partitioning and we wish to specify a specific
- * partition/table to query against.
- *
- * Note that
- * Provides us with the ability to explicitly use Postgres
- * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
- */
+ @Override
public final R withLock(Query.LockType lockType) {
query.withLock(lockType);
return root;
}
- /**
- * Execute the query with the given lock type and lock wait.
- *
- * Note that
- * Provides us with the ability to explicitly use Postgres
- * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
- */
+ @Override
public final R withLock(Query.LockType lockType, Query.LockWait lockWait) {
query.withLock(lockType, lockWait);
return root;
}
- /**
- * Add EXISTS sub-query predicate.
- */
+ @Override
public final R exists(Query> subQuery) {
peekExprList().exists(subQuery);
return root;
}
- /**
- * Add NOT EXISTS sub-query predicate.
- */
+ @Override
public final R notExists(Query> subQuery) {
peekExprList().notExists(subQuery);
return root;
}
- /**
- * EXISTS using a SQL SubQuery.
- *
- * @param sqlSubQuery The SQL SubQuery
- * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
- */
+ @Override
public final R exists(String sqlSubQuery, Object... bindValues) {
peekExprList().exists(sqlSubQuery, bindValues);
return root;
}
- /**
- * Not EXISTS using a SQL SubQuery.
- *
- * @param sqlSubQuery The SQL SubQuery
- * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values.
- */
+ @Override
public final R notExists(String sqlSubQuery, Object... bindValues) {
peekExprList().notExists(sqlSubQuery, bindValues);
return root;
}
- /**
- * Execute using "for update" clause which results in the DB locking the record.
- */
+ @Override
public final R forUpdate() {
query.forUpdate();
return root;
}
- /**
- * Execute using "for update" clause with "no wait" option.
- *
- * This is typically a Postgres and Oracle only option at this stage.
- */
+ @Override
public final R forUpdateNoWait() {
query.forUpdateNoWait();
return root;
}
- /**
- * Execute using "for update" clause with "skip locked" option.
- *
- * This is typically a Postgres and Oracle only option at this stage.
- *
- * We effectively use the underlying ORM query to build the SQL and then execute
- * and map it into DTO beans.
- */
+ @Override
public final
- * You can use this to have further control over the query. For example adding
- * fetch joins.
- *
- *
- *
- *
- * 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.
- *
- * This results in an inline comment that immediately follows
- * after the select keyword in the form: {@code /*+ hint *\/ }
- */
+ @Override
public final R setHint(String hint) {
query.setHint(hint);
return root;
}
- /**
- * Set the profile location.
- *
- * This is typically set automatically via enhancement when profile location enhancement
- * is turned on. It is generally not set by application code.
- *
- * 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
- */
+ @Override
public final R setLazyLoadBatchSize(int lazyLoadBatchSize) {
query.setLazyLoadBatchSize(lazyLoadBatchSize);
return root;
}
- /**
- * Set the property to use as keys for a map.
- *
- * If no property is set then the id property is used.
- *
- *
- * When this is not set the 'default' configured on {@link io.ebean.config.DatabaseConfig#setPersistenceContextScope(PersistenceContextScope)}
- * is used - this value defaults to {@link io.ebean.PersistenceContextScope#TRANSACTION}.
- *
- * 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.
- */
+ @Override
public final R setPersistenceContextScope(PersistenceContextScope scope) {
query.setPersistenceContextScope(scope);
return root;
}
- /**
- * Set RawSql to use for this query.
- */
+ @Override
public final R setRawSql(RawSql rawSql) {
query.setRawSql(rawSql);
return root;
}
- /**
- * When set to true when you want the returned beans to be read only.
- */
+ @Override
public final R setReadOnly(boolean readOnly) {
query.setReadOnly(readOnly);
return root;
}
- /**
- * Set this to true to use the bean cache.
- *
- * If the query result is in cache then by default this same instance is
- * returned. In this sense it should be treated as a read only object graph.
- */
+ @Override
public final R setUseCache(boolean useCache) {
query.setUseCache(useCache);
return root;
}
- /**
- * 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.
- */
+ @Override
public final R setBeanCacheMode(CacheMode beanCacheMode) {
query.setBeanCacheMode(beanCacheMode);
return root;
}
- /**
- * Set to true if this query should execute against the doc store.
- *
- * When setting this you may also consider disabling lazy loading.
- */
+ @Override
public final R setUseDocStore(boolean useDocStore) {
query.setUseDocStore(useDocStore);
return root;
}
- /**
- * Set true if you want to disable lazy loading.
- *
- * That is, once the object graph is returned further lazy loading is disabled.
- */
+ @Override
public final R setDisableLazyLoading(boolean disableLazyLoading) {
query.setDisableLazyLoading(disableLazyLoading);
return root;
}
- /**
- * 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.
- */
+ @Override
public final R setDisableReadAuditing() {
query.setDisableReadAuditing();
return root;
}
- /**
- * Set this to true to use the query cache.
- */
+ @Override
public final R setUseQueryCache(boolean useCache) {
query.setUseQueryCache(useCache);
return root;
}
- /**
- * Set the {@link CacheMode} to use the query for executing this query.
- */
+ @Override
public final R setUseQueryCache(CacheMode cacheMode) {
query.setUseQueryCache(cacheMode);
return root;
}
- /**
- * 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.
- */
+ @Override
public final R setTimeout(int secs) {
query.setTimeout(secs);
return root;
}
- /**
- * 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.
- */
+ @Override
public final Set
- * 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.
- *
- *
- * The raw expression should contain the same number of ? as there are
- * parameters.
- *
- * 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.
- */
+ @Override
public final R raw(String rawExpression, Object... bindValues) {
peekExprList().raw(rawExpression, bindValues);
return root;
}
- /**
- * Only add the raw expression if the values is not null or empty.
- *
- * 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.
- *
- * Note that we need to cast the Postgres array for UUID types like:
- *
- * The raw expression should contain a single ? at the location of the
- * parameter.
- *
- * 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.
- *
- *
- *
- * This follows SQL syntax using commas between each property with the
- * optional asc and desc keywords representing ascending and descending order
- * respectively.
- */
+ @Override
public final R orderBy(String orderByClause) {
query.orderBy(orderByClause);
return root;
}
- /**
- * @deprecated migrate to {@link #orderBy(String)}
- */
+ @Override
@Deprecated(since = "13.19", forRemoval = true)
public final R order(String orderByClause) {
return orderBy(orderByClause);
}
- /**
- * Begin a list of expressions added by 'OR'.
- *
- * Use endOr() or endJunction() to stop added to OR and 'pop' to the parent expression list.
- *
- *
- * This example uses an 'OR' expression list with an inner 'AND' expression list.
- *
- * Use endAnd() or endJunction() to stop added to AND and 'pop' to the parent expression list.
- *
- * Note that typically the AND expression is only used inside an outer 'OR' expression.
- * This is because the top level expression list defaults to an 'AND' expression list.
- *
- * This example uses an 'OR' expression list with an inner 'AND' expression list.
- *
- * Use endNot() or endJunction() to stop added to NOT and 'pop' to the parent expression list.
- */
+ @Override
public final R not() {
pushExprList(peekExprList().not());
return root;
}
- /**
- * Begin a list of expressions added by MUST.
- *
- * This automatically makes this query a document store query.
- *
- * Use endJunction() to stop added to MUST and 'pop' to the parent expression list.
- */
+ @Override
public final R must() {
pushExprList(peekExprList().must());
return root;
}
- /**
- * Begin a list of expressions added by MUST NOT.
- *
- * This automatically makes this query a document store query.
- *
- * Use endJunction() to stop added to MUST NOT and 'pop' to the parent expression list.
- */
+ @Override
public final R mustNot() {
return pushExprList(peekExprList().mustNot());
}
- /**
- * Begin a list of expressions added by SHOULD.
- *
- * This automatically makes this query a document store query.
- *
- * Use endJunction() to stop added to SHOULD and 'pop' to the parent expression list.
- */
+ @Override
public final R should() {
return pushExprList(peekExprList().should());
}
- /**
- * End a list of expressions added by 'OR'.
- */
+ @Override
public final R endJunction() {
if (textMode) {
textStack.pop();
@@ -1442,23 +615,17 @@ public abstract class TQRootBean
- * For queries against the normal database (not the doc store) this has no effect.
- *
- * This is intended for use with Document Store / ElasticSearch where expressions can be put into either
- * the "query" section or the "filter" section of the query. Full text expressions like MATCH are in the
- * "query" section but many expression can be in either - expressions after the where() are put into the
- * "filter" section which means that they don't add to the relevance and are also cache-able.
- */
+ @Override
public final R where() {
textMode = false;
return root;
}
- /**
- * Begin added expressions to the 'Text' expression list.
- *
- * This automatically makes the query a document store query.
- *
- * For ElasticSearch expressions added to 'text' go into the ElasticSearch 'query context'
- * and expressions added to 'where' go into the ElasticSearch 'filter context'.
- */
+ @Override
public final R text() {
textMode = true;
return root;
}
- /**
- * Add a Text Multi-match expression (document store only).
- *
- * This automatically makes the query a document store query.
- */
+ @Override
public final R multiMatch(String query, MultiMatch multiMatch) {
peekExprList().multiMatch(query, multiMatch);
return root;
}
- /**
- * Add a Text Multi-match expression (document store only).
- *
- * This automatically makes the query a document store query.
- */
+ @Override
public final R multiMatch(String query, String... properties) {
peekExprList().multiMatch(query, properties);
return root;
}
- /**
- * Add a Text common terms expression (document store only).
- *
- * This automatically makes the query a document store query.
- */
+ @Override
public final R textCommonTerms(String query, TextCommonTerms options) {
peekExprList().textCommonTerms(query, options);
return root;
}
- /**
- * Add a Text simple expression (document store only).
- *
- * This automatically makes the query a document store query.
- */
+ @Override
public final R textSimple(String query, TextSimple options) {
peekExprList().textSimple(query, options);
return root;
}
- /**
- * Add a Text query string expression (document store only).
- *
- * This automatically makes the query a document store query.
- */
+ @Override
public final R textQueryString(String query, TextQueryString options) {
peekExprList().textQueryString(query, options);
return root;
}
- /**
- * Execute the query using the given transaction.
- */
+ @Override
public final R usingTransaction(Transaction transaction) {
query.usingTransaction(transaction);
return root;
}
- /**
- * Execute the query using the given connection.
- */
+ @Override
public final R usingConnection(Connection connection) {
query.usingConnection(connection);
return root;
}
- /**
- * Ensure that the master DataSource is used if there is a read only data source
- * being used (that is using a read replica database potentially with replication lag).
- *
- * When the database is configured with a read-only DataSource via
- * say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
- * by default when a query is run without an active transaction, it uses the read-only data
- * source. We we use {@code usingMaster()} to instead ensure that the query is executed
- * against the master data source.
- */
+ @Override
public final R usingMaster() {
query.usingMaster();
return root;
}
- /**
- * 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.
- *
- *
- * If more than 1 row is found for this query then a PersistenceException is
- * thrown.
- *
- * This is useful when your predicates dictate that your query should only
- * return 0 or 1 results.
- *
- *
- * It is also useful with finding objects by their id when you want to specify
- * further join information to optimise the query.
- *
- *
- * This query will execute against the EbeanServer that was used to create it.
- *
- *
- * Note that this can support very large queries iterating
- * any number of results. To do so internally it can use
- * multiple persistence contexts.
- *
- * This query will execute against the EbeanServer that was used to create it.
- *
- *
- * This query will execute against the EbeanServer that was used to create it.
- *
- * @see Query#findIds()
- */
+ @Override
public final List findIds() {
return query.findIds();
}
- /**
- * Execute the query returning a map of the objects.
- *
- * This query will execute against the EbeanServer that was used to create it.
- *
- * You can use setMapKey() or asMapKey() to specify the property to be used as keys
- * on the map. If one is not specified then the id property is used.
- *
- *
- * 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 EbeanServer that was used to create it.
- *
- *
- *
- *
- * 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 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.
- *
- *
- * 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
- */
+ @Override
public final void findEach(int batch, Consumer
- * 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.
- *
- *
- * 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.
- */
+ @Override
public final List
- * 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.
- */
+ @Override
public final List
- * This is the number of 'top level' or 'root level' entities.
- */
+ @Override
public final int findCount() {
return query.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
- */
+ @Override
public final FutureRowCount
- * 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
- */
+ @Override
public final FutureIds
- * 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
- */
+ @Override
public final FutureList
- * 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.
- *
- *
- * 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.
- */
+ @Override
public final int delete() {
return query.delete();
}
- /**
- * 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.
- */
+ @Override
public final String getGeneratedSql() {
return query.getGeneratedSql();
}
- /**
- * Return the type of beans being queried.
- */
+ @Override
public final Class
- * Note that after this we no longer have the query bean so typically we use this right
- * at the end of the query.
- *
- * {@code
+ *
+ * List
+ *
+ * @param properties the properties to fetch for this bean (* = all properties).
+ */
+ R select(String properties);
+
+ /**
+ * Set a FetchGroup to control what part of the object graph is loaded.
+ * {@code
+ *
+ * // immutable threadsafe
+ *
+ * static final FetchGroup
+ *
+ *
+ * {@code
+ *
+ * static final FetchGroup
+ */
+ R select(FetchGroup{@code
+ *
+ * // alias for the customer properties in select()
+ * QCustomer cust = QCustomer.alias();
+ *
+ * // alias for the contact properties in contacts.fetch()
+ * QContact contact = QContact.alias();
+ *
+ * List
+ *
+ * @param properties the list of properties to fetch
+ */
+ @SuppressWarnings("unchecked")
+ R select(TQProperty{@code
+ *
+ * List
+ *
+ * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
+ */
+ R fetch(String path);
+
+ /**
+ * Specify a path to load including all its properties using a "query join".
+ *
+ * {@code
+ *
+ * List
+ *
+ * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
+ */
+ R fetchQuery(String path);
+
+ /**
+ * Specify a path to load from L2 cache including all its properties.
+ *
+ * {@code
+ *
+ * List
+ *
+ * @param path the property path to load from L2 cache.
+ */
+ R fetchCache(String path);
+
+ /**
+ * Specify a path and properties to load using a "query join".
+ *
+ * {@code
+ *
+ * List
+ *
+ * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
+ * @param properties the properties to load for this path.
+ */
+ R fetchQuery(String path, String properties);
+
+ /**
+ * Specify a path and properties to load from L2 cache.
+ *
+ * {@code
+ *
+ * List
+ *
+ * @param path the property path to load from L2 cache.
+ * @param properties the properties to load for this path.
+ */
+ R fetchCache(String path, String properties);
+
+ /**
+ * Specify a path to fetch with its specific properties to include
+ * (aka partial object).
+ * {@code
+ *
+ * // query orders...
+ * List
+ * {@code
+ *
+ * List
+ *
+ * @param path the path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
+ * @param properties properties of the associated bean that you want to include in the
+ * fetch (* means all properties, null also means all properties).
+ */
+ R fetch(String path, String properties);
+
+ /**
+ * 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
+ */
+ R fetch(String path, String properties, FetchConfig fetchConfig);
+
+ /**
+ * Additionally specify a FetchConfig to specify a "query join" and or define
+ * the lazy loading query.
+ * {@code
+ *
+ * // fetch customers (their id, name and status)
+ * List
+ */
+ R fetch(String path, FetchConfig fetchConfig);
+
+ /**
+ * Apply the path properties replacing the select and fetch clauses.
+ * {@code
+ *
+ * // fetch a bean with JSON content
+ * EBasicJsonList bean= new QEBasicJsonList()
+ * .id.equalTo(42)
+ * .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
+ * .findOne();
+ *
+ *
+ * // get the invalid JSON errors from the bean state
+ * Map
+ */
+ R setAllowLoadErrors();
+
+ /**
+ * Explicitly specify whether to use AutoTune for this query.
+ * {@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")
+ *
+ * }
+ * {@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
+ */
+ R setDocIndexName(String indexName);
+
+ /**
+ * Restrict the query to only return subtypes of the given inherit type.
+ * {@code
+ *
+ * List
+ */
+ R setInheritType(Class extends T> type);
+
+ /**
+ * Set the base table to use for this query.
+ * {@code
+ *
+ * QOrder()
+ * .setBaseTable("order_2019_05")
+ * .status.equalTo(Status.NEW)
+ * .findList();
+ *
+ * }
+ */
+ R setBaseTable(String baseTable);
+
+ /**
+ * Execute the query with the given lock type and WAIT.
+ * forUpdate() is the same as
+ * withLock(LockType.UPDATE).
+ * forUpdateNoWait() is the same as
+ * withLock(LockType.UPDATE, LockWait.NOWAIT).
+ * {@code
+ *
+ * int rows =
+ * new QCustomer()
+ * .name.startsWith("Rob")
+ * .organisation.id.equalTo(42)
+ * .asUpdate()
+ * .set("active", false)
+ * .update()
+ *
+ * }
+ *
+ * @return This query as an UpdateQuery
+ */
+ UpdateQuery{@code
+ *
+ * Order order =
+ * new QOrder()
+ * .setId(1)
+ * .fetch("details")
+ * .findOne();
+ *
+ * // the order details were eagerly fetched
+ * List
+ */
+ R setId(Object id);
+
+ /**
+ * Set a list of Id values to match.
+ * {@code
+ *
+ * List
+ */
+ R setIdIn(Object... ids);
+
+ /**
+ * Set a collection of Id values to match.
+ * {@code
+ *
+ * Collection> ids = ...
+ *
+ * List
+ */
+ R setIdIn(Collection> ids);
+
+ /**
+ * Set a label on the query.
+ * {@code
+ *
+ * // Assuming sku is unique for products...
+ *
+ * Map
+ *
+ * @param mapKey the property to use as keys for a map.
+ */
+ R setMapKey(String mapKey);
+
+ /**
+ * Specify the PersistenceContextScope to use for this query.
+ * {@code
+ *
+ * raw("orderQty < shipQty")
+ *
+ * }
+ *
+ * Subquery example:
+ * {@code
+ *
+ * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
+ *
+ * }
+ */
+ R raw(String rawExpression);
+
+ /**
+ * Add raw expression with an array of parameters.
+ * Without inOrEmpty()
+ * {@code
+ *
+ * QCustomer query = new QCustomer() // add some predicates
+ * .status.equalTo(Status.NEW);
+ *
+ * // common pattern - we can use rawOrEmpty() instead
+ * if (orderIds != null && !orderIds.isEmpty()) {
+ * query.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
+ *
+ * new QCustomer()
+ * .status.equalTo(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 SQL ANY expression and array parameter binding
+ * rather than IN.
+ *
+ * {@code
+ *
+ * new QCustomer()
+ * .status.equalTo(Status.NEW)
+ * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
+ * .findList();
+ *
+ * }
+ * {@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.
+ */
+ R rawOrEmpty(String raw, Collection> values);
+
+ /**
+ * Add raw expression with a single parameter.
+ * Example:
+ * {@code
+ *
+ * // use a database function
+ * raw("add_days(orderDate, 10) < ?", someDate)
+ *
+ * }
+ *
+ * Subquery example:
+ * {@code
+ *
+ * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
+ *
+ * }
+ */
+ R raw(String rawExpression, Object bindValue);
+
+ /**
+ * In expression using multiple columns.
+ */
+ R inTuples(InTuples inTuples);
+
+ /**
+ * Marker that can be used to indicate that the order by clause is defined after this.
+ * Example: order by customer name, order date
+ * {@code
+ * List
+ */
+ R orderBy();
+
+ /**
+ * @deprecated migrate to {@link #orderBy()}.
+ */
+ @Deprecated(since = "13.19", forRemoval = true)
+ R order();
+
+ /**
+ * Set the full raw order by clause replacing the existing order by clause if there is one.
+ * Example
+ * {@code
+ *
+ * List
+ * Resulting SQL where clause
+ * {@code sql
+ *
+ * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) )
+ * order by t0.id desc;
+ *
+ * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
+ *
+ * }
+ */
+ R or();
+
+ /**
+ * Begin a list of expressions added by 'AND'.
+ * Example
+ * {@code
+ *
+ * List
+ * Resulting SQL where clause
+ * {@code sql
+ *
+ * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) )
+ * order by t0.id desc;
+ *
+ * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
+ *
+ * }
+ */
+ R and();
+
+ /**
+ * Begin a list of expressions added by NOT.
+ * 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).
+ * {@code
+ *
+ * // assuming the sku of products is unique...
+ * Product product =
+ * new QProduct()
+ * .sku.equalTo("aa113")
+ * .findOne();
+ * ...
+ * }
+ * {@code
+ *
+ * // Fetch order 42 and additionally fetch join its order details...
+ * Order order =
+ * new QOrder()
+ * .fetch("details") // eagerly load the order details
+ * .id.equalTo(42)
+ * .findOne();
+ *
+ * // the order details were eagerly loaded
+ * List
+ */
+ @Nullable
+ T findOne();
+
+ /**
+ * Execute the query returning an optional bean.
+ */
+ Optional{@code
+ *
+ * List
+ *
+ * @see Query#findList()
+ */
+ List{@code
+ *
+ * // use try with resources to ensure Stream is closed
+ *
+ * try (Stream
+ */
+ Stream{@code
+ *
+ * Set
+ *
+ * @see Query#findSet()
+ */
+ Set{@code
+ *
+ * Map
+ *
+ * @see Query#findMap()
+ */
+ {@code
+ *
+ * Query
+ */
+ QueryIteratorExample
+ * {@code
+ *
+ * List
+ *
+ * @return the list of values for the selected property
+ */
+ List findSingleAttributeList();
+
+ /**
+ * Execute the query returning a single value or null for a single property.
+ * Example
+ * {@code
+ *
+ * LocalDate maxDate =
+ * new QCustomer()
+ * .select("max(startDate)")
+ * .findSingleAttribute();
+ *
+ * }
+ *
+ * @return a single value or null for the selected property
+ */
+ @Nullable
+ A findSingleAttribute();
+
+ /**
+ * Execute the query returning a single optional attribute value.
+ * Example
+ * {@code
+ *
+ * Optional
+ *
+ * @return an optional value for the selected property
+ */
+ Optional findSingleAttributeOrEmpty();
+
+ /**
+ * Execute the query processing the beans one at a time.
+ * {@code
+ *
+ * new QCustomer()
+ * .status.equalTo(Status.NEW)
+ * .orderBy().id.asc()
+ * .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 the query using callbacks to a visitor to process the resulting
+ * beans one at a time.
+ *
{@code
+ *
+ * new QCustomer()
+ * .status.equalTo(Status.NEW)
+ * .orderBy().id.asc()
+ * .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{@code
+ *
+ * PagedList
+ *
+ * @return The PagedList
+ */
+ PagedList{@code
+ *
+ * new QMachineUse()
+ * // where ...
+ * .date.inRange(fromDate, toDate)
+ *
+ * .having()
+ * .sumHours.greaterThan(1)
+ * .findList()
+ *
+ * // The sumHours property uses @Aggregation
+ * // e.g. @Aggregation("sum(hours)")
+ *
+ * }
+ */
+ R having();
+
+ /**
+ * Return the underlying having clause to typically when using dynamic aggregation formula.
+ * {@code
+ *
+ * // sum(distanceKms) ... is a "dynamic formula"
+ * // so we use havingClause() for it like:
+ *
+ * List
+ */
+ ExpressionListExample - usage of QCustomer
* {@code
*
@@ -61,7 +58,7 @@ import java.util.stream.Stream;
* @param {@code
- *
- * List
- *
- * @param properties the properties to fetch for this bean (* = all properties).
- */
+ @Override
public R select(String properties) {
query.select(properties);
return root;
}
- /**
- * Set a FetchGroup to control what part of the object graph is loaded.
- * {@code
- *
- * // immutable threadsafe
- *
- * static final FetchGroup
- *
- *
- * {@code
- *
- * static final FetchGroup
- */
+ @Override
public R select(FetchGroup{@code
- *
- * // alias for the customer properties in select()
- * QCustomer cust = QCustomer.alias();
- *
- * // alias for the contact properties in contacts.fetch()
- * QContact contact = QContact.alias();
- *
- * List
- *
- * @param properties the list of properties to fetch
- */
+ @Override
@SafeVarargs
public final R select(TQProperty{@code
- *
- * List
- *
- * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
- */
+ @Override
public final R fetch(String path) {
query.fetch(path);
return root;
}
- /**
- * Specify a path to load including all its properties using a "query join".
- *
- * {@code
- *
- * List
- *
- * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
- */
+ @Override
public final R fetchQuery(String path) {
query.fetchQuery(path);
return root;
}
- /**
- * Specify a path to load from L2 cache including all its properties.
- *
- * {@code
- *
- * List
- *
- * @param path the property path to load from L2 cache.
- */
+ @Override
public final R fetchCache(String path) {
query.fetchCache(path);
return root;
}
- /**
- * Specify a path and properties to load using a "query join".
- *
- * {@code
- *
- * List
- *
- * @param path the property path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
- * @param properties the properties to load for this path.
- */
+ @Override
public final R fetchQuery(String path, String properties) {
query.fetchQuery(path, properties);
return root;
}
- /**
- * Specify a path and properties to load from L2 cache.
- *
- * {@code
- *
- * List
- *
- * @param path the property path to load from L2 cache.
- * @param properties the properties to load for this path.
- */
+ @Override
public final R fetchCache(String path, String properties) {
query.fetchCache(path, properties);
return root;
}
- /**
- * Specify a path to fetch with its specific properties to include
- * (aka partial object).
- * {@code
- *
- * // query orders...
- * List
- * {@code
- *
- * List
- *
- * @param path the path of an associated (OneToOne, OneToMany, ManyToOne or ManyToMany) bean.
- * @param properties properties of the associated bean that you want to include in the
- * fetch (* means all properties, null also means all properties).
- */
+ @Override
public final R fetch(String path, String properties) {
query.fetch(path, properties);
return root;
}
- /**
- * 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
- */
+ @Override
public final R fetch(String path, String properties, FetchConfig fetchConfig) {
query.fetch(path, properties, fetchConfig);
return root;
}
- /**
- * Additionally specify a FetchConfig to specify a "query join" and or define
- * the lazy loading query.
- * {@code
- *
- * // fetch customers (their id, name and status)
- * List
- */
+ @Override
public final R fetch(String path, FetchConfig fetchConfig) {
query.fetch(path, fetchConfig);
return root;
}
- /**
- * Apply the path properties replacing the select and fetch clauses.
- * {@code
- *
- * // fetch a bean with JSON content
- * EBasicJsonList bean= new QEBasicJsonList()
- * .id.equalTo(42)
- * .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
- * .findOne();
- *
- *
- * // get the invalid JSON errors from the bean state
- * Map
- */
+ @Override
public final R setAllowLoadErrors() {
query.setAllowLoadErrors();
return root;
}
- /**
- * Explicitly specify whether to use AutoTune for this query.
- * {@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")
- *
- * }
- * {@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
- */
+ @Override
public final R setDocIndexName(String indexName) {
query.setDocIndexName(indexName);
return root;
}
- /**
- * Restrict the query to only return subtypes of the given inherit type.
- * {@code
- *
- * List
- */
+ @Override
public final R setInheritType(Class extends T> type) {
query.setInheritType(type);
return root;
}
- /**
- * Set the base table to use for this query.
- * {@code
- *
- * QOrder()
- * .setBaseTable("order_2019_05")
- * .status.equalTo(Status.NEW)
- * .findList();
- *
- * }
- */
+ @Override
public final R setBaseTable(String baseTable) {
query.setBaseTable(baseTable);
return root;
}
- /**
- * Execute the query with the given lock type and WAIT.
- * forUpdate() is the same as
- * withLock(LockType.UPDATE).
- * forUpdateNoWait() is the same as
- * withLock(LockType.UPDATE, LockWait.NOWAIT).
- * {@code
- *
- * int rows =
- * new QCustomer()
- * .name.startsWith("Rob")
- * .organisation.id.equalTo(42)
- * .asUpdate()
- * .set("active", false)
- * .update()
- *
- * }
- *
- * @return This query as an UpdateQuery
- */
+ @Override
public final UpdateQuery{@code
- *
- * Order order =
- * new QOrder()
- * .setId(1)
- * .fetch("details")
- * .findOne();
- *
- * // the order details were eagerly fetched
- * List
- */
+ @Override
public final R setId(Object id) {
query.setId(id);
return root;
}
- /**
- * Set a list of Id values to match.
- * {@code
- *
- * List
- */
+ @Override
public final R setIdIn(Object... ids) {
query.where().idIn(ids);
return root;
}
- /**
- * Set a collection of Id values to match.
- * {@code
- *
- * Collection> ids = ...
- *
- * List
- */
+ @Override
public final R setIdIn(Collection> ids) {
query.where().idIn(ids);
return root;
}
- /**
- * Set a label on the query.
- * {@code
- *
- * // Assuming sku is unique for products...
- *
- * Map
- *
- * @param mapKey the property to use as keys for a map.
- */
+ @Override
public final R setMapKey(String mapKey) {
query.setMapKey(mapKey);
return root;
}
- /**
- * Specify the PersistenceContextScope to use for this query.
- * {@code
- *
- * raw("orderQty < shipQty")
- *
- * }
- *
- * Subquery example:
- * {@code
- *
- * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
- *
- * }
- */
+ @Override
public final R raw(String rawExpression) {
peekExprList().raw(rawExpression);
return root;
}
- /**
- * Add raw expression with an array of parameters.
- * Without inOrEmpty()
- * {@code
- *
- * QCustomer query = new QCustomer() // add some predicates
- * .status.equalTo(Status.NEW);
- *
- * // common pattern - we can use rawOrEmpty() instead
- * if (orderIds != null && !orderIds.isEmpty()) {
- * query.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
- *
- * new QCustomer()
- * .status.equalTo(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 SQL ANY expression and array parameter binding
- * rather than IN.
- *
- * {@code
- *
- * new QCustomer()
- * .status.equalTo(Status.NEW)
- * .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
- * .findList();
- *
- * }
- * {@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.
- */
+ @Override
public final R rawOrEmpty(String raw, Collection> values) {
peekExprList().rawOrEmpty(raw, values);
return root;
}
- /**
- * Add raw expression with a single parameter.
- * Example:
- * {@code
- *
- * // use a database function
- * raw("add_days(orderDate, 10) < ?", someDate)
- *
- * }
- *
- * Subquery example:
- * {@code
- *
- * .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
- *
- * }
- */
+ @Override
public final R raw(String rawExpression, Object bindValue) {
peekExprList().raw(rawExpression, bindValue);
return root;
}
- /**
- * In expression using multiple columns.
- */
+ @Override
public final R inTuples(InTuples inTuples) {
peekExprList().inTuples(inTuples);
return root;
}
- /**
- * Marker that can be used to indicate that the order by clause is defined after this.
- * Example: order by customer name, order date
- * {@code
- * List
- */
+ @Override
public final R orderBy() {
// Yes this does not actually do anything! We include it because style wise it makes
// the query nicer to read and suggests that order by definitions are added after this
return root;
}
- /**
- * @deprecated migrate to {@link #orderBy()}.
- */
+ @Override
@Deprecated(since = "13.19", forRemoval = true)
public final R order() {
return root;
}
- /**
- * Set the full raw order by clause replacing the existing order by clause if there is one.
- * Example
- * {@code
- *
- * List
- * Resulting SQL where clause
- * {@code sql
- *
- * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) )
- * order by t0.id desc;
- *
- * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
- *
- * }
- */
+ @Override
public final R or() {
pushExprList(peekExprList().or());
return root;
}
- /**
- * Begin a list of expressions added by 'AND'.
- * Example
- * {@code
- *
- * List
- * Resulting SQL where clause
- * {@code sql
- *
- * where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) )
- * order by t0.id desc;
- *
- * --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
- *
- * }
- */
+ @Override
public final R and() {
pushExprList(peekExprList().and());
return root;
}
- /**
- * Begin a list of expressions added by NOT.
- * 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
- */
+ @Override
public final boolean exists() {
return query.exists();
}
- /**
- * Execute the query returning either a single bean or null (if no matching
- * bean is found).
- * {@code
- *
- * // assuming the sku of products is unique...
- * Product product =
- * new QProduct()
- * .sku.equalTo("aa113")
- * .findOne();
- * ...
- * }
- * {@code
- *
- * // Fetch order 42 and additionally fetch join its order details...
- * Order order =
- * new QOrder()
- * .fetch("details") // eagerly load the order details
- * .id.equalTo(42)
- * .findOne();
- *
- * // the order details were eagerly loaded
- * List
- */
+ @Override
@Nullable
public final T findOne() {
return query.findOne();
}
- /**
- * Execute the query returning an optional bean.
- */
+ @Override
public final Optional{@code
- *
- * List
- *
- * @see Query#findList()
- */
+ @Override
public final List{@code
- *
- * // use try with resources to ensure Stream is closed
- *
- * try (Stream
- */
+ @Override
public final Stream{@code
- *
- * Set
- *
- * @see Query#findSet()
- */
+ @Override
public final Set{@code
- *
- * Map
- *
- * @see Query#findMap()
- */
+ @Override
public final {@code
- *
- * Query
- */
+ @Override
public final QueryIteratorExample
- * {@code
- *
- * List
- *
- * @return the list of values for the selected property
- */
+ @Override
public final List findSingleAttributeList() {
return query.findSingleAttributeList();
}
- /**
- * Execute the query returning a single value or null for a single property.
- * Example
- * {@code
- *
- * LocalDate maxDate =
- * new QCustomer()
- * .select("max(startDate)")
- * .findSingleAttribute();
- *
- * }
- *
- * @return a single value or null for the selected property
- */
+ @Override
@Nullable
public final A findSingleAttribute() {
return query.findSingleAttribute();
}
- /**
- * Execute the query returning a single optional attribute value.
- * Example
- * {@code
- *
- * Optional
- *
- * @return an optional value for the selected property
- */
+ @Override
public final Optional findSingleAttributeOrEmpty() {
return query.findSingleAttributeOrEmpty();
}
- /**
- * Execute the query processing the beans one at a time.
- * {@code
- *
- * new QCustomer()
- * .status.equalTo(Status.NEW)
- * .orderBy().id.asc()
- * .findEach((Customer customer) -> {
- *
- * // do something with customer
- * System.out.println("-- visit " + customer);
- * });
- *
- * }
- *
- * @param consumer the consumer used to process the queried beans.
- */
+ @Override
public final void findEach(Consumer> consumer) {
query.findEach(batch, consumer);
}
- /**
- * Execute the query using callbacks to a visitor to process the resulting
- * beans one at a time.
- *
{@code
- *
- * new QCustomer()
- * .status.equalTo(Status.NEW)
- * .orderBy().id.asc()
- * .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.
- */
+ @Override
public final void findEachWhile(Predicate{@code
- *
- * PagedList
- *
- * @return The PagedList
- */
+ @Override
public final PagedList{@code
- *
- * new QMachineUse()
- * // where ...
- * .date.inRange(fromDate, toDate)
- *
- * .having()
- * .sumHours.greaterThan(1)
- * .findList()
- *
- * // The sumHours property uses @Aggregation
- * // e.g. @Aggregation("sum(hours)")
- *
- * }
- */
+ @Override
public final R having() {
if (whereStack == null) {
whereStack = new ArrayStack<>();
@@ -2107,31 +845,7 @@ public abstract class TQRootBean{@code
- *
- * // sum(distanceKms) ... is a "dynamic formula"
- * // so we use havingClause() for it like:
- *
- * List
- */
+ @Override
public final ExpressionList