This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch 8.0.x-hibernate7 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 137181a040221ce8431e507ff04735d85acddf06 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Feb 8 16:22:10 2026 -0600 changed return type of HibernateToManyProperty.getHibernateAssociatedEntity --- .../hibernate/cfg/HibernateManyToManyProperty.java | 2 +- .../hibernate/cfg/HibernateManyToOneProperty.java | 2 +- .../hibernate/cfg/HibernateOneToManyProperty.java | 2 +- .../hibernate/cfg/HibernateOneToOneProperty.java | 2 +- .../orm/hibernate/cfg/HibernateToManyProperty.java | 6 +- .../domainbinding/DefaultColumnNameFetcher.java | 4 +- .../cfg/domainbinding/NamingStrategyWrapper.java | 6 +- .../cfg/domainbinding/TableForManyCalculator.java | 24 ++-- .../secondpass/CollectionSecondPassBinder.java | 12 +- .../secondpass/ListSecondPassBinder.java | 2 +- ...CompositeIdentifierToManyToOneBinderSpec.groovy | 7 +- .../DefaultColumnNameFetcherSpec.groovy | 2 +- .../domainbinding/NamingStrategyWrapperSpec.groovy | 10 +- .../TableForManyCalculatorSpec.groovy | 145 ++++++++++++++------- 14 files changed, 140 insertions(+), 86 deletions(-) diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToManyProperty.java index 3f2e278ef2..23be1ed5c2 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToManyProperty.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToManyProperty.java @@ -15,7 +15,7 @@ public class HibernateManyToManyProperty extends ManyToManyWithMapping<PropertyC } @Override - public GrailsHibernatePersistentEntity getAssociatedEntity() { + public GrailsHibernatePersistentEntity getHibernateAssociatedEntity() { return (GrailsHibernatePersistentEntity) super.getAssociatedEntity(); } } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToOneProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToOneProperty.java index 0bad6f60b4..eae9e87e7a 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToOneProperty.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateManyToOneProperty.java @@ -15,7 +15,7 @@ public class HibernateManyToOneProperty extends ManyToOneWithMapping<PropertyCon } @Override - public GrailsHibernatePersistentEntity getAssociatedEntity() { + public GrailsHibernatePersistentEntity getHibernateAssociatedEntity() { return (GrailsHibernatePersistentEntity) super.getAssociatedEntity(); } } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToManyProperty.java index 63a9cf1412..f28114c17b 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToManyProperty.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToManyProperty.java @@ -15,7 +15,7 @@ public class HibernateOneToManyProperty extends OneToManyWithMapping<PropertyCon } @Override - public GrailsHibernatePersistentEntity getAssociatedEntity() { + public GrailsHibernatePersistentEntity getHibernateAssociatedEntity() { return (GrailsHibernatePersistentEntity) super.getAssociatedEntity(); } } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToOneProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToOneProperty.java index 347799452c..7b9610718b 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToOneProperty.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateOneToOneProperty.java @@ -15,7 +15,7 @@ public class HibernateOneToOneProperty extends OneToOneWithMapping<PropertyConfi } @Override - public GrailsHibernatePersistentEntity getAssociatedEntity() { + public GrailsHibernatePersistentEntity getHibernateAssociatedEntity() { return (GrailsHibernatePersistentEntity) super.getAssociatedEntity(); } } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateToManyProperty.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateToManyProperty.java index 4b183322b8..bb3b02f279 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateToManyProperty.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateToManyProperty.java @@ -20,15 +20,15 @@ public interface HibernateToManyProperty extends GrailsHibernatePersistentProper return ((Association) this).isBidirectional(); } - default Association getInverseSide() { - return ((Association) this).getInverseSide(); + default HibernateToManyProperty getHibernateInverseSide() { + return (HibernateToManyProperty)((Association) this).getInverseSide(); } default boolean isCircular() { return ((Association) this).isCircular(); } - default GrailsHibernatePersistentEntity getAssociatedEntity() { + default GrailsHibernatePersistentEntity getHibernateAssociatedEntity() { return (GrailsHibernatePersistentEntity) ((Association) this).getAssociatedEntity(); } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java index 97c33e5c63..121b43ada9 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java @@ -44,12 +44,12 @@ public class DefaultColumnNameFetcher { } if (!association.isBidirectional() && association instanceof org.grails.datastore.mapping.model.types.OneToMany) { - String prefix = namingStrategyWrapper.resolveTableName(property.getOwner().getName().replace('.', '_')); + String prefix = namingStrategyWrapper.resolveTableName(property.getOwner().getJavaClass().getSimpleName()); return backticksRemover.apply(prefix) + UNDERSCORE + backticksRemover.apply(columnName) + FOREIGN_KEY_SUFFIX; } if (property.isInherited() && property.isBidirectionalManyToOne()) { - return namingStrategyWrapper.resolveColumnName(property.getOwner().getName()) + '_' + columnName + FOREIGN_KEY_SUFFIX; + return namingStrategyWrapper.resolveColumnName(property.getOwner().getJavaClass().getSimpleName()) + '_' + columnName + FOREIGN_KEY_SUFFIX; } return columnName + FOREIGN_KEY_SUFFIX; diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java index 1f3130ea18..79fa59be8f 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java @@ -37,27 +37,25 @@ public class NamingStrategyWrapper implements PersistentEntityNamingStrategy { @Override public String resolveColumnName(String logicalName) { return Optional.ofNullable(logicalName) - .map(name -> name.replace('.', '_')) .flatMap(name -> // Safely handle a null return from the strategy by wrapping it in an Optional. Optional.ofNullable(namingStrategy.toPhysicalColumnName(toIdentifier(name), jdbcEnvironment)) ) .map(Identifier::getText) // Per Hibernate contract, if the strategy returns null, use the original logical name. - .orElseGet(() -> logicalName != null ? logicalName.replace('.', '_') : null); + .orElse(logicalName); } @Override public String resolveTableName(String logicalName) { return Optional.ofNullable(logicalName) - .map(name -> name.replace('.', '_')) .flatMap(name -> // Safely handle a null return from the strategy. Optional.ofNullable(namingStrategy.toPhysicalTableName(toIdentifier(name), jdbcEnvironment)) ) .map(Identifier::getText) // Per Hibernate contract, if the strategy returns null, use the original logical name. - .orElseGet(() -> logicalName != null ? logicalName.replace('.', '_') : null); + .orElse(logicalName); } @Override diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculator.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculator.java index 695d1ff65e..add708ed82 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculator.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculator.java @@ -5,10 +5,11 @@ import java.util.Map; import org.hibernate.MappingException; import org.grails.datastore.mapping.model.PersistentEntity; +import org.grails.datastore.mapping.model.types.Association; import org.grails.datastore.mapping.model.types.Basic; import org.grails.datastore.mapping.model.types.ManyToMany; import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity; -import org.grails.orm.hibernate.cfg.HibernateToManyProperty; +import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty; import org.grails.orm.hibernate.cfg.JoinTable; import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy; import org.grails.orm.hibernate.cfg.PropertyConfig; @@ -46,9 +47,8 @@ public class TableForManyCalculator { * the relationship has to "own" the relationship so that there is not a situation * where you have two mapping tables for left_right and right_left */ - public String calculateTableForMany(HibernateToManyProperty property) { + public String calculateTableForMany(GrailsHibernatePersistentProperty property) { String propertyColumnName = namingStrategy.resolveColumnName(property.getName()); - //fix for GRAILS-5895 PropertyConfig config = property.getMappedForm(); JoinTable jt = config.getJoinTable(); boolean hasJoinTableMapping = jt != null && jt.getName() != null; @@ -60,27 +60,29 @@ public class TableForManyCalculator { return jt.getName(); } return backticksRemover.apply(left) + UNDERSCORE + backticksRemover.apply(propertyColumnName); - } - - if (property instanceof Basic) { + } else if (property instanceof Basic) { if (hasJoinTableMapping) { return jt.getName(); } return backticksRemover.apply(left) + UNDERSCORE + backticksRemover.apply(propertyColumnName); } - if (property.getAssociatedEntity() == null) { - throw new MappingException("Expected an entity to be associated with the association (" + property + ") and none was found. "); + // Only proceed with association logic if it's an actual Association and has an associated entity + if (!(property instanceof Association association)) { + throw new MappingException("Property [" + property.getName() + "] is not an association and is not a basic type for table calculation."); } - GrailsHibernatePersistentEntity domainClass = property.getAssociatedEntity(); + GrailsHibernatePersistentEntity domainClass = (GrailsHibernatePersistentEntity) association.getAssociatedEntity(); + if (domainClass == null) { + throw new MappingException("Expected an entity to be associated with the association (" + property + ") and none was found. "); + } String right = tableNameFetcher.getTableName(domainClass); if (property instanceof ManyToMany property1) { if (hasJoinTableMapping) { return jt.getName(); } - if (property.isOwningSide()) { + if (association.isOwningSide()) { return backticksRemover.apply(left) + UNDERSCORE + backticksRemover.apply(propertyColumnName); } String s2 = namingStrategy.resolveColumnName(property1.getInversePropertyName()); @@ -96,7 +98,7 @@ public class TableForManyCalculator { return backticksRemover.apply(left) + UNDERSCORE + backticksRemover.apply(right); } - if (property.isOwningSide()) { + if (association.isOwningSide()) { return backticksRemover.apply(left) + UNDERSCORE + backticksRemover.apply(right); } return backticksRemover.apply(right) + UNDERSCORE + backticksRemover.apply(left); 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 383f1a07bb..e35baa073b 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 @@ -67,7 +67,7 @@ public class CollectionSecondPassBinder { PropertyConfig propConfig = property.getMappedForm(); - GrailsHibernatePersistentEntity referenced = property.getAssociatedEntity(); + GrailsHibernatePersistentEntity referenced = property.getHibernateAssociatedEntity(); if (StringUtils.hasText(propConfig.getSort())) { if (!property.isBidirectional() && (property instanceof org.grails.datastore.mapping.model.types.OneToMany)) { throw new DatastoreConfigurationException("Default sort for associations ["+property.getOwner().getName()+"->" + property.getName() + @@ -156,7 +156,7 @@ public class CollectionSecondPassBinder { // link a bidirectional relationship if (property.isBidirectional()) { - GrailsHibernatePersistentProperty otherSide = (GrailsHibernatePersistentProperty) property.getInverseSide(); + var otherSide = property.getHibernateInverseSide(); if ((otherSide instanceof org.grails.datastore.mapping.model.types.ToOne) && property.shouldBindWithForeignKey()) { @@ -195,7 +195,7 @@ public class CollectionSecondPassBinder { // if we have a many-to-many if (isManyToMany || property.isBidirectionalOneToManyMap()) { - PersistentProperty otherSide = property.getInverseSide(); + var otherSide = property.getHibernateInverseSide(); if (property.isBidirectional()) { if (LOG.isDebugEnabled()) @@ -310,7 +310,7 @@ public class CollectionSecondPassBinder { } } } else { - final GrailsHibernatePersistentEntity domainClass = property.getAssociatedEntity(); + final GrailsHibernatePersistentEntity domainClass = property.getHibernateAssociatedEntity(); Mapping m = null; if (domainClass != null) { @@ -325,7 +325,7 @@ public class CollectionSecondPassBinder { columnName = joinColumnMappingOptional.get().getName(); } else { - var decapitalize = domainClass.getName(); + var decapitalize = domainClass.getJavaClass().getSimpleName(); columnName = namingStrategy.resolveColumnName(decapitalize) + FOREIGN_KEY_SUFFIX; } @@ -352,7 +352,7 @@ public class CollectionSecondPassBinder { } // set referenced entity - manyToOne.setReferencedEntityName(property.getAssociatedEntity().getName()); + manyToOne.setReferencedEntityName(property.getHibernateAssociatedEntity().getName()); } private void bindManyToMany(Association property, ManyToOne element, diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/ListSecondPassBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/ListSecondPassBinder.java index 9bfe9b9c95..56fcfbbc08 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/ListSecondPassBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/ListSecondPassBinder.java @@ -80,7 +80,7 @@ public class ListSecondPassBinder { PersistentClass referenced = mappings.getEntityBinding(entityName); - boolean compositeIdProperty = property.getInverseSide().isCompositeIdProperty(); + boolean compositeIdProperty = property.getHibernateInverseSide().isCompositeIdProperty(); if (!compositeIdProperty) { Backref prop = new Backref(); final PersistentEntity owner = property.getOwner(); diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdentifierToManyToOneBinderSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdentifierToManyToOneBinderSpec.groovy index aa5d5cd012..5016f46d5b 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdentifierToManyToOneBinderSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/CompositeIdentifierToManyToOneBinderSpec.groovy @@ -5,6 +5,7 @@ import org.grails.datastore.mapping.model.PersistentProperty import org.grails.datastore.mapping.model.types.ToOne import org.grails.orm.hibernate.cfg.ColumnConfig import org.grails.orm.hibernate.cfg.CompositeIdentity +import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy import org.grails.orm.hibernate.cfg.PropertyConfig @@ -29,7 +30,7 @@ class CompositeIdentifierToManyToOneBinderSpec extends Specification { // 2. Set up stubs for the method arguments def association = Stub(ToOne, additionalInterfaces: [GrailsHibernatePersistentProperty]) def value = Stub(SimpleValue) - def refDomainClass = Stub(PersistentEntity) + def refDomainClass = Stub(PersistentEntity, additionalInterfaces: [GrailsHibernatePersistentEntity]) def path = "/test" // Use a real CompositeIdentity object to avoid final method mocking issues @@ -47,7 +48,7 @@ class CompositeIdentifierToManyToOneBinderSpec extends Specification { refDomainClass.getPropertyByName("nestedEntity") >> nestedEntityProp nestedEntityProp.name >> "nestedEntity" - def nestedAssociatedEntity = Stub(PersistentEntity) + def nestedAssociatedEntity = Stub(PersistentEntity, additionalInterfaces: [GrailsHibernatePersistentEntity]) nestedEntityProp.getAssociatedEntity() >> nestedAssociatedEntity def nestedPartA = Stub(PersistentProperty) @@ -95,7 +96,7 @@ class CompositeIdentifierToManyToOneBinderSpec extends Specification { def value = Stub(SimpleValue) def compositeId = new CompositeIdentity() compositeId.setPropertyNames(["prop1", "prop2"] as String[]) - def refDomainClass = Stub(PersistentEntity) + def refDomainClass = Stub(PersistentEntity, additionalInterfaces: [GrailsHibernatePersistentEntity]) def path = "/test" // 3. Set up the "match" condition diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy index 43b9a496a4..3bb8ae5dbf 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy @@ -36,7 +36,7 @@ class DefaultColumnNameFetcherSpec extends HibernateGormDatastoreSpec { where: description | entityClass | propertyName | expectedColumnName "a simple property" | DefaultColumnNameFetcherSpecEntity | "name" | "name" - "a unidirectional one-to-many" | DefaultColumnNameFetcherSpecUnidirectionalOwner | "children" | "org_grails_orm_hibernate_cfg_domainbinding_default_column_name_fetcher_spec_unidirectional_owner_children_id" + "a unidirectional one-to-many" | DefaultColumnNameFetcherSpecUnidirectionalOwner | "children" | "default_column_name_fetcher_spec_unidirectional_owner_children_id" "a bidirectional many-to-one" | DefaultColumnNameFetcherSpecEntity | "bidirectionalManyToOne" | "bidirectional_many_to_one_id" "a many-to-many" | AManyToManyEntity | "manyToMany" | "amany_to_many_entity_id" "an inherited bidirectional m-t-o" | InheritedEntity | "bidirectionalManyToOne" | "bidirectional_many_to_one_id" diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy index 59b76a4cfd..87358288ec 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy @@ -133,10 +133,9 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { capturedIdentifier.text == decapitalizedOwnerName } - def "should replace dots with underscores for logical column name before passing to wrapped strategy"() { + def "should preserve dots for logical column name before passing to wrapped strategy"() { given: def logicalNameWithDots = "com.example.MyClass.myProperty" - def expectedLogicalNameForStrategy = "com_example_MyClass_myProperty" def expectedPhysicalName = "com_example_my_class_my_property" def capturedIdentifier @@ -150,13 +149,12 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { then: actualResult == expectedPhysicalName - capturedIdentifier.text == expectedLogicalNameForStrategy + capturedIdentifier.text == logicalNameWithDots } - def "should replace dots with underscores for logical table name before passing to wrapped strategy"() { + def "should preserve dots for logical table name before passing to wrapped strategy"() { given: def logicalNameWithDots = "com.example.MyClass" - def expectedLogicalNameForStrategy = "com_example_MyClass" def expectedPhysicalName = "com_example_my_class" def capturedIdentifier @@ -170,7 +168,7 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { then: actualResult == expectedPhysicalName - capturedIdentifier.text == expectedLogicalNameForStrategy + capturedIdentifier.text == logicalNameWithDots } } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy index 143c1a7e28..4807f01920 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableForManyCalculatorSpec.groovy @@ -1,74 +1,129 @@ package org.grails.orm.hibernate.cfg.domainbinding - +import grails.gorm.specs.HibernateGormDatastoreSpec +import grails.persistence.Entity +import org.grails.datastore.mapping.model.types.Association import org.grails.datastore.mapping.model.types.Basic import org.grails.datastore.mapping.model.types.ManyToMany import org.grails.datastore.mapping.model.types.ToMany import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity +import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentProperty +import org.grails.orm.hibernate.cfg.HibernateManyToManyProperty +import org.grails.orm.hibernate.cfg.HibernateOneToManyProperty import org.grails.orm.hibernate.cfg.HibernateToManyProperty import org.grails.orm.hibernate.cfg.JoinTable -import org.grails.orm.hibernate.cfg.Mapping -import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy -import org.grails.orm.hibernate.cfg.PropertyConfig -import spock.lang.Specification + import spock.lang.Unroll -class TableForManyCalculatorSpec extends Specification { +class TableForManyCalculatorSpec extends HibernateGormDatastoreSpec { @Unroll def "Test calculateTableForMany for #scenario"() { given: - def namingStrategy = Stub(PersistentEntityNamingStrategy) - def tableNameFetcher = Stub(TableNameFetcher) - def backticksRemover = Stub(BackticksRemover) - def trimmer = Stub(BackTigsTrimmer) + def namingStrategy = getGrailsDomainBinder().getNamingStrategy() + def tableNameFetcher = new TableNameFetcher(namingStrategy) + def backticksRemover = new BackticksRemover() + def trimmer = new BackTigsTrimmer() def calculator = new TableForManyCalculator(namingStrategy, tableNameFetcher, backticksRemover, trimmer) - GrailsHibernatePersistentEntity ownerEntity = Stub(GrailsHibernatePersistentEntity) - GrailsHibernatePersistentEntity associatedEntity = Stub(GrailsHibernatePersistentEntity) - def config = new PropertyConfig() - if (hasJoinTable) { - config.setJoinTable(new JoinTable(name: "explicit_join_table")) - } + GrailsHibernatePersistentEntity ownerEntityInstance + GrailsHibernatePersistentEntity associatedEntityInstance + GrailsHibernatePersistentProperty propertyToTest - HibernateToManyProperty property = Mock(mockClass, additionalInterfaces: [HibernateToManyProperty]) - property.getType() >> propertyJavaType - property.getOwner() >> ownerEntity - property.getName() >> "myProp" - property.getAssociatedEntity() >> associatedEntity - property.isOwningSide() >> isOwningSide - property.getMappedForm() >> config - property.supportsJoinColumnMapping() >> shouldBindWithJoinColumn - - if (property instanceof ManyToMany) { - ((ManyToMany)property).getInversePropertyName() >> "inverseProp" + // Setup entities and properties based on scenario + switch (scenario) { + case "an owning OneToMany": + ownerEntityInstance = createPersistentEntity(OwningSide) + associatedEntityInstance = createPersistentEntity(AssociatedSide) + propertyToTest = ownerEntityInstance.getPropertyByName("associated") as GrailsHibernatePersistentProperty + break + case "a Basic property": + ownerEntityInstance = createPersistentEntity(BasicCollectionOwner) + propertyToTest = ownerEntityInstance.getPropertyByName("items") as GrailsHibernatePersistentProperty + break + case "a Map property": + ownerEntityInstance = createPersistentEntity(MapCollectionOwner) + propertyToTest = ownerEntityInstance.getPropertyByName("data") as GrailsHibernatePersistentProperty + break + case "an owning ManyToMany": + ownerEntityInstance = createPersistentEntity(OwningSide) + associatedEntityInstance = createPersistentEntity(Tag) + propertyToTest = ownerEntityInstance.getPropertyByName("tags") as GrailsHibernatePersistentProperty + break + case "an inverse ManyToMany": + ownerEntityInstance = createPersistentEntity(Tag) + associatedEntityInstance = createPersistentEntity(OwningSide) + propertyToTest = ownerEntityInstance.getPropertyByName("owners") as GrailsHibernatePersistentProperty + break + case "a ManyToMany with explicit joinTable": + ownerEntityInstance = createPersistentEntity(OwningSide) + associatedEntityInstance = createPersistentEntity(Tag) + propertyToTest = ownerEntityInstance.getPropertyByName("tags") as GrailsHibernatePersistentProperty + propertyToTest.getMappedForm().setJoinTable(new JoinTable(name: "my_custom_join_table")) + break + case "a ToMany with supportsJoinColumnMapping": + ownerEntityInstance = createPersistentEntity(UnidirectionalOwner) + associatedEntityInstance = createPersistentEntity(UnidirectionalItem) + propertyToTest = ownerEntityInstance.getPropertyByName("items") as GrailsHibernatePersistentProperty + break + default: + throw new IllegalArgumentException("Unknown scenario: $scenario") } - ownerEntity.getMappedForm() >> new Mapping() - namingStrategy.resolveColumnName("myProp") >> "my_prop_col" - namingStrategy.resolveColumnName("inverseProp") >> "inverse_prop_col" - tableNameFetcher.getTableName(ownerEntity) >> "owner_table" - tableNameFetcher.getTableName(associatedEntity) >> "associated_table" - - backticksRemover.apply(_) >> { String s -> s } - trimmer.trimBackTigs(_) >> { String s -> s } when: - def result = calculator.calculateTableForMany(property) + def result = calculator.calculateTableForMany(propertyToTest) then: result == expectedTableName where: - scenario | mockClass | propertyJavaType | isOwningSide | hasJoinTable | shouldBindWithJoinColumn | expectedTableName - "a Map property" | ToMany.class | Map | true | false | false | "owner_table_my_prop_col" - "a Basic property" | Basic.class | List | true | false | false | "owner_table_my_prop_col" - "an owning ManyToMany" | ManyToMany.class | Set | true | false | false | "owner_table_my_prop_col" - "an inverse ManyToMany" | ManyToMany.class | Set | false | false | false | "associated_table_inverse_prop_col" - "a ManyToMany with joinTable" | ManyToMany.class | Set | true | true | false | "explicit_join_table" - "a ToMany with joinColumn" | ToMany.class | Set | true | false | true | "owner_table_associated_table" - "an owning ToMany" | ToMany.class | Set | true | false | false | "owner_table_associated_table" - "an inverse ToMany" | ToMany.class | Set | false | false | false | "associated_table_owner_table" + scenario | expectedTableName + + "a Map property" | "map_collection_owner_data" + "a Basic property" | "basic_collection_owner_items" + "an owning OneToMany" | "owning_side_associated_side" + "an owning ManyToMany" | "tag_owners" + "an inverse ManyToMany" | "owning_side_tags" // MappedBy logic ensures single join table + "a ManyToMany with explicit joinTable" | "my_custom_join_table" + "a ToMany with supportsJoinColumnMapping" | "unidirectional_owner_unidirectional_item" } +} + +@Entity +class AssociatedSide { + static belongsTo = [owningSide: OwningSide] +} + +@Entity +class OwningSide { + static hasMany = [associated: AssociatedSide, tags: Tag] // For one-to-many and many-to-many + static mappedBy = [tags: 'owners'] // For many-to-many inverse +} + +@Entity +class BasicCollectionOwner { + List<String> items +} + + +@Entity +class MapCollectionOwner { + Map<String, String> data +} + +@Entity +class Tag { + static hasMany = [owners: OwningSide] +} + +@Entity +class UnidirectionalItem { + // No belongsTo, making it unidirectional +} + +@Entity +class UnidirectionalOwner { + static hasMany = [items: UnidirectionalItem] } \ No newline at end of file
