This is an automated email from the ASF dual-hosted git repository. jamesfredley pushed a commit to branch test/h7-functional-coverage in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 6d0aaa5241b3b771655324baf6f541031baff21e Author: James Fredley <[email protected]> AuthorDate: Thu Jun 11 13:59:13 2026 -0400 Apply Hibernate 7 HQL query settings consistently Assisted-by: Hephaestus:openai/gpt-5.5 --- .../orm/hibernate/query/HqlQueryMethods.java | 37 +++++++++++++++++++--- .../grails/orm/hibernate/query/SelectHqlQuery.java | 4 +-- .../orm/hibernate/query/HqlQueryMethodsSpec.groovy | 33 ++++++++++++++++--- .../orm/hibernate/query/SelectHqlQuerySpec.groovy | 11 +++++++ 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryMethods.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryMethods.java index 3f3559fad2..9d80213d41 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryMethods.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/HqlQueryMethods.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import jakarta.persistence.LockModeType; + public interface HqlQueryMethods { Set<String> INTERNAL_SETTINGS = Set.of( @@ -34,7 +36,8 @@ public interface HqlQueryMethods { HibernateQueryArgument.READ_ONLY.value(), HibernateQueryArgument.FETCH_SIZE.value(), HibernateQueryArgument.MAX.value(), - HibernateQueryArgument.OFFSET.value() + HibernateQueryArgument.OFFSET.value(), + HibernateQueryArgument.LOCK.value() ); default void populateQuerySettings(HqlQueryDelegate d, Map<String, Object> args) { @@ -43,14 +46,40 @@ public interface HqlQueryMethods { d.setQueryFlushMode(GrailsQueryFlushMode.mapToHibernateQueryFlushMode(args.get(HibernateQueryArgument.FLUSH_MODE.value()))); } if (args.containsKey(HibernateQueryArgument.MAX.value())) { - d.setMaxResults((Integer) args.get(HibernateQueryArgument.MAX.value())); + d.setMaxResults(toInteger(args.get(HibernateQueryArgument.MAX.value()))); } if (args.containsKey(HibernateQueryArgument.OFFSET.value())) { - d.setFirstResult((Integer) args.get(HibernateQueryArgument.OFFSET.value())); + d.setFirstResult(toInteger(args.get(HibernateQueryArgument.OFFSET.value()))); + } + if (args.containsKey(HibernateQueryArgument.FETCH_SIZE.value())) { + d.setFetchSize(toInteger(args.get(HibernateQueryArgument.FETCH_SIZE.value()))); + } + if (args.containsKey(HibernateQueryArgument.TIMEOUT.value())) { + d.setTimeout(toInteger(args.get(HibernateQueryArgument.TIMEOUT.value()))); } if (args.containsKey(HibernateQueryArgument.READ_ONLY.value())) { - d.setReadOnly((Boolean) args.get(HibernateQueryArgument.READ_ONLY.value())); + d.setReadOnly(toBoolean(args.get(HibernateQueryArgument.READ_ONLY.value()))); + } + if (toBoolean(args.get(HibernateQueryArgument.LOCK.value()))) { + d.setLockMode(LockModeType.PESSIMISTIC_WRITE); + d.setCacheable(false); + } else if (args.containsKey(HibernateQueryArgument.CACHE.value())) { + d.setCacheable(toBoolean(args.get(HibernateQueryArgument.CACHE.value()))); + } + } + + static int toInteger(Object value) { + if (value instanceof Number number) { + return number.intValue(); + } + return Integer.parseInt(value.toString()); + } + + static boolean toBoolean(Object value) { + if (value instanceof Boolean bool) { + return bool; } + return value != null && Boolean.parseBoolean(value.toString()); } default void populateHints(HqlQueryDelegate d, Map<String, Object> hints) { diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java index eadc7c8071..76f27fcd65 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/query/SelectHqlQuery.java @@ -96,7 +96,7 @@ public class SelectHqlQuery extends Query implements HqlQueryMethods, Serializab return max; } Object m = queryContext.querySettings().get(HibernateQueryArgument.MAX.value()); - return m instanceof Number n ? n.intValue() : -1; + return m == null ? -1 : HqlQueryMethods.toInteger(m); } @Override @@ -105,6 +105,6 @@ public class SelectHqlQuery extends Query implements HqlQueryMethods, Serializab return offset; } Object o = queryContext.querySettings().get(HibernateQueryArgument.OFFSET.value()); - return o instanceof Number n ? n.intValue() : 0; + return o == null ? 0 : HqlQueryMethods.toInteger(o); } } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HqlQueryMethodsSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HqlQueryMethodsSpec.groovy index a6ad612e1d..4dbd386ea0 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HqlQueryMethodsSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/HqlQueryMethodsSpec.groovy @@ -19,6 +19,7 @@ package org.grails.orm.hibernate.query import org.grails.orm.hibernate.query.HibernateQueryArgument +import jakarta.persistence.LockModeType import spock.lang.Specification import org.hibernate.query.QueryFlushMode @@ -64,9 +65,12 @@ class HqlQueryMethodsSpec extends Specification { def delegate = Mock(HqlQueryDelegate) def settings = [ (HibernateQueryArgument.FLUSH_MODE.value()): "COMMIT", - (HibernateQueryArgument.MAX.value()): 10, - (HibernateQueryArgument.OFFSET.value()): 5, - (HibernateQueryArgument.READ_ONLY.value()): true + (HibernateQueryArgument.MAX.value()): '10', + (HibernateQueryArgument.OFFSET.value()): '5', + (HibernateQueryArgument.FETCH_SIZE.value()): '50', + (HibernateQueryArgument.TIMEOUT.value()): '30', + (HibernateQueryArgument.READ_ONLY.value()): 'true', + (HibernateQueryArgument.CACHE.value()): 'true' ] when: @@ -76,7 +80,27 @@ class HqlQueryMethodsSpec extends Specification { 1 * delegate.setQueryFlushMode(QueryFlushMode.NO_FLUSH) 1 * delegate.setMaxResults(10) 1 * delegate.setFirstResult(5) + 1 * delegate.setFetchSize(50) + 1 * delegate.setTimeout(30) 1 * delegate.setReadOnly(true) + 1 * delegate.setCacheable(true) + } + + void "test populateQuerySettings applies lock and disables cache"() { + given: + def delegate = Mock(HqlQueryDelegate) + def settings = [ + (HibernateQueryArgument.LOCK.value()): 'true', + (HibernateQueryArgument.CACHE.value()): 'true' + ] + + when: + queryMethods.populateQuerySettings(delegate, settings) + + then: + 1 * delegate.setLockMode(LockModeType.PESSIMISTIC_WRITE) + 1 * delegate.setCacheable(false) + 0 * delegate.setCacheable(true) } void "test populateParameters with named parameters"() { @@ -96,13 +120,14 @@ class HqlQueryMethodsSpec extends Specification { void "test populateParameters filters internal settings"() { given: def delegate = Mock(HqlQueryDelegate) - def ctx = new HqlQueryContext("hql", Object, [(HibernateQueryArgument.MAX.value()): 10, title: "GORM"], [], [:], [:], false, false) + def ctx = new HqlQueryContext("hql", Object, [(HibernateQueryArgument.MAX.value()): 10, (HibernateQueryArgument.LOCK.value()): true, title: "GORM"], [], [:], [:], false, false) when: HqlQueryMethods.populateParameters(delegate, ctx) then: 0 * delegate.setParameter(HibernateQueryArgument.MAX.value(), _) + 0 * delegate.setParameter(HibernateQueryArgument.LOCK.value(), _) 1 * delegate.setParameter("title", "GORM") } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/SelectHqlQuerySpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/SelectHqlQuerySpec.groovy index 8c947936bf..3642ef198b 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/SelectHqlQuerySpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/query/SelectHqlQuerySpec.groovy @@ -141,6 +141,17 @@ class SelectHqlQuerySpec extends HibernateGormDatastoreSpec { results.size() == 1 } + void "createHqlQuery exposes converted max and offset args"() { + when: + def query = buildHqlQuery("from SelectHqlQuerySpecBook order by title", [:], null, [max: '2', offset: '1']) + def results = query.list() + + then: + query.max == 2 + query.offset == 1 + results.size() == 2 + } + void "createHqlQuery with empty query string defaults to full entity query"() { when: def results = buildHqlQuery("").list()
