blazebit / blaze-persistence Goto Github PK
View Code? Open in Web Editor NEWRich Criteria API for JPA providers
Home Page: https://persistence.blazebit.com
License: Apache License 2.0
Rich Criteria API for JPA providers
Home Page: https://persistence.blazebit.com
License: Apache License 2.0
Create a class CriteriaFactory which has a context and can produce criteria builders.
This can be used to bind configuration originating from extensions to that context.
ParameterAPITest#testUseParameterTwoTimes fails out of no reason.
In the PaginationTest we currently use a joinAlias directly instead of wrapping it into VALUE().
This is wrong in strict JPQL. Indexed collection paths(e.g. List or Map<Integer, String>) which have a non-entity value type, should always use the VALUE function.
Currently we always generate a fresh Expression when we call createXXXExpression. If the performance is bad, we could think about caching the expression tree and return clones.
isParameterSet throws exception for non existing parameters
This requirement resulted from issue #38
An exception is required in this scenario because this is the only scenario in which the id query can result in multiple result set rows with the same root entity id. This is because we have to include the subquery in the select clause if it is used in the order by. Furthermore, if the subquery references a collection from the surrounding query it will cause the final result set to contain multiple rows for the same root entity.
Query.setHint allows to set some very nice things such as read only and so on. Maybe we can find some hint that we can set to improve performance.
This requires a ResultTransformer that converts the flat tuple structure such that it creates collections for related tuples.
Make it possible to include subviews into a master entity view.
com.blazebit.persistence.ParameterizedComplexExpressionTest will provide you with test cases.
Currently we are adding a where clause like "KEY(map) = :key" for expression like "map[:key]". This is not completely right since we actually filter out elements that don't have a value for the given key. We should generate a JOIN-WITH clause for hibernate and a JOIN-ON clause for JPA 2.1+ instead of a where clause for filtering by key.
PaginatedCriteriaBuilder only works for entity-queries and does not support group by and distinct. Highlight this fact in the documentation.
Currently we use the class Expressions to generate expressions. An expression factory that is an instance field of CriteriaBuilderFactory should be used instead.
This also enables caching on CriteriaBuilderFactory level.
Because of the request of Thomas Herzog we should add subquery support to the SelectObjectBuilder.
See the following tests
PaginationTest#testOrderByExpression
PaginationTest#testOrderBySelectAlias
Make it possible to include collections of subviews into a master entity view.
We currently have where().
Replace this with whereSubquery(String expression), whereSubquery(String subqueryAlias, String expression) and whereSubquery().
Replace the subquery alias in the expression with the subquery expression. The expression can be transformed right after the subquery builder terminates.
The OUTER() function is used within a subquery to retrieve the join alias for a given absolute path from the surrounding query.
Extract an ExpressionFactory interface with the createSimpleExpression method. The normal implementation should not support the OUTER() function. Only the new second implementation for subqueries should support the function.
JPQL defines several literals, check if the parser can properly handle them and which are support in hibernate because I think hibernate had problems with some literals.
Given following JPQ query:
SELECT d.id, contacts.name FROM Document d LEFT JOIN d.contacts contacts WITH KEY(contacts) = 1
Hibernate generates the following SQL query:
select
document0_.id as col_0_0_,
person2_.name as col_1_0_
from
Document document0_
left outer join
contacts contacts1_
on document0_.id=contacts1_.Document_id
left outer join
Person person2_
on contacts1_.contacts_id=person2_.id
and (
contacts1_.contacts_KEY=1
)
The first left outer join is performed because d.contacts uses a collection table. Hence, if one document has assigned two contacts this single join yields two rows for this document on the left side. Now, when the Person columns are joined we receive NULLs for the contact with KEY != 1.
Currently we are generating predicates of the form "NOT path IN ..." which should also for readability be transformed into "path NOT IN ..."
Make it possible to include collections of the entity into a master entity view.
Currently we always generate a fresh query when we call getQueryString. If the performance is bad, we could think about caching the query string by name.
A CriteriaBuilderFactory could offer a method
from(String queryName, EntityManager em, Class entityClass, String alias)
The queryName could act as a cache key.
COUNT(*) is not allowed in JPQL, but Hibernate supports it. We should maybe switch to COUNT(rootAlias.id) which is what we actually want I guess.
JPQL allows mutliple FROM clause elements. Investigate if how we can implement that.
Selecting an array expression with a select alias results in a WITH clause that uses the select alias where it should use the join alias. Also see the test.
43291bd
Currently the API gives the user no possibility to specify the ON clause of a join node. This should be added in future versions.
As can be seen in the test of the following commit: fcdd593
The problem is, that the implicit join "LEFT JOIN d.contacts contacts" isn't added.
Investigate if we can introduce keyset pagination by adding PagedList#highest and PagedList#lowest which can be used to make queries for something smaller than lowest or bigger than highest http://use-the-index-luke.com/no-offset
Currently EntityViewManagers have to be created by calling EntityViewManagerProvider.from(EntityManager). CriteriaBuilders are created via Criteria.from(EntityManager, Class, String).
In the future we could provide an extension, that looks for EntityManager beans, and creates beans for EntityViewManagers and CriteriaBuilders so that those instances can be injected.
Maybe we also need to restructure how we can create object builders.
We have already prototyped the case when API, now it needs to be implemented and some more tests have to be added.
ObjectBuilders now need the JPA Metamodel and therefore we can not create them as we did before in the EntityViewExtension.
Either remove the method and auto-registration or introduce a possibility to make the persistence unit available to the extension.
Hibernate currently only allows the usage of parameters, constants and the join alias in the with-clause of a join. As a workaround we could introduce a flag that allows the generation of with-clauses as where-clause.
Where clauses should look as follows:
OUTER JOIN relation ON condition
should result in
WHERE (relation.id IS NULL OR condition)
The NULL-check is only required for OUTER-Joins (i.e. all joins except INNER JOIN).
Make it possible to include the results of subqueries into entity views.
In JPA it is invalid to do join fetches when selecting something different than the root entity. Add checks to the criteria implementation so we don't get the error at querying time but before.
Currently filters for mapping attributes can be applied with @MappingFilter which accepts a Filter class.
Hibernate filters inspired me and I want to do something similar.
Since providing a Filter class is much more typesafe we will leave it like that, but maybe the Filter interface will become an abstract class that offers some basic functionality. The @MappingFilter annotation will maybe get a name parameter which is defaulted to the attribute name. Also the constructor contract defined in the Filter interface should be removed if possible and replaced by setParameter and getParameter methods on the Filter interface/abstract class. We need getParameter for introspection in EntityViewSetting as we don't know parameter names in general but mostly assume there is only one parameter that can be set. We could maybe also introduce a convention that single parameter filters should use the parameter name 'value' or even add another method that accepts only an Object for exactly that case. That method would do what is currently provided by the constructor, but the contract would be much cleaner.
Since a method attribute or view type can then have multiple filters, but only one default, we have to add that in the metamodel.
To make filters more flexible we might also want to consider a possibility to add more than a single restriction. Currently a RestrictionBuilder is passed into the filter which is fine most of the time, but sometimes we might want to apply functions on the left hand side too, or even use more complex predicates.
This will finally make them as mighty as hibernate filters(I think), but more typesafe.
A subquery does not necessarily need a quantor, hence we should also be able to say e.g.: where("x").eq().from(...)....
We must support the following for id queries (we do not support this in the CriteriaBuilder or SubqueryBuilder):
e.g. selectSubquery("a").fromblabla.end().page(0,1).orderBySubquery("MAX(a)", true, false)
For the id query we must extract the wrapping expression for the order by clause and apply it to the corresponding select alias (which must correspond to a subquery). E.g we then have
SELECT id, MAX(SELECT bla FROM bla) AS a ORDER BY a
ProxyFactory must generate equals and hashcode
Referring to InterfaceViewTest.testInterface(), following query is generated so far:
SELECT contacts, d.id, contacts, d.name FROM Document d LEFT JOIN d.contacts contacts WHERE KEY(contacts) = 1 AND KEY(contacts) = :contactPersonNumber ORDER BY d.id ASC NULLS LAST
This results in an empty result set if :contactPersonNumber != 1
Instead the query should be built like this:
SELECT contacts1, d.id, contacts2, d.name FROM Document d LEFT JOIN d.contacts contacts1 LEFT JOIN d.contacts contacts2 WHERE KEY(contacts1) = 1 OR KEY(contacts2) = :contactPersonNumber ORDER BY d.id ASC NULLS LAST
Currently we can only join a path like "doc.localized.name" once, but it is sometimes necessary to join it multiple times with different aliases.
This is especially necessary for queries that use indexed collections.
If for example one would want to select two distinct values from a map attribute with different keys, the resulting JPQL Query could look like:
"SELECT o1, o2, FROM SomeType s LEFT JOIN s.map o1 LEFT JOIN s.map o2 WHERE KEY(o1) = 1 AND KEY(o2) = 2"
Note that this query in contrast to the next one, only returns a result, if both there are objects for both keys 1 and 2.
"SELECT o1, o2, FROM SomeType s LEFT JOIN s.map o1 LEFT JOIN s.map o2 WHERE KEY(o1) = 1 OR KEY(o2) = 2"
This query would return null for o2 if there was no entry with key 2.
When enabling this feature, please consider the different use cases.
Currently the EntityViewSetting class can only handle direct attributes. It should also be able to handle subviews and collections.
We need a hierarchy because there could be two subqueries where equal aliases are allowed.
Implement the already prototyped subquery API.
I came across the following error which describes why it is needed:
http://www.h2database.com/javadoc/org/h2/constant/ErrorCode.html#c90068
Introduce methods xxxCase etc. to be able to use case when in the respective clauses.
We will introduce methods in the criteria builder like xxxSubquery(String expression, String alias, ...) that make it possible to wrap an expression around a subquery. The MappingSubquery annotation and the metamodel have to be adapted. Also we have to adapt the current tuple element mappers for subqueries.
Currently we generate hibernate specific FROM-statements which is wrong because that is not valid JPQL. We can easily generate something like SELECT rootAlias FROM...
The expression parser fails at a expression like "COUNT(id)".
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.