From cea417d4e4b5ccd613a771cb25d6e25152216f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Thu, 8 Jun 2023 12:04:26 +0200 Subject: [PATCH] ORM/HR with Panache: if a query fails and it matches a named query we generate a nicer exception --- .../common/runtime/AbstractJpaOperations.java | 217 +++++++++--------- .../runtime/CommonPanacheQueryImpl.java | 17 +- .../common/runtime/NamedQueryUtil.java | 31 ++- .../kotlin/runtime/KotlinJpaOperations.kt | 5 +- .../kotlin/runtime/PanacheQueryImpl.kt | 5 +- .../runtime/CustomCountPanacheQuery.java | 2 +- .../orm/panache/runtime/JpaOperations.java | 4 +- .../orm/panache/runtime/PanacheQueryImpl.java | 4 +- .../common/runtime/AbstractJpaOperations.java | 111 +++++---- .../runtime/CommonPanacheQueryImpl.java | 17 +- .../common/runtime/NamedQueryUtil.java | 32 ++- .../kotlin/runtime/KotlinJpaOperations.kt | 3 +- .../kotlin/runtime/PanacheQueryImpl.kt | 3 +- .../runtime/CustomCountPanacheQuery.java | 2 +- .../panache/runtime/JpaOperations.java | 5 +- .../panache/runtime/PanacheQueryImpl.java | 4 +- .../exception/PanacheQueryException.java | 4 + .../io/quarkus/it/panache/TestEndpoint.java | 65 ++++++ .../it/panache/reactive/TestEndpoint.java | 188 ++++++++++++--- 19 files changed, 511 insertions(+), 208 deletions(-) diff --git a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java index f2abf844e335b..ebcb984482cf5 100644 --- a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java +++ b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java @@ -35,7 +35,7 @@ public static void setEntityToPersistenceUnit(Map map) { entityToPersistenceUnit = Collections.unmodifiableMap(map); } - protected abstract PanacheQueryType createPanacheQuery(EntityManager em, String query, String orderBy, + protected abstract PanacheQueryType createPanacheQuery(EntityManager em, String query, String originalQuery, String orderBy, Object paramsArrayOrMap); public abstract List list(PanacheQueryType query); @@ -195,110 +195,110 @@ public PanacheQueryType find(Class entityClass, String query, Object... param return find(entityClass, query, null, params); } - public PanacheQueryType find(Class entityClass, String query, Sort sort, Object... params) { + public PanacheQueryType find(Class entityClass, String panacheQuery, Sort sort, Object... params) { EntityManager em = getEntityManager(entityClass); - if (PanacheJpaUtil.isNamedQuery(query)) { - String namedQuery = query.substring(1); + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + String namedQuery = panacheQuery.substring(1); if (sort != null) { throw new IllegalArgumentException( "Sort cannot be used with named query, add an \"order by\" clause to the named query \"" + namedQuery + "\" instead"); } NamedQueryUtil.checkNamedQuery(entityClass, namedQuery); - return createPanacheQuery(em, query, null, params); + return createPanacheQuery(em, panacheQuery, panacheQuery, null, params); } - String findQuery = PanacheJpaUtil.createFindQuery(entityClass, query, paramCount(params)); - return createPanacheQuery(em, findQuery, PanacheJpaUtil.toOrderBy(sort), params); + String translatedHqlQuery = PanacheJpaUtil.createFindQuery(entityClass, panacheQuery, paramCount(params)); + return createPanacheQuery(em, translatedHqlQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } - public PanacheQueryType find(Class entityClass, String query, Map params) { - return find(entityClass, query, null, params); + public PanacheQueryType find(Class entityClass, String panacheQuery, Map params) { + return find(entityClass, panacheQuery, null, params); } - public PanacheQueryType find(Class entityClass, String query, Sort sort, Map params) { + public PanacheQueryType find(Class entityClass, String panacheQuery, Sort sort, Map params) { EntityManager em = getEntityManager(entityClass); - if (PanacheJpaUtil.isNamedQuery(query)) { - String namedQuery = query.substring(1); + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + String namedQuery = panacheQuery.substring(1); if (sort != null) { throw new IllegalArgumentException( "Sort cannot be used with named query, add an \"order by\" clause to the named query \"" + namedQuery + "\" instead"); } NamedQueryUtil.checkNamedQuery(entityClass, namedQuery); - return createPanacheQuery(em, query, null, params); + return createPanacheQuery(em, panacheQuery, panacheQuery, null, params); } - String findQuery = PanacheJpaUtil.createFindQuery(entityClass, query, paramCount(params)); - return createPanacheQuery(em, findQuery, PanacheJpaUtil.toOrderBy(sort), params); + String translatedHqlQuery = PanacheJpaUtil.createFindQuery(entityClass, panacheQuery, paramCount(params)); + return createPanacheQuery(em, translatedHqlQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } - public PanacheQueryType find(Class entityClass, String query, Parameters params) { - return find(entityClass, query, null, params); + public PanacheQueryType find(Class entityClass, String panacheQuery, Parameters params) { + return find(entityClass, panacheQuery, null, params); } - public PanacheQueryType find(Class entityClass, String query, Sort sort, Parameters params) { - return find(entityClass, query, sort, params.map()); + public PanacheQueryType find(Class entityClass, String panacheQuery, Sort sort, Parameters params) { + return find(entityClass, panacheQuery, sort, params.map()); } - public List list(Class entityClass, String query, Object... params) { - return list(find(entityClass, query, params)); + public List list(Class entityClass, String panacheQuery, Object... params) { + return list(find(entityClass, panacheQuery, params)); } - public List list(Class entityClass, String query, Sort sort, Object... params) { - return list(find(entityClass, query, sort, params)); + public List list(Class entityClass, String panacheQuery, Sort sort, Object... params) { + return list(find(entityClass, panacheQuery, sort, params)); } - public List list(Class entityClass, String query, Map params) { - return list(find(entityClass, query, params)); + public List list(Class entityClass, String panacheQuery, Map params) { + return list(find(entityClass, panacheQuery, params)); } - public List list(Class entityClass, String query, Sort sort, Map params) { - return list(find(entityClass, query, sort, params)); + public List list(Class entityClass, String panacheQuery, Sort sort, Map params) { + return list(find(entityClass, panacheQuery, sort, params)); } - public List list(Class entityClass, String query, Parameters params) { - return list(find(entityClass, query, params)); + public List list(Class entityClass, String panacheQuery, Parameters params) { + return list(find(entityClass, panacheQuery, params)); } - public List list(Class entityClass, String query, Sort sort, Parameters params) { - return list(find(entityClass, query, sort, params)); + public List list(Class entityClass, String panacheQuery, Sort sort, Parameters params) { + return list(find(entityClass, panacheQuery, sort, params)); } - public Stream stream(Class entityClass, String query, Object... params) { - return stream(find(entityClass, query, params)); + public Stream stream(Class entityClass, String panacheQuery, Object... params) { + return stream(find(entityClass, panacheQuery, params)); } - public Stream stream(Class entityClass, String query, Sort sort, Object... params) { - return stream(find(entityClass, query, sort, params)); + public Stream stream(Class entityClass, String panacheQuery, Sort sort, Object... params) { + return stream(find(entityClass, panacheQuery, sort, params)); } - public Stream stream(Class entityClass, String query, Map params) { - return stream(find(entityClass, query, params)); + public Stream stream(Class entityClass, String panacheQuery, Map params) { + return stream(find(entityClass, panacheQuery, params)); } - public Stream stream(Class entityClass, String query, Sort sort, Map params) { - return stream(find(entityClass, query, sort, params)); + public Stream stream(Class entityClass, String panacheQuery, Sort sort, Map params) { + return stream(find(entityClass, panacheQuery, sort, params)); } - public Stream stream(Class entityClass, String query, Parameters params) { - return stream(find(entityClass, query, params)); + public Stream stream(Class entityClass, String panacheQuery, Parameters params) { + return stream(find(entityClass, panacheQuery, params)); } - public Stream stream(Class entityClass, String query, Sort sort, Parameters params) { - return stream(find(entityClass, query, sort, params)); + public Stream stream(Class entityClass, String panacheQuery, Sort sort, Parameters params) { + return stream(find(entityClass, panacheQuery, sort, params)); } public PanacheQueryType findAll(Class entityClass) { String query = "FROM " + PanacheJpaUtil.getEntityName(entityClass); EntityManager em = getEntityManager(entityClass); - return createPanacheQuery(em, query, null, null); + return createPanacheQuery(em, query, null, null, null); } public PanacheQueryType findAll(Class entityClass, Sort sort) { String query = "FROM " + PanacheJpaUtil.getEntityName(entityClass); EntityManager em = getEntityManager(entityClass); - return createPanacheQuery(em, query, PanacheJpaUtil.toOrderBy(sort), null); + return createPanacheQuery(em, query, null, PanacheJpaUtil.toOrderBy(sort), null); } public List listAll(Class entityClass) { @@ -323,28 +323,37 @@ public long count(Class entityClass) { .getSingleResult(); } - public long count(Class entityClass, String query, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public long count(Class entityClass, String panacheQuery, Object... params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return (long) bindParameters(namedQuery, params).getSingleResult(); } - return (long) bindParameters( - getEntityManager(entityClass) - .createQuery(PanacheJpaUtil.createCountQuery(entityClass, query, paramCount(params))), - params).getSingleResult(); + try { + return (long) bindParameters( + getEntityManager(entityClass) + .createQuery(PanacheJpaUtil.createCountQuery(entityClass, panacheQuery, paramCount(params))), + params).getSingleResult(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); + } } - public long count(Class entityClass, String query, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public long count(Class entityClass, String panacheQuery, Map params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return (long) bindParameters(namedQuery, params).getSingleResult(); } - return (long) bindParameters( - getEntityManager(entityClass) - .createQuery(PanacheJpaUtil.createCountQuery(entityClass, query, paramCount(params))), - params).getSingleResult(); + try { + return (long) bindParameters( + getEntityManager(entityClass) + .createQuery(PanacheJpaUtil.createCountQuery(entityClass, panacheQuery, paramCount(params))), + params).getSingleResult(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); + } + } public long count(Class entityClass, String query, Parameters params) { @@ -392,30 +401,38 @@ public boolean deleteById(Class entityClass, Object id) { return true; } - public long delete(Class entityClass, String query, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public long delete(Class entityClass, String panacheQuery, Object... params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return bindParameters(namedQuery, params).executeUpdate(); } - return bindParameters( - getEntityManager(entityClass) - .createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, query, paramCount(params))), - params) - .executeUpdate(); + try { + return bindParameters( + getEntityManager(entityClass) + .createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, panacheQuery, paramCount(params))), + params) + .executeUpdate(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); + } } - public long delete(Class entityClass, String query, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public long delete(Class entityClass, String panacheQuery, Map params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return bindParameters(namedQuery, params).executeUpdate(); } - return bindParameters( - getEntityManager(entityClass) - .createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, query, paramCount(params))), - params) - .executeUpdate(); + try { + return bindParameters( + getEntityManager(entityClass) + .createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, panacheQuery, paramCount(params))), + params) + .executeUpdate(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); + } } public long delete(Class entityClass, String query, Parameters params) { @@ -445,46 +462,36 @@ public int executeUpdate(String query, Map params) { return jpaQuery.executeUpdate(); } - public int executeUpdate(String query, Class entityClass, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public int executeUpdate(Class entityClass, String panacheQuery, Object... params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return bindParameters(namedQuery, params).executeUpdate(); } - Query jpaQuery = getEntityManager(entityClass).createQuery(query); - bindParameters(jpaQuery, params); - return jpaQuery.executeUpdate(); - } - - public int executeUpdate(String query, Class entityClass, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); - return bindParameters(namedQuery, params).executeUpdate(); + try { + String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, panacheQuery, paramCount(params)); + Query jpaQuery = getEntityManager(entityClass).createQuery(updateQuery); + bindParameters(jpaQuery, params); + return jpaQuery.executeUpdate(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); } - - Query jpaQuery = getEntityManager(entityClass).createQuery(query); - bindParameters(jpaQuery, params); - return jpaQuery.executeUpdate(); } - public int executeUpdate(Class entityClass, String query, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); + public int executeUpdate(Class entityClass, String panacheQuery, Map params) { + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + Query namedQuery = extractNamedQuery(entityClass, panacheQuery); return bindParameters(namedQuery, params).executeUpdate(); } - String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, query, paramCount(params)); - return executeUpdate(updateQuery, entityClass, params); - } - - public int executeUpdate(Class entityClass, String query, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) { - Query namedQuery = extractNamedQuery(entityClass, query); - return bindParameters(namedQuery, params).executeUpdate(); + try { + String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, panacheQuery, paramCount(params)); + Query jpaQuery = getEntityManager(entityClass).createQuery(updateQuery); + bindParameters(jpaQuery, params); + return jpaQuery.executeUpdate(); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, panacheQuery); } - - String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, query, paramCount(params)); - return executeUpdate(updateQuery, entityClass, params); } public int update(Class entityClass, String query, Map params) { diff --git a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java index 2560932c0ade0..531958d8b8071 100644 --- a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java +++ b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java @@ -38,7 +38,14 @@ public void close() { }; private Object paramsArrayOrMap; + /** + * this is the HQL query expanded from the Panache-Query + */ private String query; + /** + * this is the original Panache-Query, if any (can be null) + */ + private String originalQuery; protected String countQuery; private String orderBy; private EntityManager em; @@ -53,9 +60,11 @@ public void close() { private Map> filters; - public CommonPanacheQueryImpl(EntityManager em, String query, String orderBy, Object paramsArrayOrMap) { + public CommonPanacheQueryImpl(EntityManager em, String query, String originalQuery, String orderBy, + Object paramsArrayOrMap) { this.em = em; this.query = query; + this.originalQuery = originalQuery; this.orderBy = orderBy; this.paramsArrayOrMap = paramsArrayOrMap; } @@ -350,7 +359,11 @@ private Query createBaseQuery() { String namedQuery = query.substring(1); jpaQuery = em.createNamedQuery(namedQuery); } else { - jpaQuery = em.createQuery(orderBy != null ? query + orderBy : query); + try { + jpaQuery = em.createQuery(orderBy != null ? query + orderBy : query); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, originalQuery); + } } if (paramsArrayOrMap instanceof Map) { diff --git a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/NamedQueryUtil.java b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/NamedQueryUtil.java index 2f08368ff20c9..9e8c3a46ddf03 100644 --- a/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/NamedQueryUtil.java +++ b/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/NamedQueryUtil.java @@ -4,6 +4,8 @@ import java.util.Map; import java.util.Set; +import org.hibernate.query.SemanticException; + import io.quarkus.panache.common.exception.PanacheQueryException; public final class NamedQueryUtil { @@ -20,10 +22,35 @@ public static void setNamedQueryMap(Map> newNamedQueryMap) { } public static void checkNamedQuery(Class entityClass, String namedQuery) { - Set namedQueries = namedQueryMap.get(entityClass.getName()); - if (namedQueries == null || !namedQueries.contains(namedQuery)) { + if (!isNamedQuery(entityClass, namedQuery)) { throw new PanacheQueryException("The named query '" + namedQuery + "' must be defined on your JPA entity or one of its super classes"); } } + + public static boolean isNamedQuery(Class entityClass, String namedQuery) { + Set namedQueries = namedQueryMap.get(entityClass.getName()); + return namedQueries != null && namedQueries.contains(namedQuery); + } + + private static boolean isNamedQuery(String namedQuery) { + for (Set namedQueries : namedQueryMap.values()) { + if (namedQueries.contains(namedQuery)) { + return true; + } + } + return false; + } + + public static RuntimeException checkForNamedQueryMistake(IllegalArgumentException x, String originalQuery) { + if (originalQuery != null + && x.getCause() instanceof SemanticException + && isNamedQuery(originalQuery)) { + return new PanacheQueryException("Invalid query '" + originalQuery + + "' but it matches a known @NamedQuery, perhaps you should prefix it with a '#' to use it as a named query: '#" + + originalQuery + "'", x); + } else { + return x; + } + } } diff --git a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/KotlinJpaOperations.kt b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/KotlinJpaOperations.kt index 75620a7d1abe2..a8348890cee26 100644 --- a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/KotlinJpaOperations.kt +++ b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/KotlinJpaOperations.kt @@ -6,10 +6,11 @@ import jakarta.persistence.EntityManager class KotlinJpaOperations : AbstractJpaOperations>() { override fun createPanacheQuery( em: EntityManager, - query: String, + hqlQuery: String, + originalQuery: String?, orderBy: String?, paramsArrayOrMap: Any? - ) = PanacheQueryImpl(em, query, orderBy, paramsArrayOrMap) + ) = PanacheQueryImpl(em, hqlQuery, originalQuery, orderBy, paramsArrayOrMap) override fun list(query: PanacheQueryImpl<*>) = query.list() diff --git a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/PanacheQueryImpl.kt b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/PanacheQueryImpl.kt index b7e4ac79948ee..e63ea6b628290 100644 --- a/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/PanacheQueryImpl.kt +++ b/extensions/panache/hibernate-orm-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/PanacheQueryImpl.kt @@ -13,11 +13,12 @@ class PanacheQueryImpl : PanacheQuery { internal constructor( em: EntityManager?, - query: String?, + hqlQuery: String?, + originalQuery: String?, orderBy: String?, paramsArrayOrMap: Any? ) { - delegate = CommonPanacheQueryImpl(em, query, orderBy, paramsArrayOrMap) + delegate = CommonPanacheQueryImpl(em, hqlQuery, originalQuery, orderBy, paramsArrayOrMap) } private constructor(delegate: CommonPanacheQueryImpl) { diff --git a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/CustomCountPanacheQuery.java b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/CustomCountPanacheQuery.java index 36c1148f1ece6..5d2d173755d16 100644 --- a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/CustomCountPanacheQuery.java +++ b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/CustomCountPanacheQuery.java @@ -13,7 +13,7 @@ public class CustomCountPanacheQuery extends PanacheQueryImpl { public CustomCountPanacheQuery(EntityManager em, Query jpaQuery, String customCountQuery, Object paramsArrayOrMap) { - super(new CommonPanacheQueryImpl<>(em, castQuery(jpaQuery).getQueryString(), null, paramsArrayOrMap) { + super(new CommonPanacheQueryImpl<>(em, castQuery(jpaQuery).getQueryString(), null, null, paramsArrayOrMap) { { this.countQuery = customCountQuery; } diff --git a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/JpaOperations.java b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/JpaOperations.java index 380f66dd0f1f1..ab0f0dbc6a72d 100644 --- a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/JpaOperations.java +++ b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/JpaOperations.java @@ -14,9 +14,9 @@ public class JpaOperations extends AbstractJpaOperations> { public static final JpaOperations INSTANCE = new JpaOperations(); @Override - protected PanacheQueryImpl createPanacheQuery(EntityManager em, String query, String orderBy, + protected PanacheQueryImpl createPanacheQuery(EntityManager em, String query, String originalQuery, String orderBy, Object paramsArrayOrMap) { - return new PanacheQueryImpl<>(em, query, orderBy, paramsArrayOrMap); + return new PanacheQueryImpl<>(em, query, originalQuery, orderBy, paramsArrayOrMap); } @Override diff --git a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/PanacheQueryImpl.java b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/PanacheQueryImpl.java index 00bd2bf6f3ba1..900f2bf1ac710 100644 --- a/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/PanacheQueryImpl.java +++ b/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/runtime/PanacheQueryImpl.java @@ -18,8 +18,8 @@ public class PanacheQueryImpl implements PanacheQuery { private CommonPanacheQueryImpl delegate; - PanacheQueryImpl(EntityManager em, String query, String orderBy, Object paramsArrayOrMap) { - this.delegate = new CommonPanacheQueryImpl<>(em, query, orderBy, paramsArrayOrMap); + PanacheQueryImpl(EntityManager em, String query, String originalQuery, String orderBy, Object paramsArrayOrMap) { + this.delegate = new CommonPanacheQueryImpl<>(em, query, originalQuery, orderBy, paramsArrayOrMap); } protected PanacheQueryImpl(CommonPanacheQueryImpl delegate) { diff --git a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/AbstractJpaOperations.java b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/AbstractJpaOperations.java index e3f5b77ffcf00..6745b72f55274 100644 --- a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/AbstractJpaOperations.java +++ b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/AbstractJpaOperations.java @@ -24,7 +24,8 @@ public abstract class AbstractJpaOperations { static final long TIMEOUT_MS = 5000; private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - protected abstract PanacheQueryType createPanacheQuery(Uni session, String query, String orderBy, + protected abstract PanacheQueryType createPanacheQuery(Uni session, String query, String originalQuery, + String orderBy, Object paramsArrayOrMap); protected abstract Uni> list(PanacheQueryType query); @@ -102,44 +103,44 @@ public Uni findById(Class entityClass, Object id, LockModeType lockModeTyp .chain(session -> session.find(entityClass, id, LockModeConverter.convertToLockMode(lockModeType))); } - public PanacheQueryType find(Class entityClass, String query, Object... params) { - return find(entityClass, query, null, params); + public PanacheQueryType find(Class entityClass, String panacheQuery, Object... params) { + return find(entityClass, panacheQuery, null, params); } - public PanacheQueryType find(Class entityClass, String query, Sort sort, Object... params) { - String findQuery = PanacheJpaUtil.createFindQuery(entityClass, query, paramCount(params)); + public PanacheQueryType find(Class entityClass, String panacheQuery, Sort sort, Object... params) { Uni session = getSession(); - if (PanacheJpaUtil.isNamedQuery(query)) { - String namedQuery = query.substring(1); + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + String namedQuery = panacheQuery.substring(1); if (sort != null) { throw new IllegalArgumentException( "Sort cannot be used with named query, add an \"order by\" clause to the named query \"" + namedQuery + "\" instead"); } NamedQueryUtil.checkNamedQuery(entityClass, namedQuery); - return createPanacheQuery(session, query, PanacheJpaUtil.toOrderBy(sort), params); + return createPanacheQuery(session, panacheQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } - return createPanacheQuery(session, findQuery, PanacheJpaUtil.toOrderBy(sort), params); + String hqlQuery = PanacheJpaUtil.createFindQuery(entityClass, panacheQuery, paramCount(params)); + return createPanacheQuery(session, hqlQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } - public PanacheQueryType find(Class entityClass, String query, Map params) { - return find(entityClass, query, null, params); + public PanacheQueryType find(Class entityClass, String panacheQuery, Map params) { + return find(entityClass, panacheQuery, null, params); } - public PanacheQueryType find(Class entityClass, String query, Sort sort, Map params) { - String findQuery = PanacheJpaUtil.createFindQuery(entityClass, query, paramCount(params)); + public PanacheQueryType find(Class entityClass, String panacheQuery, Sort sort, Map params) { Uni session = getSession(); - if (PanacheJpaUtil.isNamedQuery(query)) { - String namedQuery = query.substring(1); + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) { + String namedQuery = panacheQuery.substring(1); if (sort != null) { throw new IllegalArgumentException( "Sort cannot be used with named query, add an \"order by\" clause to the named query \"" + namedQuery + "\" instead"); } NamedQueryUtil.checkNamedQuery(entityClass, namedQuery); - return createPanacheQuery(session, query, PanacheJpaUtil.toOrderBy(sort), params); + return createPanacheQuery(session, panacheQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } - return createPanacheQuery(session, findQuery, PanacheJpaUtil.toOrderBy(sort), params); + String hqlQuery = PanacheJpaUtil.createFindQuery(entityClass, panacheQuery, paramCount(params)); + return createPanacheQuery(session, hqlQuery, panacheQuery, PanacheJpaUtil.toOrderBy(sort), params); } public PanacheQueryType find(Class entityClass, String query, Parameters params) { @@ -177,13 +178,13 @@ public Uni> list(Class entityClass, String query, Sort sort, Paramete public PanacheQueryType findAll(Class entityClass) { String query = "FROM " + PanacheJpaUtil.getEntityName(entityClass); Uni session = getSession(); - return createPanacheQuery(session, query, null, null); + return createPanacheQuery(session, query, null, null, null); } public PanacheQueryType findAll(Class entityClass, Sort sort) { String query = "FROM " + PanacheJpaUtil.getEntityName(entityClass); Uni session = getSession(); - return createPanacheQuery(session, query, PanacheJpaUtil.toOrderBy(sort), null); + return createPanacheQuery(session, query, null, PanacheJpaUtil.toOrderBy(sort), null); } public Uni> listAll(Class entityClass) { @@ -202,33 +203,37 @@ public Uni count(Class entityClass) { } @SuppressWarnings({ "unchecked", "rawtypes" }) - public Uni count(Class entityClass, String query, Object... params) { + public Uni count(Class entityClass, String panacheQuery, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName, Long.class), params).getSingleResult(); }); return (Uni) getSession().chain(session -> bindParameters( - session.createQuery(PanacheJpaUtil.createCountQuery(entityClass, query, paramCount(params))), - params).getSingleResult()); + session.createQuery(PanacheJpaUtil.createCountQuery(entityClass, panacheQuery, paramCount(params))), + params).getSingleResult()) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } @SuppressWarnings({ "rawtypes", "unchecked" }) - public Uni count(Class entityClass, String query, Map params) { + public Uni count(Class entityClass, String panacheQuery, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName, Long.class), params).getSingleResult(); }); return (Uni) getSession().chain(session -> bindParameters( - session.createQuery(PanacheJpaUtil.createCountQuery(entityClass, query, paramCount(params))), - params).getSingleResult()); + session.createQuery(PanacheJpaUtil.createCountQuery(entityClass, panacheQuery, paramCount(params))), + params).getSingleResult()) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } public Uni count(Class entityClass, String query, Parameters params) { @@ -269,32 +274,36 @@ public Uni deleteById(Class entityClass, Object id) { }); } - public Uni delete(Class entityClass, String query, Object... params) { + public Uni delete(Class entityClass, String panacheQuery, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName), params).executeUpdate().map(Integer::longValue); }); return getSession().chain(session -> bindParameters( - session.createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, query, paramCount(params))), params) - .executeUpdate().map(Integer::longValue)); + session.createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, panacheQuery, paramCount(params))), params) + .executeUpdate().map(Integer::longValue)) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } - public Uni delete(Class entityClass, String query, Map params) { + public Uni delete(Class entityClass, String panacheQuery, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName), params).executeUpdate().map(Integer::longValue); }); return getSession().chain(session -> bindParameters( - session.createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, query, paramCount(params))), params) - .executeUpdate().map(Integer::longValue)); + session.createQuery(PanacheJpaUtil.createDeleteQuery(entityClass, panacheQuery, paramCount(params))), params) + .executeUpdate().map(Integer::longValue)) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } public Uni delete(Class entityClass, String query, Parameters params) { @@ -306,30 +315,34 @@ public IllegalStateException implementationInjectionMissing() { "This method is normally automatically overridden in subclasses: did you forget to annotate your entity with @Entity?"); } - public Uni executeUpdate(Class entityClass, String query, Object... params) { + public Uni executeUpdate(Class entityClass, String panacheQuery, Object... params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName), params).executeUpdate(); }); - String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, query, paramCount(params)); - return executeUpdate(updateQuery, params); + String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, panacheQuery, paramCount(params)); + return executeUpdate(updateQuery, params) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } - public Uni executeUpdate(Class entityClass, String query, Map params) { + public Uni executeUpdate(Class entityClass, String panacheQuery, Map params) { - if (PanacheJpaUtil.isNamedQuery(query)) + if (PanacheJpaUtil.isNamedQuery(panacheQuery)) return (Uni) getSession().chain(session -> { - String namedQueryName = query.substring(1); + String namedQueryName = panacheQuery.substring(1); NamedQueryUtil.checkNamedQuery(entityClass, namedQueryName); return bindParameters(session.createNamedQuery(namedQueryName), params).executeUpdate(); }); - String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, query, paramCount(params)); - return executeUpdate(updateQuery, params); + String updateQuery = PanacheJpaUtil.createUpdateQuery(entityClass, panacheQuery, paramCount(params)); + return executeUpdate(updateQuery, params) + .onFailure(IllegalArgumentException.class) + .transform(x -> NamedQueryUtil.checkForNamedQueryMistake((IllegalArgumentException) x, panacheQuery)); } public Uni update(Class entityClass, String query, Map params) { diff --git a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/CommonPanacheQueryImpl.java b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/CommonPanacheQueryImpl.java index 2862cf3379c81..0419cc9b22ea2 100644 --- a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/CommonPanacheQueryImpl.java +++ b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/CommonPanacheQueryImpl.java @@ -25,7 +25,14 @@ public class CommonPanacheQueryImpl { private Object paramsArrayOrMap; + /** + * this is the HQL query expanded from the Panache-Query + */ private String query; + /** + * this is the original Panache-Query, if any (can be null) + */ + private String originalQuery; protected String countQuery; private String orderBy; private Uni em; @@ -40,9 +47,11 @@ public class CommonPanacheQueryImpl { private Map> filters; - public CommonPanacheQueryImpl(Uni em, String query, String orderBy, Object paramsArrayOrMap) { + public CommonPanacheQueryImpl(Uni em, String query, String originalQuery, String orderBy, + Object paramsArrayOrMap) { this.em = em; this.query = query; + this.originalQuery = originalQuery; this.orderBy = orderBy; this.paramsArrayOrMap = paramsArrayOrMap; } @@ -340,7 +349,11 @@ private Mutiny.Query createBaseQuery(Mutiny.Session em) { String namedQuery = query.substring(1); jpaQuery = em.createNamedQuery(namedQuery); } else { - jpaQuery = em.createQuery(orderBy != null ? query + orderBy : query); + try { + jpaQuery = em.createQuery(orderBy != null ? query + orderBy : query); + } catch (IllegalArgumentException x) { + throw NamedQueryUtil.checkForNamedQueryMistake(x, originalQuery); + } } if (paramsArrayOrMap instanceof Map) { diff --git a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/NamedQueryUtil.java b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/NamedQueryUtil.java index c251a7f6317ca..75a869a1324e1 100644 --- a/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/NamedQueryUtil.java +++ b/extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/NamedQueryUtil.java @@ -4,6 +4,9 @@ import java.util.Map; import java.util.Set; +import org.hibernate.query.SemanticException; +import org.hibernate.query.sqm.ParsingException; + import io.quarkus.panache.common.exception.PanacheQueryException; public final class NamedQueryUtil { @@ -20,10 +23,35 @@ public static void setNamedQueryMap(Map> newNamedQueryMap) { } public static void checkNamedQuery(Class entityClass, String namedQuery) { - Set namedQueries = namedQueryMap.get(entityClass.getName()); - if (namedQueries == null || !namedQueries.contains(namedQuery)) { + if (!isNamedQuery(entityClass, namedQuery)) { throw new PanacheQueryException("The named query '" + namedQuery + "' must be defined on your JPA entity or one of its super classes"); } } + + public static boolean isNamedQuery(Class entityClass, String namedQuery) { + Set namedQueries = namedQueryMap.get(entityClass.getName()); + return namedQueries != null && namedQueries.contains(namedQuery); + } + + private static boolean isNamedQuery(String namedQuery) { + for (Set namedQueries : namedQueryMap.values()) { + if (namedQueries.contains(namedQuery)) { + return true; + } + } + return false; + } + + public static RuntimeException checkForNamedQueryMistake(IllegalArgumentException x, String originalQuery) { + if (originalQuery != null + && (x.getCause() instanceof SemanticException || x.getCause() instanceof ParsingException) + && isNamedQuery(originalQuery)) { + return new PanacheQueryException("Invalid query '" + originalQuery + + "' but it matches a known @NamedQuery, perhaps you should prefix it with a '#' to use it as a named query: '#" + + originalQuery + "'", x); + } else { + return x; + } + } } diff --git a/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/KotlinJpaOperations.kt b/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/KotlinJpaOperations.kt index fdbb43f137aff..c8d1a060ccf84 100644 --- a/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/KotlinJpaOperations.kt +++ b/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/KotlinJpaOperations.kt @@ -8,9 +8,10 @@ class KotlinJpaOperations : AbstractJpaOperations>() { override fun createPanacheQuery( session: Uni, query: String, + originalQuery: String?, orderBy: String?, paramsArrayOrMap: Any? - ) = PanacheQueryImpl(session, query, orderBy, paramsArrayOrMap) + ) = PanacheQueryImpl(session, query, originalQuery, orderBy, paramsArrayOrMap) override fun list(query: PanacheQueryImpl<*>): Uni> = query.list() as Uni> diff --git a/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/PanacheQueryImpl.kt b/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/PanacheQueryImpl.kt index ff2b9d48ebc31..ab5e6a0761621 100644 --- a/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/PanacheQueryImpl.kt +++ b/extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/main/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/runtime/PanacheQueryImpl.kt @@ -14,10 +14,11 @@ class PanacheQueryImpl : PanacheQuery { internal constructor( em: Uni, query: String?, + originalQuery: String?, orderBy: String?, paramsArrayOrMap: Any? ) { - delegate = CommonPanacheQueryImpl(em, query, orderBy, paramsArrayOrMap) + delegate = CommonPanacheQueryImpl(em, query, originalQuery, orderBy, paramsArrayOrMap) } private constructor(delegate: CommonPanacheQueryImpl) { diff --git a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/CustomCountPanacheQuery.java b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/CustomCountPanacheQuery.java index 0bbe7ca504f85..00f1cbf9e943e 100644 --- a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/CustomCountPanacheQuery.java +++ b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/CustomCountPanacheQuery.java @@ -11,7 +11,7 @@ public class CustomCountPanacheQuery extends PanacheQueryImpl { public CustomCountPanacheQuery(Uni em, String query, String customCountQuery, Object paramsArrayOrMap) { - super(new CommonPanacheQueryImpl(em, query, null, paramsArrayOrMap) { + super(new CommonPanacheQueryImpl(em, query, null, null, paramsArrayOrMap) { { this.countQuery = customCountQuery; } diff --git a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/JpaOperations.java b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/JpaOperations.java index bc671a43c83aa..5f888b55d744b 100644 --- a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/JpaOperations.java +++ b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/JpaOperations.java @@ -12,9 +12,10 @@ public class JpaOperations extends AbstractJpaOperations> { public static final JpaOperations INSTANCE = new JpaOperations(); @Override - protected PanacheQueryImpl createPanacheQuery(Uni session, String query, String orderBy, + protected PanacheQueryImpl createPanacheQuery(Uni session, String query, String originalQuery, + String orderBy, Object paramsArrayOrMap) { - return new PanacheQueryImpl<>(session, query, orderBy, paramsArrayOrMap); + return new PanacheQueryImpl<>(session, query, originalQuery, orderBy, paramsArrayOrMap); } @SuppressWarnings({ "rawtypes", "unchecked" }) diff --git a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/PanacheQueryImpl.java b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/PanacheQueryImpl.java index 6ae96e94c5a02..0c3c8f481e245 100644 --- a/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/PanacheQueryImpl.java +++ b/extensions/panache/hibernate-reactive-panache/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/runtime/PanacheQueryImpl.java @@ -18,8 +18,8 @@ public class PanacheQueryImpl implements PanacheQuery { private CommonPanacheQueryImpl delegate; - PanacheQueryImpl(Uni em, String query, String orderBy, Object paramsArrayOrMap) { - this.delegate = new CommonPanacheQueryImpl(em, query, orderBy, paramsArrayOrMap); + PanacheQueryImpl(Uni em, String query, String originalQuery, String orderBy, Object paramsArrayOrMap) { + this.delegate = new CommonPanacheQueryImpl(em, query, originalQuery, orderBy, paramsArrayOrMap); } protected PanacheQueryImpl(CommonPanacheQueryImpl delegate) { diff --git a/extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/exception/PanacheQueryException.java b/extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/exception/PanacheQueryException.java index 5cfc1a925702e..756cc15116120 100644 --- a/extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/exception/PanacheQueryException.java +++ b/extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/exception/PanacheQueryException.java @@ -4,4 +4,8 @@ public class PanacheQueryException extends RuntimeException { public PanacheQueryException(String s) { super(s); } + + public PanacheQueryException(String s, Throwable cause) { + super(s, cause); + } } diff --git a/integration-tests/hibernate-orm-panache/src/main/java/io/quarkus/it/panache/TestEndpoint.java b/integration-tests/hibernate-orm-panache/src/main/java/io/quarkus/it/panache/TestEndpoint.java index 3ea97d484cc46..375605f439b66 100644 --- a/integration-tests/hibernate-orm-panache/src/main/java/io/quarkus/it/panache/TestEndpoint.java +++ b/integration-tests/hibernate-orm-panache/src/main/java/io/quarkus/it/panache/TestEndpoint.java @@ -176,10 +176,12 @@ public String testModel() { () -> Person.find("#Person.getByName", Sort.by("name"), Parameters.with("name", "stef"))); NamedQueryEntity.find("#NamedQueryMappedSuperClass.getAll").list(); NamedQueryEntity.find("#NamedQueryEntity.getAll").list(); + Assertions.assertThrows(PanacheQueryException.class, () -> NamedQueryEntity.find("NamedQueryEntity.getAll").list()); NamedQueryWith2QueriesEntity.find("#NamedQueryWith2QueriesEntity.getAll1").list(); NamedQueryWith2QueriesEntity.find("#NamedQueryWith2QueriesEntity.getAll2").list(); Assertions.assertEquals(1, Person.count("#Person.countAll")); + Assertions.assertThrows(PanacheQueryException.class, () -> Person.count("Person.countAll")); Assertions.assertEquals(1, Person.count("#Person.countByName", Parameters.with("name", "stef").map())); Assertions.assertEquals(1, Person.count("#Person.countByName", Parameters.with("name", "stef"))); Assertions.assertEquals(1, Person.count("#Person.countByName.ordinal", "stef")); @@ -188,6 +190,9 @@ public String testModel() { persons = Person.find("#Person.getByName", Parameters.with("name", "stef2")).list(); Assertions.assertEquals(1, persons.size()); + Assertions.assertThrows(PanacheQueryException.class, + () -> Person.update("Person.updateAllNames", Parameters.with("name", "stef2").map())); + Assertions.assertEquals(1, Person.update("#Person.updateAllNames", Parameters.with("name", "stef3"))); persons = Person.find("#Person.getByName", Parameters.with("name", "stef3")).list(); Assertions.assertEquals(1, persons.size()); @@ -210,6 +215,8 @@ public String testModel() { Assertions.assertEquals(1, Person.delete("#Person.deleteAll")); Assertions.assertEquals(0, Person.find("").list().size()); + Assertions.assertThrows(PanacheQueryException.class, () -> Person.delete("Person.deleteAll")); + person = makeSavedPerson(); Dog.deleteAll(); Assertions.assertEquals(1, Person.find("").list().size()); @@ -719,9 +726,67 @@ public String testModelDao() { () -> personDao.find("#Person.getByName", Sort.by("name"), Parameters.with("name", "stef"))); namedQueryRepository.find("#NamedQueryMappedSuperClass.getAll").list(); namedQueryRepository.find("#NamedQueryEntity.getAll").list(); + Assertions.assertThrows(PanacheQueryException.class, () -> namedQueryRepository.find("NamedQueryEntity.getAll").list()); namedQueryWith2QueriesRepository.find("#NamedQueryWith2QueriesEntity.getAll1").list(); namedQueryWith2QueriesRepository.find("#NamedQueryWith2QueriesEntity.getAll2").list(); + Assertions.assertEquals(1, personDao.count("#Person.countAll")); + Assertions.assertThrows(PanacheQueryException.class, () -> personDao.count("Person.countAll")); + Assertions.assertEquals(1, personDao.count("#Person.countByName", Parameters.with("name", "stef").map())); + Assertions.assertEquals(1, personDao.count("#Person.countByName", Parameters.with("name", "stef"))); + Assertions.assertEquals(1, personDao.count("#Person.countByName.ordinal", "stef")); + + Assertions.assertEquals(1, personDao.update("#Person.updateAllNames", Parameters.with("name", "stef2").map())); + persons = personDao.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + Assertions.assertEquals(1, persons.size()); + + Assertions.assertThrows(PanacheQueryException.class, + () -> personDao.update("Person.updateAllNames", Parameters.with("name", "stef2").map())); + + Assertions.assertEquals(1, personDao.update("#Person.updateAllNames", Parameters.with("name", "stef3"))); + persons = personDao.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + Assertions.assertEquals(1, persons.size()); + + Assertions.assertEquals(1, personDao.update("#Person.updateNameById", + Parameters.with("name", "stef2").and("id", person.id).map())); + persons = personDao.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + Assertions.assertEquals(1, persons.size()); + + Assertions.assertEquals(1, personDao.update("#Person.updateNameById", + Parameters.with("name", "stef3").and("id", person.id))); + persons = personDao.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + Assertions.assertEquals(1, persons.size()); + + Assertions.assertEquals(1, personDao.update("#Person.updateNameById.ordinal", "stef", person.id)); + persons = personDao.find("#Person.getByName", Parameters.with("name", "stef")).list(); + Assertions.assertEquals(1, persons.size()); + + Dog.deleteAll(); + Assertions.assertEquals(1, personDao.delete("#Person.deleteAll")); + Assertions.assertEquals(0, personDao.find("").list().size()); + + Assertions.assertThrows(PanacheQueryException.class, () -> personDao.delete("Person.deleteAll")); + + person = makeSavedPersonDao(); + dogDao.deleteAll(); + Assertions.assertEquals(1, personDao.find("").list().size()); + Assertions.assertEquals(1, personDao.delete("#Person.deleteById", Parameters.with("id", person.id).map())); + Assertions.assertEquals(0, personDao.find("").list().size()); + + person = makeSavedPersonDao(); + dogDao.deleteAll(); + Assertions.assertEquals(1, personDao.find("").list().size()); + Assertions.assertEquals(1, personDao.delete("#Person.deleteById", Parameters.with("id", person.id))); + Assertions.assertEquals(0, personDao.find("").list().size()); + + person = makeSavedPersonDao(); + dogDao.deleteAll(); + Assertions.assertEquals(1, personDao.find("").list().size()); + Assertions.assertEquals(1, personDao.delete("#Person.deleteById.ordinal", person.id)); + Assertions.assertEquals(0, personDao.find("").list().size()); + + person = makeSavedPerson(); + //empty query persons = personDao.find("").list(); Assertions.assertEquals(1, persons.size()); diff --git a/integration-tests/hibernate-reactive-panache/src/main/java/io/quarkus/it/panache/reactive/TestEndpoint.java b/integration-tests/hibernate-reactive-panache/src/main/java/io/quarkus/it/panache/reactive/TestEndpoint.java index 31adbc7737863..90ef071ce4f21 100644 --- a/integration-tests/hibernate-reactive-panache/src/main/java/io/quarkus/it/panache/reactive/TestEndpoint.java +++ b/integration-tests/hibernate-reactive-panache/src/main/java/io/quarkus/it/panache/reactive/TestEndpoint.java @@ -181,6 +181,9 @@ public Uni testModel() { }).flatMap(v -> assertThrows(IllegalArgumentException.class, () -> Person.list("#Person.getByName", Sort.by("name"), Parameters.with("name", "stef")), "Should have thrown sort exception")) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> Person.list("Person.getByName", Parameters.with("name", "stef")), + "Should have thrown helpful exception")) .flatMap(v -> NamedQueryEntity.list("#NamedQueryMappedSuperClass.getAll")) .flatMap(v -> NamedQueryEntity.list("#NamedQueryEntity.getAll")) .flatMap(v -> NamedQueryWith2QueriesEntity.list("#NamedQueryWith2QueriesEntity.getAll1")) @@ -213,7 +216,119 @@ public Uni testModel() { Assertions.assertEquals(0, count); return makeSavedPerson(); - }); + }) + .flatMap(v -> Person.count("#Person.countAll") + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.count("#Person.countByName", Parameters.with("name", "stef").map()); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.count("#Person.countByName", Parameters.with("name", "stef")); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.count("#Person.countByName.ordinal", "stef"); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Uni.createFrom().voidItem(); + })) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> Person.count("Person.countAll"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> Person.update("#Person.updateAllNames", Parameters.with("name", "stef2").map()) + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + }).flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.update("#Person.updateAllNames", Parameters.with("name", "stef3")); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + }).flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.update("#Person.updateNameById", + Parameters.with("name", "stef2").and("id", ((Person) persons.get(0)).id).map()); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + }).flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.update("#Person.updateNameById", + Parameters.with("name", "stef3").and("id", ((Person) persons.get(0)).id)); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + }).flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.update("#Person.updateNameById.ordinal", "stef", + ((Person) persons.get(0)).id); + }).flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("#Person.getByName", Parameters.with("name", "stef")).list(); + }).flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Uni.createFrom().voidItem(); + })) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> Person.update("Person.updateAllNames"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> Dog.deleteAll() + .flatMap(v -> Person.delete("#Person.deleteAll")) + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("").list(); + }) + .flatMap(persons -> { + Assertions.assertEquals(0, persons.size()); + return Uni.createFrom().voidItem(); + })) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> Person.delete("Person.deleteAll"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() + .flatMap(v -> Person.find("").list()) + .flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.delete("#Person.deleteById", + Parameters.with("id", personToDelete.id).map()); + }) + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("").list(); + }) + .flatMap(persons -> { + Assertions.assertEquals(0, persons.size()); + return Uni.createFrom().voidItem(); + }))) + .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() + .flatMap(v -> Person.find("").list()) + .flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.delete("#Person.deleteById", Parameters.with("id", personToDelete.id)); + }) + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("").list(); + }) + .flatMap(persons -> { + Assertions.assertEquals(0, persons.size()); + return Uni.createFrom().voidItem(); + }))) + .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() + .flatMap(v -> Person.find("").list()) + .flatMap(persons -> { + Assertions.assertEquals(1, persons.size()); + return Person.delete("#Person.deleteById.ordinal", personToDelete.id); + }) + .flatMap(count -> { + Assertions.assertEquals(1, count); + return Person.find("").list(); + }) + .flatMap(persons -> { + Assertions.assertEquals(0, persons.size()); + return makeSavedPersonDao(); + }))); + }).flatMap(person -> { return Person.count() @@ -858,6 +973,9 @@ public Uni testModelDao() { }).flatMap(v -> assertThrows(IllegalArgumentException.class, () -> personDao.list("#Person.getByName", Sort.by("name"), Parameters.with("name", "stef")), "Should have thrown sort exception")) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> personDao.list("Person.getByName", Parameters.with("name", "stef")), + "Should have thrown helpful exception")) .flatMap(v -> namedQueryRepository.list("#NamedQueryMappedSuperClass.getAll")) .flatMap(v -> namedQueryRepository.list("#NamedQueryEntity.getAll")) .flatMap(v -> namedQueryWith2QueriesRepository.list("#NamedQueryWith2QueriesEntity.getAll1")) @@ -892,103 +1010,113 @@ public Uni testModelDao() { return makeSavedPersonDao(); }) - .flatMap(v -> Person.count("#Person.countAll") + .flatMap(v -> personDao.count("#Person.countAll") .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.count("#Person.countByName", Parameters.with("name", "stef").map()); + return personDao.count("#Person.countByName", Parameters.with("name", "stef").map()); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.count("#Person.countByName", Parameters.with("name", "stef")); + return personDao.count("#Person.countByName", Parameters.with("name", "stef")); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.count("#Person.countByName.ordinal", "stef"); + return personDao.count("#Person.countByName.ordinal", "stef"); }).flatMap(count -> { Assertions.assertEquals(1, count); return Uni.createFrom().voidItem(); })) - .flatMap(voidUni -> Person.update("#Person.updateAllNames", Parameters.with("name", "stef2").map()) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> personDao.count("Person.countAll"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> personDao + .update("#Person.updateAllNames", Parameters.with("name", "stef2").map()) .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + return personDao.find("#Person.getByName", Parameters.with("name", "stef2")).list(); }).flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.update("#Person.updateAllNames", Parameters.with("name", "stef3")); + return personDao.update("#Person.updateAllNames", Parameters.with("name", "stef3")); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + return personDao.find("#Person.getByName", Parameters.with("name", "stef3")).list(); }).flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.update("#Person.updateNameById", + return personDao.update("#Person.updateNameById", Parameters.with("name", "stef2").and("id", ((Person) persons.get(0)).id).map()); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("#Person.getByName", Parameters.with("name", "stef2")).list(); + return personDao.find("#Person.getByName", Parameters.with("name", "stef2")).list(); }).flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.update("#Person.updateNameById", + return personDao.update("#Person.updateNameById", Parameters.with("name", "stef3").and("id", ((Person) persons.get(0)).id)); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("#Person.getByName", Parameters.with("name", "stef3")).list(); + return personDao.find("#Person.getByName", Parameters.with("name", "stef3")).list(); }).flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.update("#Person.updateNameById.ordinal", "stef", + return personDao.update("#Person.updateNameById.ordinal", "stef", ((Person) persons.get(0)).id); }).flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("#Person.getByName", Parameters.with("name", "stef")).list(); + return personDao.find("#Person.getByName", Parameters.with("name", "stef")).list(); }).flatMap(persons -> { Assertions.assertEquals(1, persons.size()); return Uni.createFrom().voidItem(); })) - .flatMap(voidUni -> Dog.deleteAll() - .flatMap(v -> Person.delete("#Person.deleteAll")) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> personDao.update("Person.updateAllNames"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> dogDao.deleteAll() + .flatMap(v -> personDao.delete("#Person.deleteAll")) .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("").list(); + return personDao.find("").list(); }) .flatMap(persons -> { Assertions.assertEquals(0, persons.size()); return Uni.createFrom().voidItem(); })) - .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() - .flatMap(v -> Person.find("").list()) + .flatMap(v -> assertThrows(PanacheQueryException.class, + () -> personDao.delete("Person.deleteAll"), + "Should have thrown helpful exception")) + .flatMap(voidUni -> makeSavedPersonDao().flatMap(personToDelete -> dogDao.deleteAll() + .flatMap(v -> personDao.find("").list()) .flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.delete("#Person.deleteById", + return personDao.delete("#Person.deleteById", Parameters.with("id", personToDelete.id).map()); }) .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("").list(); + return personDao.find("").list(); }) .flatMap(persons -> { Assertions.assertEquals(0, persons.size()); return Uni.createFrom().voidItem(); }))) - .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() - .flatMap(v -> Person.find("").list()) + .flatMap(voidUni -> makeSavedPersonDao().flatMap(personToDelete -> dogDao.deleteAll() + .flatMap(v -> personDao.find("").list()) .flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.delete("#Person.deleteById", Parameters.with("id", personToDelete.id)); + return personDao.delete("#Person.deleteById", Parameters.with("id", personToDelete.id)); }) .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("").list(); + return personDao.find("").list(); }) .flatMap(persons -> { Assertions.assertEquals(0, persons.size()); return Uni.createFrom().voidItem(); }))) - .flatMap(voidUni -> makeSavedPerson().flatMap(personToDelete -> Dog.deleteAll() - .flatMap(v -> Person.find("").list()) + .flatMap(voidUni -> makeSavedPersonDao().flatMap(personToDelete -> dogDao.deleteAll() + .flatMap(v -> personDao.find("").list()) .flatMap(persons -> { Assertions.assertEquals(1, persons.size()); - return Person.delete("#Person.deleteById.ordinal", personToDelete.id); + return personDao.delete("#Person.deleteById.ordinal", personToDelete.id); }) .flatMap(count -> { Assertions.assertEquals(1, count); - return Person.find("").list(); + return personDao.find("").list(); }) .flatMap(persons -> { Assertions.assertEquals(0, persons.size());