Class SqlQueryContext<S,Q extends FlexibleRelationalPathBase<R>,R>
java.lang.Object
com.evolveum.midpoint.repo.sqlbase.SqlQueryContext<S,Q,R>
- Type Parameters:
S- schema type, used by encapsulated mappingQ- type of entity pathR- row type related to theSqlQueryContext
- All Implemented Interfaces:
FilterProcessor<ObjectFilter>
- Direct Known Subclasses:
SqaleQueryContext
public abstract class SqlQueryContext<S,Q extends FlexibleRelationalPathBase<R>,R>
extends Object
implements FilterProcessor<ObjectFilter>
Execution context of the SQL query.
Works as a kind of accumulator where information are added as the object query is interpreted.
The object has a couple of overlapping responsibilities:
* It implements
FilterProcessor and is used as an entry point for filter processing for the query.
* It executes the query, returning PageOf low-level rows, see executeQuery(com.evolveum.midpoint.repo.sqlbase.JdbcSession).
* It transforms the row beans to midPoint objects using transformToSchemaType(com.evolveum.midpoint.repo.sqlbase.PageOf<com.querydsl.core.Tuple>, com.evolveum.midpoint.repo.sqlbase.JdbcSession).
QueryTableMapping is crucial for all these steps and flow of the execution goes a lot between
the SqlQueryExecutor, this class and particular methods of the mapping.
Anything specific for a particular type/table should be part of the mapping logic.
The mapping contract should cover all the needs of this execution context.
It can be extended if needed, but always think whether existing mechanisms are not enough already.
E.g. if you need to post-process the low level result, there is a way how to do it and it allows for things
like loading all the detail table rows in a single query.
See transformToSchemaType(com.evolveum.midpoint.repo.sqlbase.PageOf<com.querydsl.core.Tuple>, com.evolveum.midpoint.repo.sqlbase.JdbcSession) for notes how this allows for inter-row state keeping as well.
[NOTE]
Implementation note:
There was an option to keep this as an information accumulator only and do the execution
elsewhere, but it proved more practical to utilize all the contained parameterized types.
Methods executing the query and processing the result would need to be parameterized the same way
this context already is - so it was better to use the types here.
[NOTE]
This object does not handle SQL connections or transaction in any way, any connection
needed is provided from the outside.-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic class -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intDefault page size if pagination is requested, that is offset is set, but maxSize is not.protected final Qprotected final QueryTableMapping<S,Q, R> static final intNumber of values (identifiers) used in the IN clause to-many fetching selects.static final longIf no other limit is used for query this limit will be used for sanity reasons.protected booleanprotected Collection<SelectorOptions<GetOperationOptions>>protected final com.querydsl.sql.SQLQuery<?> -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedSqlQueryContext(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlQueryContext<?, ?, ?> parentContext, com.querydsl.sql.SQLQuery<?> sqlQuery) Constructor for derived context or sub-context, e.g.protectedSqlQueryContext(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlRepoContext sqlRepoContext, com.querydsl.sql.SQLQuery<?> query) Constructor for root query context. -
Method Summary
Modifier and TypeMethodDescriptionvoidBefore-query hook, empty by default, called *before* the JDBC transaction starts.createCanonicalItemPath(@NotNull ItemPath itemPath) intexecuteCount(JdbcSession jdbcSession) PageOf<com.querydsl.core.Tuple>executeQuery(JdbcSession jdbcSession) Returns page of results with each row represented by aTuple.SqlQueryContext<?,?, ?> boolean<TS,TQ extends FlexibleRelationalPathBase<TR>, TR>
SqlQueryContext<TS,TQ, TR> leftJoin(@NotNull QueryTableMapping<TS, TQ, TR> targetMapping, @NotNull BiFunction<Q, TQ, com.querydsl.core.types.Predicate> joinOnPredicateFunction) Adds new LEFT JOIN to the query and returnsSqlQueryContextfor this join path.mapping()voidabstract <TS,TQ extends FlexibleRelationalPathBase<TR>, TR>
SqlQueryContext<TS,TQ, TR> newSubcontext(TQ newPath, QueryTableMapping<TS, TQ, TR> newMapping) Contract to implement to obtain derived (e.g.protected abstract <TS,TQ extends FlexibleRelationalPathBase<TR>, TR>
SqlQueryContext<TS,TQ, TR> newSubcontext(TQ newPath, QueryTableMapping<TS, TQ, TR> newMapping, com.querydsl.sql.SQLQuery<?> query) Contract to implement to obtain derived (e.g.@NotNull QNamenormalizeRelation(QName qName) SqlQueryContext<?,?, ?> path()Returns entity path of this context.<T extends FlexibleRelationalPathBase<?>>
Tcom.querydsl.core.types.Predicateprocess(@NotNull ObjectFilter filter) Implements contract forFilterProcessorworking as a top-level dispatcher to concrete filter types.voidprocessFilter(ObjectFilter filter) Processes the object filter and sets the WHERE clause.com.querydsl.core.types.PredicateprocessFuzzyFilter(FuzzyStringMatchFilter<?> filter, com.querydsl.core.types.Expression<?> path, ValueFilterValues<?, ?> values) Produces predicate for fuzzy filter with pre-provided expression for the left side.voidprocessObjectPaging(ObjectPaging paging) This method takes care ofObjectPagingwhich includes ordering.void<T> Class<? extends T>qNameToSchemaClass(@NotNull QName qName) <CQ extends FlexibleRelationalPathBase<CR>,CR>
SqlQueryContext.ResolveResult<CQ,CR> resolvePathWithJoins(ItemPath inputPath) root()<T extends FlexibleRelationalPathBase<?>>
TvoidsetParentItemContext(SqlQueryContext<?, ?, ?> parentItemContext) com.querydsl.sql.SQLQuery<?>sqlQuery()Returns wrapped query if usage of Querydsl API is more convenient.<TS,TQ extends FlexibleRelationalPathBase<TR>, TR>
SqlQueryContext<TS,TQ, TR> subquery(@NotNull QueryTableMapping<TS, TQ, TR> targetMapping) Creates new subquery and returnsSqlQueryContextfor it, typically for (NOT) EXISTS.<TS,TQ extends FlexibleRelationalPathBase<TR>, TR>
SqlQueryContext<TS,TQ, TR> Creates new subquery, seesubquery(QueryTableMapping)for more.transformToSchemaType(PageOf<com.querydsl.core.Tuple> result, JdbcSession jdbcSession) Transforms result page with (bean + extension columns) tuple to schema type.uniqueAliasName(String baseAliasName) Adjusts the alias name to make it unique and registers the name as used.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.evolveum.midpoint.repo.sqlbase.filtering.FilterProcessor
process
-
Field Details
-
DEFAULT_PAGE_SIZE
public static final int DEFAULT_PAGE_SIZEDefault page size if pagination is requested, that is offset is set, but maxSize is not.- See Also:
-
NO_PAGINATION_LIMIT
public static final long NO_PAGINATION_LIMITIf no other limit is used for query this limit will be used for sanity reasons.- See Also:
-
MAX_ID_IN_FOR_TO_MANY_FETCH
public static final int MAX_ID_IN_FOR_TO_MANY_FETCHNumber of values (identifiers) used in the IN clause to-many fetching selects. This works effectively as factor of how bad N+1 select is, it's at most N/this-limit+1 bad. For obvious reasons, this works only for non-composite PKs (IDs) on the master entity.- See Also:
-
sqlQuery
protected final com.querydsl.sql.SQLQuery<?> sqlQuery -
entityPath
-
entityPathMapping
-
notFilterUsed
protected boolean notFilterUsed -
options
-
-
Constructor Details
-
SqlQueryContext
protected SqlQueryContext(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlRepoContext sqlRepoContext, com.querydsl.sql.SQLQuery<?> query) Constructor for root query context. -
SqlQueryContext
protected SqlQueryContext(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlQueryContext<?, ?, ?> parentContext, com.querydsl.sql.SQLQuery<?> sqlQuery) Constructor for derived context or sub-context, e.g. JOIN, EXISTS, etc.
-
-
Method Details
-
getParentItemContext
-
setParentItemContext
-
root
-
root
-
processFilter
Processes the object filter and sets the WHERE clause. This is different fromprocess(ObjectFilter)that just creates a predicate. That method is used in this one andQueryBase.where(Predicate)is called.- Throws:
RepositoryException
-
process
public com.querydsl.core.types.Predicate process(@NotNull @NotNull ObjectFilter filter) throws RepositoryException Implements contract forFilterProcessorworking as a top-level dispatcher to concrete filter types. This is a universal/generic filter processor that dispatches to the actual filter processor based on the filter type. It is used both as an entry point for the root filter of the query, but also when various structural filters need to resolve their components (e.g. AND uses this for its components). *This only returns the created predicate, compare withprocessFilter(com.evolveum.midpoint.prism.query.ObjectFilter).* Some subtypes ofObjectFilterfrom Prism API are not supported here, see subclasses.- Specified by:
processin interfaceFilterProcessor<S>- Throws:
RepositoryException
-
processObjectPaging
This method takes care ofObjectPagingwhich includes ordering.- Throws:
RepositoryException
-
resolvePathWithJoins
public <CQ extends FlexibleRelationalPathBase<CR>,CR> SqlQueryContext.ResolveResult<CQ,CR> resolvePathWithJoins(ItemPath inputPath) throws RepositoryException - Throws:
RepositoryException
-
executeQuery
Returns page of results with each row represented by aTuple. Tuple contains expressions specified byQueryTableMapping.selectExpressions(Q, java.util.Collection<com.evolveum.midpoint.schema.SelectorOptions<com.evolveum.midpoint.schema.GetOperationOptions>>), seebuildSelectExpressions(Q, com.querydsl.sql.SQLQuery<?>)for details. This may for example beSqlQueryContext(representing the whole entity) and then individual paths for extension columns, seeextensionColumnsinQueryTableMapping.QueryTableMappinghas many responsibilities in the process: *optionsare used to amend the select expression list; the options later enter as a parameter to most methods related to the transformation from row to midPoint object. *QueryTableMapping.createRowTransformer(com.evolveum.midpoint.repo.sqlbase.SqlQueryContext<S, Q, R>, com.evolveum.midpoint.repo.sqlbase.JdbcSession, java.util.Collection<com.evolveum.midpoint.schema.SelectorOptions<com.evolveum.midpoint.schema.GetOperationOptions>>)(used later bytransformToSchemaType(com.evolveum.midpoint.repo.sqlbase.PageOf<com.querydsl.core.Tuple>, com.evolveum.midpoint.repo.sqlbase.JdbcSession)) allows for low-level result list processing, e.g. fetching any additional objects efficiently.- Throws:
QueryException
-
executeCount
-
leftJoin
public <TS,TQ extends FlexibleRelationalPathBase<TR>, SqlQueryContext<TS,TR> TQ, leftJoinTR> (@NotNull @NotNull QueryTableMapping<TS, TQ, TR> targetMapping, @NotNull @NotNull BiFunction<Q, TQ, com.querydsl.core.types.Predicate> joinOnPredicateFunction) Adds new LEFT JOIN to the query and returnsSqlQueryContextfor this join path. The returned context still uses the same SQL query; any further filter processing will add WHERE conditions to the original query, but the conditions use the new alias.- Type Parameters:
TQ- query type for the JOINed (target) tableTR- row type related to theSqlQueryContext- Parameters:
targetMapping- mapping for the JOIN target query typejoinOnPredicateFunction- bi-function producing ON predicate for the JOIN
-
subquery
public <TS,TQ extends FlexibleRelationalPathBase<TR>, SqlQueryContext<TS,TR> TQ, subqueryTR> (@NotNull @NotNull Class<TQ> subqueryType) Creates new subquery, seesubquery(QueryTableMapping)for more.- Parameters:
subqueryType- entity path type the subquery
-
subquery
public <TS,TQ extends FlexibleRelationalPathBase<TR>, SqlQueryContext<TS,TR> TQ, subqueryTR> (@NotNull @NotNull QueryTableMapping<TS, TQ, TR> targetMapping) Creates new subquery and returnsSqlQueryContextfor it, typically for (NOT) EXISTS. Call toFetchableSubQueryBase.exists()can't be here, because it's a predicate creating call that we may need to execute when returning the predicate inside the filter processor. See `TypeFilterProcessor` from `repo-sqale` for example.- Type Parameters:
TQ- query type for the subquery tableTR- row type related to theSqlQueryContext- Parameters:
targetMapping- mapping for the subquery type
-
newSubcontext
public abstract <TS,TQ extends FlexibleRelationalPathBase<TR>, SqlQueryContext<TS,TR> TQ, newSubcontextTR> (TQ newPath, QueryTableMapping<TS, TQ, TR> newMapping) Contract to implement to obtain derived (e.g. joined) query context.- Type Parameters:
TQ- query type for the new (target) tableTR- row type related to theSqlQueryContext
-
newSubcontext
protected abstract <TS,TQ extends FlexibleRelationalPathBase<TR>, SqlQueryContext<TS,TR> TQ, newSubcontextTR> (TQ newPath, QueryTableMapping<TS, TQ, TR> newMapping, com.querydsl.sql.SQLQuery<?> query) Contract to implement to obtain derived (e.g. subquery) query context.- Type Parameters:
TQ- query type for the new (target) tableTR- row type related to theSqlQueryContext
-
uniqueAliasName
Adjusts the alias name to make it unique and registers the name as used. -
processOptions
-
transformToSchemaType
public PageOf<S> transformToSchemaType(PageOf<com.querydsl.core.Tuple> result, JdbcSession jdbcSession) throws SchemaException, QueryException Transforms result page with (bean + extension columns) tuple to schema type. JDBC session is provided as it may be needed for additional fetches. Instead of calling some transformation method row-by-row, transformer object is provided by the table mapper - which allows for potentially stateful processing.- Throws:
SchemaExceptionQueryException
-
sqlQuery
public com.querydsl.sql.SQLQuery<?> sqlQuery()Returns wrapped query if usage of Querydsl API is more convenient. -
parentContext
-
path
Returns entity path of this context. -
path
-
mapping
-
queryMapping
-
markNotFilterUsage
public void markNotFilterUsage() -
isNotFilterUsed
public boolean isNotFilterUsed() -
repositoryContext
-
prismContext
-
qNameToSchemaClass
-
createCanonicalItemPath
-
normalizeRelation
-
beforeQuery
public void beforeQuery()Before-query hook, empty by default, called *before* the JDBC transaction starts. -
processFuzzyFilter
public com.querydsl.core.types.Predicate processFuzzyFilter(FuzzyStringMatchFilter<?> filter, com.querydsl.core.types.Expression<?> path, ValueFilterValues<?, ?> values) throws QueryExceptionProduces predicate for fuzzy filter with pre-provided expression for the left side. This does not care about single/multi-value definition which must be treated above this method.- Throws:
QueryException
-