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 <[email protected]> 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 {}
