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
Modifier and TypeClassDescriptionstatic class
-
Field Summary
Modifier and TypeFieldDescriptionstatic final int
Default page size if pagination is requested, that is offset is set, but maxSize is not.protected final Q
protected final QueryTableMapping<S,
Q, R> static final int
Number of values (identifiers) used in the IN clause to-many fetching selects.static final long
If no other limit is used for query this limit will be used for sanity reasons.protected boolean
protected Collection<SelectorOptions<GetOperationOptions>>
protected final com.querydsl.sql.SQLQuery<?>
-
Constructor Summary
ModifierConstructorDescriptionprotected
SqlQueryContext
(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlQueryContext<?, ?, ?> parentContext, com.querydsl.sql.SQLQuery<?> sqlQuery) Constructor for derived context or sub-context, e.g.protected
SqlQueryContext
(Q entityPath, QueryTableMapping<S, Q, R> mapping, SqlRepoContext sqlRepoContext, com.querydsl.sql.SQLQuery<?> query) Constructor for root query context. -
Method Summary
Modifier and TypeMethodDescriptionvoid
Before-query hook, empty by default, called *before* the JDBC transaction starts.createCanonicalItemPath
(@NotNull ItemPath itemPath) int
executeCount
(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 returnsSqlQueryContext
for this join path.mapping()
void
abstract <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. joined) query context.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. subquery) query context.@NotNull QName
normalizeRelation
(QName qName) SqlQueryContext<?,
?, ?> path()
Returns entity path of this context.<T extends FlexibleRelationalPathBase<?>>
Tcom.querydsl.core.types.Predicate
process
(@NotNull ObjectFilter filter) Implements contract forFilterProcessor
working as a top-level dispatcher to concrete filter types.void
processFilter
(ObjectFilter filter) Processes the object filter and sets the WHERE clause.com.querydsl.core.types.Predicate
processFuzzyFilter
(FuzzyStringMatchFilter<?> filter, com.querydsl.core.types.Expression<?> path, ValueFilterValues<?, ?> values) Produces predicate for fuzzy filter with pre-provided expression for the left side.void
processObjectPaging
(ObjectPaging paging) This method takes care ofObjectPaging
which 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<?>>
Tvoid
setParentItemContext
(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 returnsSqlQueryContext
for 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, wait
Methods 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 forFilterProcessor
working 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 ofObjectFilter
from Prism API are not supported here, see subclasses.- Specified by:
process
in interfaceFilterProcessor<S>
- Throws:
RepositoryException
-
processObjectPaging
This method takes care ofObjectPaging
which 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, seeextensionColumns
inQueryTableMapping
.QueryTableMapping
has many responsibilities in the process: *options
are 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 returnsSqlQueryContext
for 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 returnsSqlQueryContext
for 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:
SchemaException
QueryException
-
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
-