Package com.blazebit.persistence.querydsl
blaze-persistence-integration-querydsl-expressionsmodule implements an extended expression model for Blaze-Persistence JPQL.Next.
The module provides a BlazeJPAQuery
as a default implementation of JPQLNextQuery
, which extends the all familiar JPQLQuery
.
BlazeJPAQuery
is analog to JPAQuery
. Users can
implement extensions on top of JPQLNextQuery
by extending AbstractBlazeJPAQuery
.
BlazeJPAQuery
can be serialized using the JPQLNextSerializer
, and may be rendered to a CriteriaBuilder
using the BlazeCriteriaBuilderRenderer
.
This allows for the queries to be executed through Blaze-Persistence JPQL.Next query engine. Be sure to use the
JPQLNextTemplates
or any Templates
implementation that includes the
extensions from JPQLNextTemplates
when using JPQL.Next specific features (e.g. window functions, values
clauses, set operations, common table expressions).
This module aims an API that is as close to the original QueryDSL API as possible. Where features did not exist in
querydsl-jpa, but did exist in
querydsl-sql, we stayed as close to the existing SQL implementation as possible. This includes the implementation for window functions, common table expressions (CTEs) and union queries which was the basis for all types of set expressions.
Staying close to QueryDSL's API however, also means that the API is not as fluent as Blaze-Persistence users are accustomed to. This means that creating common table expressions or complex set operations may lead to superfluous code.
Examples
The following chapters demonstrate some of the possibilities of theblaze-persistence-integration-querydsl-expressionsintegration.
Plain query
QTestEntity testEntity = QTestEntity.testEntity; BlazeJPAQuery<Tuple> query = new BlazeJPAQuery<Tuple>(entityManager, cbf).from(testEntity) .select(testEntity.field.as("blep"), testEntity.field.substring(2)) .where(testEntity.field.length().gt(1)); List<Tuple> fetch = query.fetch();
Implicit joins
Contrary to JPQL, JPQL.Next allows for implicit joins. For deep path expressions it is not necessary to specify the joins manually.
List<Book> dilbert = new BlazeJPAQuery<>(entityManager, cbf).from(book) .where(book.author.name.eq("Dilbert")) .select(book).fetch();
Window functions
QTestEntity sub = new QTestEntity("sub"); BlazeJPAQuery<Tuple> query = new BlazeJPAQuery<Tuple>(entityManager, cbf).from(testEntity) .select(testEntity.field.as("blep"), JPQLNextExpressions.rowNumber(), JPQLNextExpressions.lastValue(testEntity.field).over().partitionBy(testEntity.id)) .where(testEntity.id.in(select(sub.id).from(sub))); List<Tuple> fetch = query.fetch();
Named window functions
QTestEntity sub = new QTestEntity("sub"); NamedWindow blep = new NamedWindow("whihi").partitionBy(testEntity.id); BlazeJPAQuery<Tuple> query = new BlazeJPAQuery<Tuple>(entityManager, cbf).from(testEntity) .window(blep) .select(testEntity.field.as("blep"), JPQLNextExpressions.rowNumber().over(blep), JPQLNextExpressions.lastValue(testEntity.field).over(blep)) .where(testEntity.id.in(select(sub.id).from(sub))); List<Tuple> fetch = query.fetch();
Regular association joins
Map<Author, List<Book>> booksByAuthor = new BlazeJPAQuery<>(entityManager, cbf) .from(author) .innerJoin(author.books, book) .transform(GroupBy.groupBy(author).as(GroupBy.list(book)));
Regular entity joins
QAuthor otherAuthor = new QAuthor("otherAuthor"); QBook otherBook = new QBook("otherBook"); Map<Author, List<Book>> booksByAuthor = new BlazeJPAQuery<Tuple>(entityManager, cbf) .from(otherAuthor) .innerJoin(otherBook).on(otherBook.author.eq(otherAuthor)) .transform(GroupBy.groupBy(otherAuthor).as(GroupBy.list(otherBook)));
Managed type values clause
Book theBook = new Book(); theBook.id = 1337L; theBook.name = "test"; List<Book> fetch = new BlazeJPAQuery<Book>(entityManager, cbf) .fromValues(book, Collections.singleton(theBook)) .select(book) .fetch();
Managed attribute values clause
StringPath bookName = Expressions.stringPath("bookName"); List<String> fetch = new BlazeJPAQuery<>(entityManager, cbf) .fromValues(book.name, bookName, Collections.singleton("book")) .select(bookName) .fetch();
Common Table Expressions
First declare your CTE entity:
@CTE @Entity public class IdHolderCte { @Id Long id; String name; }
Next, it can be queried as such:
List<Long> fetch = new BlazeJPAQuery<TestEntity>(entityManager, cbf) .with(idHolderCte, select( JPQLNextExpressions.bind(idHolderCte.id, book.id), JPQLNextExpressions.bind(idHolderCte.name, book.name)).from(book)) .select(idHolderCte.id).from(idHolderCte) .fetch();
Note: Set operations are also allowed in CTEs, and through set operations it is also possible to write recursive CTEs.
Subquery joins
A limitation of JPQL frequently stumbled opon, is that subqueries cannot be joined. With Blaze-Persistence however, this is perfectly possible:
QRecursiveEntity recursiveEntity = new QRecursiveEntity("t"); List<RecursiveEntity> fetch = new BlazeJPAQuery<>(entityManager, cbf) .select(recursiveEntity) .from(JPAExpressions.select(recursiveEntity) .from(recursiveEntity) .where(recursiveEntity.parent.name.eq("root1")) .orderBy(recursiveEntity.name.asc()) .limit(1L), recursiveEntity) .fetch();
The subquery may project any managed entity, including CTEs.
Lateral joins
Subquery joins are allowed to access outer query variables, if a lateral join is used.
QRecursiveEntity t = new QRecursiveEntity("t"); QRecursiveEntity subT = new QRecursiveEntity("subT"); QRecursiveEntity subT2 = new QRecursiveEntity("subT2"); List<Tuple> fetch = new BlazeJPAQuery<>(entityManager, cbf) .select(t, subT2) .from(t) .leftJoin(JPAExpressions.select(subT).from(t.children, subT).orderBy(subT.id.asc()).limit(1), subT2) .lateral() .fetch();
- Author:
- Jan-Willem Gmelig Meyling
-
Interface Summary Interface Description ExtendedFetchable<T> Extension forFetchable
JPQLNextQuery<T,Q extends JPQLNextQuery<T,Q>> Query interface for JPQL.Next queriesSetExpression<RT> Set expresion defines an interface for set operation queries.WithBuilder<R> WithBuilder
is a builder for common table expressions. -
Class Summary Class Description AbstractBlazeJPAQuery<T,Q extends AbstractBlazeJPAQuery<T,Q>> Abstract base class for JPA API based implementations of the JPQLQuery interfaceBinds<X> FactoryExpression
for representing CTE bindings.BlazeCriteriaBuilderRenderer<T> A class for rendering aBlazeJPAQuery
to aCriteriaBuilder
BlazeJPAQuery<T> BlazeJPAQuery is the default implementation of the JPQLQuery interface for Blaze-Persistence JPQL.NextFilterableWindowOver<T> FilterableWindowOver
is the first part of a WindowFunction construction.JPQLNextExpressions Utility methods for creating JPQL.next expressionsJPQLNextSerializer Slightly adjustedJPQLSerializer
implementations that has basic support for rendering set operations.JPQLNextTemplates JPQLNextTemplates
extendsJPQLTemplates
to provide operator patterns for JPQL.Next serializationNamedWindow A named window.NotEmptySetVisitor Visitor implementation that checks if a query is empty (i.e. has no default joins).SetExpressionImpl<T,Q extends AbstractBlazeJPAQuery<T,Q>> Default implementation forSetExpression
.SetOperationFlag A special type ofQueryFlag
that indicates that a subquery represents a set operation.SetUtils Utility methods for generating set operations.ValuesExpression<T> An expression type that represents aVALUES
clause that can be used asFROM
expression.WindowDefinition<Q extends WindowDefinition<Q,?>,T> A base class for window definition expressions.WindowFunction<A> WindowFunction
is a builder for window function expressions.WindowOver<T> WindowOver
is the first part of a WindowFunction construction.WindowRows<Def extends WindowDefinition<Def,?>> WindowRows
provides the building of the rows/range part of the window function expression. -
Enum Summary Enum Description DatePart DatePart
defines date parts for various date/time operationsJPQLNextOps JPQLNextOps
provides JPQL.Next specific operators.