You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2026/03/03 23:27:18 UTC
(grails-core) 11/24: test OrderByClauseBuilder
This is an automated email from the ASF dual-hosted git repository.
borinquenkid pushed a commit to branch 8.0.x-hibernate7-dev
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 4b7a1796415dfecec49c2f326e7694d7b3904f26
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Tue Mar 3 08:33:01 2026 -0600
test OrderByClauseBuilder
---
.../secondpass/CollectionSecondPassBinder.java | 4 +-
.../domainbinding/OrderByClauseBuilderSpec.groovy | 230 ++++++++++-----------
2 files changed, 113 insertions(+), 121 deletions(-)
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java
index 9b54553ca5..6b705fa4d8 100644
--- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java
@@ -186,8 +186,8 @@ public class CollectionSecondPassBinder {
bindManyToManyElement(manyToMany, collection);
} else if (property.isBidirectionalOneToManyMap() && property.isBidirectional()) {
bindBidirectionalMapElement(property, collection);
- } else if (property.isUnidirectionalOneToMany()) {
- unidirectionalOneToManyBinder.bind((HibernateOneToManyProperty) property, collection);
+ } else if (property instanceof HibernateOneToManyProperty oneToManyProperty && oneToManyProperty.isUnidirectionalOneToMany()) {
+ unidirectionalOneToManyBinder.bind(oneToManyProperty, collection);
} else if (property.supportsJoinColumnMapping()) {
collectionWithJoinTableBinder.bindCollectionWithJoinTable(property, mappings, collection);
}
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/OrderByClauseBuilderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/OrderByClauseBuilderSpec.groovy
index 603681fe1c..6b27f7746b 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/OrderByClauseBuilderSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/OrderByClauseBuilderSpec.groovy
@@ -1,10 +1,17 @@
package org.grails.orm.hibernate.cfg.domainbinding
-import grails.gorm.annotation.Entity
import grails.gorm.specs.HibernateGormDatastoreSpec
import org.grails.datastore.mapping.model.DatastoreConfigurationException
-import org.hibernate.mapping.PersistentClass
+import org.hibernate.mapping.BasicValue
+import org.hibernate.mapping.Column
+import org.hibernate.mapping.Component
+import org.hibernate.mapping.JoinedSubclass
+import org.hibernate.mapping.Property
+import org.hibernate.mapping.RootClass
+import org.hibernate.mapping.SingleTableSubclass
+import org.hibernate.mapping.Table
import spock.lang.Subject
+import spock.lang.Unroll
import org.grails.orm.hibernate.cfg.domainbinding.util.OrderByClauseBuilder
@@ -13,159 +20,144 @@ class OrderByClauseBuilderSpec extends HibernateGormDatastoreSpec {
@Subject
OrderByClauseBuilder builder = new OrderByClauseBuilder()
- void setupSpec() {
- manager.addAllDomainClasses([OrderTest, SubOrderTest, OrderWithComponent])
+ private RootClass entityClass
+ private RootClass componentEntityClass
+
+ def setup() {
+ def ctx = getGrailsDomainBinder().getMetadataBuildingContext()
+ def table = new Table("test", "order_entity")
+
+ entityClass = new RootClass(ctx)
+ entityClass.setEntityName("OrderEntity")
+ entityClass.setTable(table)
+ entityClass.setIdentifier(basicValue(ctx, table, "id"))
+ entityClass.addProperty(simpleProperty(ctx, table, "name", "name"))
+ entityClass.addProperty(simpleProperty(ctx, table, "age", "age"))
+ entityClass.addProperty(simpleProperty(ctx, table, "other", "other_column"))
+
+ def compTable = new Table("test", "comp_entity")
+ componentEntityClass = new RootClass(ctx)
+ componentEntityClass.setEntityName("CompEntity")
+ componentEntityClass.setTable(compTable)
+ componentEntityClass.setIdentifier(basicValue(ctx, compTable, "id"))
+
+ def comp = new Component(ctx, compTable, componentEntityClass)
+ comp.addProperty(simpleProperty(ctx, compTable, "c1", "comp_c1"))
+ comp.addProperty(simpleProperty(ctx, compTable, "c2", "comp_c2"))
+ def compProp = new Property()
+ compProp.setName("comp")
+ compProp.setValue(comp)
+ componentEntityClass.addProperty(compProp)
}
- void "test buildOrderByClause with empty string (default to id)"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("", pc, "role", "asc")
-
- then:
- result == "id asc"
+ void "null hqlOrderBy returns null"() {
+ expect:
+ builder.buildOrderByClause(null, entityClass, "role", "asc") == null
}
- void "test buildOrderByClause with single property"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("name", pc, "role", "asc")
-
- then:
- result == "name asc"
+ void "empty hqlOrderBy returns identifier column with asc"() {
+ expect:
+ builder.buildOrderByClause("", entityClass, "role", "asc") == "id asc"
}
- void "test buildOrderByClause with property and explicit order"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("name desc", pc, "role", "asc")
-
- then:
- result == "name desc"
+ @Unroll
+ void "single property '#hql' with defaultOrder '#defaultOrder' returns '#expected'"() {
+ expect:
+ builder.buildOrderByClause(hql, entityClass, "role", defaultOrder) == expected
+
+ where:
+ hql | defaultOrder | expected
+ "name" | "asc" | "name asc"
+ "name" | "desc" | "name desc"
+ "name asc" | "desc" | "name asc"
+ "name desc" | "asc" | "name desc"
+ "name ASC" | "desc" | "name asc"
+ "name DESC" | "asc" | "name desc"
}
- void "test buildOrderByClause with multiple properties"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("name, age desc", pc, "role", "asc")
-
- then:
- result == "name asc, age desc"
+ void "custom column name is used in order clause"() {
+ expect:
+ builder.buildOrderByClause("other", entityClass, "role", "asc") == "other_column asc"
}
- void "test buildOrderByClause with mapped column name"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("other", pc, "role", "asc")
-
- then:
- result == "other_column asc"
+ void "multiple properties with mixed directions"() {
+ expect:
+ builder.buildOrderByClause("name, age desc", entityClass, "role", "asc") == "name asc, age desc"
}
- void "test buildOrderByClause with null string"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause(null, pc, "role", "asc")
-
- then:
- result == null
+ void "component property expands to all its columns"() {
+ expect:
+ builder.buildOrderByClause("comp", componentEntityClass, "role", "asc") == "comp_c1 asc, comp_c2 asc"
}
- void "test buildOrderByClause with non-existent property"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
+ void "non-existent property throws DatastoreConfigurationException"() {
when:
- builder.buildOrderByClause("foo", pc, "role", "asc")
+ builder.buildOrderByClause("nonExistent", entityClass, "role", "asc")
then:
- thrown(DatastoreConfigurationException)
+ def ex = thrown(DatastoreConfigurationException)
+ ex.message.contains("OrderEntity.nonExistent")
}
- void "test buildOrderByClause with invalid sort clause"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
+ void "double direction token throws DatastoreConfigurationException"() {
when:
- // Double ordering keyword should fail
- builder.buildOrderByClause("name asc desc", pc, "role", "asc")
+ builder.buildOrderByClause("name asc desc", entityClass, "role", "asc")
then:
thrown(DatastoreConfigurationException)
}
- void "test buildOrderByClause with different defaultOrder"() {
+ void "inherited property from parent in joined subclass receives table prefix"() {
given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderTest.name)
-
- when:
- String result = builder.buildOrderByClause("name", pc, "role", "desc")
-
- then:
- result == "name desc"
- }
+ def ctx = getGrailsDomainBinder().getMetadataBuildingContext()
+ def subTable = new Table("test", "sub_entity")
+ def sub = new JoinedSubclass(entityClass, ctx)
+ sub.setEntityName("SubEntity")
+ sub.setTable(subTable)
+ sub.addProperty(simpleProperty(ctx, subTable, "extra", "extra_col"))
- void "test buildOrderByClause with multiple columns"() {
- given:
- PersistentClass pc = datastore.metadata.getEntityBinding(OrderWithComponent.name)
+ expect: "property from root table gets no prefix when sorting on root class"
+ builder.buildOrderByClause("name", entityClass, "role", "asc") == "name asc"
- when:
- String result = builder.buildOrderByClause("comp", pc, "role", "asc")
+ and: "property from root table gets its table prefix when sorting on the subclass"
+ builder.buildOrderByClause("name", sub, "role", "asc") == "order_entity.name asc"
- then:
- result == "comp_c1 asc, comp_c2 asc"
+ and: "property from subclass table gets no prefix when sorting on the subclass"
+ builder.buildOrderByClause("extra", sub, "role", "asc") == "extra_col asc"
}
- void "test buildOrderByClause with table prefix for inherited property"() {
+ void "single-table subclass property is sorted without table prefix"() {
given:
- PersistentClass pc = datastore.metadata.getEntityBinding(SubOrderTest.name)
-
- when:
- // 'name' is in the base table 'order_test', 'subProperty' is in 'sub_order_test'
- String result = builder.buildOrderByClause("name, subProperty", pc, "role", "asc")
-
- then:
- // In GORM TPH is default, so no table prefix
- result == "name asc, sub_property asc"
+ def ctx = getGrailsDomainBinder().getMetadataBuildingContext()
+ entityClass.setClassName("org.grails.orm.hibernate.cfg.domainbinding.ParentEntity")
+ def sub = new SingleTableSubclass(entityClass, ctx)
+ sub.setEntityName("ChildEntity")
+ sub.setClassName("org.grails.orm.hibernate.cfg.domainbinding.ChildEntity")
+ sub.addProperty(simpleProperty(ctx, entityClass.getTable(), "childProp", "child_prop"))
+
+ expect: "parent property has no prefix on the subclass"
+ builder.buildOrderByClause("name", sub, "role", "asc") == "name asc"
+
+ and: "subclass-own property has no prefix"
+ builder.buildOrderByClause("childProp", sub, "role", "asc") == "child_prop asc"
}
-}
-@Entity
-class OrderTest {
- String name
- Integer age
- String other
+ // ---- helpers --------------------------------------------------------
- static mapping = {
- other column: 'other_column'
+ private static BasicValue basicValue(ctx, Table table, String columnName) {
+ def v = new BasicValue(ctx, table)
+ v.addColumn(new Column(columnName))
+ v
}
-}
-
-@Entity
-class SubOrderTest extends OrderTest {
- String subProperty
-}
-@Entity
-class OrderWithComponent {
- Long id
- TestComponent comp
- static embedded = ['comp']
+ private static Property simpleProperty(ctx, Table table, String name, String columnName) {
+ def prop = new Property()
+ prop.setName(name)
+ prop.setValue(basicValue(ctx, table, columnName))
+ prop
+ }
}
-class TestComponent {
- String c1
- String c2
-}
+// Minimal classes needed for mapped-class assignments in the STI test
+class ParentEntity {}
+class ChildEntity extends ParentEntity {}