HHH-15132 - Improvements for NavigablePath

Begin breaking down "full path"
This commit is contained in:
Steve Ebersole 2022-03-21 14:10:59 -05:00
parent 73153be99d
commit f474449e7d
19 changed files with 190 additions and 67 deletions

View File

@ -667,14 +667,14 @@ public class EntityCollectionPart
NavigablePath path = np.getParent();
// Fast path
if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
return targetKeyPropertyNames.contains( np.getLocalName() )
&& fkDescriptor.getKeyTable().equals( tableExpression );
}
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() );
sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() );
sb.insert( 0, path.getLocalName() );
path = path.getParent();
}
return navigablePath.equals( path )

View File

@ -202,7 +202,7 @@ public class PluralAttributeMappingImpl
// then we say this is bidirectional, given that this is only invoked for model parts of the collection elements
return fkDescriptor.getTargetPart() == modelPart.getForeignKeyDescriptor().getTargetPart();
}
return fetchablePath.getUnaliasedLocalName().endsWith( bidirectionalAttributeName );
return fetchablePath.getLocalName().endsWith( bidirectionalAttributeName );
}
@SuppressWarnings("unused")

View File

@ -748,8 +748,8 @@ public class ToOneAttributeMapping
private Key key;
}
*/
if ( parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|| parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME ) ) {
if ( parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|| parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME ) ) {
// todo (6.0): maybe it's better to have a flag in creation state that marks if we are building a circular fetch domain result already to skip this?
return null;
}
@ -893,9 +893,9 @@ public class ToOneAttributeMapping
parent.getFullPath() = "Mother.biologicalChild"
*/
final NavigablePath grandparentNavigablePath = parentNavigablePath.getParent();
if ( parentNavigablePath.getUnaliasedLocalName().equals( CollectionPart.Nature.ELEMENT.getName() )
if ( parentNavigablePath.getLocalName().equals( CollectionPart.Nature.ELEMENT.getName() )
&& grandparentNavigablePath != null
&& grandparentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName ) ) {
&& grandparentNavigablePath.getLocalName().equals( bidirectionalAttributeName ) ) {
final NavigablePath parentPath = grandparentNavigablePath.getParent();
// This can be null for a collection loader
if ( parentPath == null ) {
@ -915,13 +915,13 @@ public class ToOneAttributeMapping
}
// If we have a parent, we ensure that the parent is the same as the attribute name
else {
return parentPath.getUnaliasedLocalName().equals( navigableRole.getLocalName() );
return parentPath.getLocalName().equals( navigableRole.getLocalName() );
}
}
}
return false;
}
return parentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName );
return parentNavigablePath.getLocalName().equals( bidirectionalAttributeName );
}
public String getBidirectionalAttributeName(){
@ -944,7 +944,7 @@ public class ToOneAttributeMapping
referencedNavigablePath = parentNavigablePath;
hasBidirectionalFetchParent = true;
}
else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) {
else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getLocalName() ) != null ) {
referencedNavigablePath = parentNavigablePath.getParent().getParent();
hasBidirectionalFetchParent = fetchParent instanceof Fetch
&& ( (Fetch) fetchParent ).getFetchParent() instanceof Fetch;
@ -1007,7 +1007,7 @@ public class ToOneAttributeMapping
// So we create a delayed fetch, as we are sure to find the entity in the PC
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final NavigablePath realParent;
if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) {
if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getLocalName() ) != null ) {
realParent = parentNavigablePath.getParent();
}
else {
@ -1386,7 +1386,7 @@ public class ToOneAttributeMapping
break;
}
}
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() ) ) {
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getLocalName() ) ) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
parentTableGroup.getNavigablePath().getParent()
);
@ -1420,14 +1420,14 @@ public class ToOneAttributeMapping
NavigablePath path = np.getParent();
// Fast path
if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
return targetKeyPropertyNames.contains( np.getLocalName() )
&& identifyingColumnsTableExpression.equals( tableExpression );
}
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() );
sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() );
sb.insert( 0, path.getLocalName() );
path = path.getParent();
}
return navigablePath.equals( path )
@ -1542,14 +1542,14 @@ public class ToOneAttributeMapping
NavigablePath path = np.getParent();
// Fast path
if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
return targetKeyPropertyNames.contains( np.getLocalName() )
&& identifyingColumnsTableExpression.equals( tableExpression );
}
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() );
sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() );
sb.insert( 0, path.getLocalName() );
path = path.getParent();
}
return navigablePath.equals( path )

View File

@ -66,7 +66,7 @@ public class FunctionExpression implements OrderingExpression, FunctionRendering
final OrderingExpression orderingExpression = arguments.get( i );
final String subModelPartName;
if ( orderingExpression instanceof DomainPath ) {
final String partName = ( (DomainPath) orderingExpression ).getNavigablePath().getUnaliasedLocalName();
final String partName = ( (DomainPath) orderingExpression ).getNavigablePath().getLocalName();
if ( CollectionPart.Nature.ELEMENT.getName().equals( partName ) ) {
subModelPartName = AbstractDomainPath.ELEMENT_TOKEN;
}

View File

@ -4013,7 +4013,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
SqmPath<?> lhs = pluralAttributePath.getLhs();
final List<String> implicitJoinPaths = new ArrayList<>();
while ( !( lhs instanceof AbstractSqmFrom<?, ?> ) ) {
implicitJoinPaths.add( lhs.getNavigablePath().getUnaliasedLocalName() );
implicitJoinPaths.add( lhs.getNavigablePath().getLocalName() );
lhs = lhs.getLhs();
}
final AbstractSqmFrom<?, ?> correlationBase = (AbstractSqmFrom<?, ?>) lhs;
@ -4022,7 +4022,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
for ( int i = implicitJoinPaths.size() - 1; i >= 0; i-- ) {
joinBase = joinBase.join( implicitJoinPaths.get( i ) );
}
final SqmAttributeJoin<?, ?> collectionJoin = joinBase.join( pluralAttributePath.getNavigablePath().getUnaliasedLocalName() );
final SqmAttributeJoin<?, ?> collectionJoin = joinBase.join( pluralAttributePath.getNavigablePath().getLocalName() );
fromClause.addRoot( correlation.getCorrelatedRoot() );
if ( collectionReferenceCtx == null ) {
final SqmLiteral<Integer> literal = new SqmLiteral<>(

View File

@ -240,7 +240,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
return (X) existing;
}
final SqmFrom<?, ?> sqmFrom = resolveFrom( path.getLhs() ).join( path.getNavigablePath().getUnaliasedLocalName() );
final SqmFrom<?, ?> sqmFrom = resolveFrom( path.getLhs() ).join( path.getNavigablePath().getLocalName() );
register( sqmFrom );
//noinspection unchecked
return (X) sqmFrom;

View File

@ -171,6 +171,6 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getUnaliasedLocalName(), v ) );
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
}
}

View File

@ -151,7 +151,7 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
@Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getUnaliasedLocalName(), v ) );
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
}
@Override

View File

@ -2983,7 +2983,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
prepareReusablePath( path, () -> null );
final NavigablePath navigablePath;
if ( CollectionPart.Nature.fromNameExact( path.getNavigablePath().getUnaliasedLocalName() ) != null ) {
if ( CollectionPart.Nature.fromNameExact( path.getNavigablePath().getLocalName() ) != null ) {
navigablePath = path.getLhs().getLhs().getNavigablePath();
}
else if ( path instanceof SqmTreatedRoot<?, ?> ) {
@ -3648,7 +3648,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
assert parentTableGroup != null;
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) parentTableGroup.getModelPart().findSubPart(
pluralPath.getNavigablePath().getUnaliasedLocalName(),
pluralPath.getNavigablePath().getLocalName(),
null
);
assert pluralAttributeMapping != null;
@ -5344,7 +5344,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
path.getLhs().getNavigablePath()
);
final NavigablePath navigablePath = parentTableGroup.getNavigablePath().append(
path.getNavigablePath().getUnaliasedLocalName(),
path.getNavigablePath().getLocalName(),
Long.toString( System.nanoTime() )
);
final TableGroup tableGroup = new SyntheticVirtualTableGroup(

View File

@ -103,7 +103,7 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
reusablePaths = new HashMap<>();
}
final String relativeName = path.getNavigablePath().getUnaliasedLocalName();
final String relativeName = path.getNavigablePath().getLocalName();
final SqmPath<?> previous = reusablePaths.put( relativeName, path );
if ( previous != null && previous != path ) {

View File

@ -108,7 +108,7 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
final SqmPathRegistry pathRegistry = creationState.getCurrentProcessingState().getPathRegistry();
final String alias = selector.toHqlString();
final NavigablePath navigablePath = getNavigablePath().getParent().append(
getNavigablePath().getUnaliasedLocalName(),
getNavigablePath().getLocalName(),
alias
).append( CollectionPart.Nature.ELEMENT.getName() );
final SqmFrom<?, ?> indexedPath = pathRegistry.findFromByPath( navigablePath );

View File

@ -77,7 +77,7 @@ public class SqmAliasedNodeRef extends AbstractSqmExpression<Integer> {
sb.append( position );
}
else {
sb.append( navigablePath.getUnaliasedLocalName() );
sb.append( navigablePath.getLocalName() );
}
}
}

View File

@ -23,23 +23,28 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper";
private final NavigablePath parent;
private final String fullPath;
private final String unaliasedLocalName;
private final String localName;
private final String alias;
private final String identifierForTableGroup;
private final String fullPath;
public NavigablePath(NavigablePath parent, String navigableName) {
this.parent = parent;
this.alias = null;
// the _identifierMapper is a "hidden property" on entities with composite keys.
// concatenating it will prevent the path from correctly being used to look up
// various things such as criteria paths and fetch profile association paths
if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) {
this.fullPath = parent != null ? parent.getFullPath() : "";
this.unaliasedLocalName = "";
this.localName = "";
this.identifierForTableGroup = parent != null ? parent.getIdentifierForTableGroup() : "";
this.fullPath = parent != null ? parent.getFullPath() : "";
}
else {
this.unaliasedLocalName = navigableName;
this.localName = navigableName;
if ( parent != null ) {
final String parentFullPath = parent.getFullPath();
this.fullPath = StringHelper.isEmpty( parentFullPath )
@ -51,7 +56,7 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
}
else {
this.fullPath = navigableName;
identifierForTableGroup = navigableName;
this.identifierForTableGroup = navigableName;
}
}
}
@ -62,28 +67,32 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public NavigablePath(String rootName, String alias) {
this.parent = null;
this.alias = StringHelper.nullIfEmpty( alias );
this.localName = rootName;
this.identifierForTableGroup = rootName;
this.fullPath = alias == null ? rootName : rootName + "(" + alias + ")";
this.unaliasedLocalName = StringHelper.unqualify( rootName );
identifierForTableGroup = rootName;
}
public NavigablePath(NavigablePath parent, String property, String alias) {
String navigableName = alias == null
alias = StringHelper.nullIfEmpty( alias );
final String navigableName = alias == null
? property
: property + '(' + alias + ')';
this.parent = parent;
this.alias = alias;
// the _identifierMapper is a "hidden property" on entities with composite keys.
// concatenating it will prevent the path from correctly being used to look up
// various things such as criteria paths and fetch profile association paths
if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) {
this.fullPath = parent != null ? parent.getFullPath() : "";
this.unaliasedLocalName = "";
this.localName = "";
identifierForTableGroup = parent != null ? parent.getFullPath() : "";
}
else {
this.unaliasedLocalName = property;
this.localName = property;
if ( parent != null ) {
final String parentFullPath = parent.getFullPath();
this.fullPath = StringHelper.isEmpty( parentFullPath )
@ -107,11 +116,12 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public NavigablePath(
NavigablePath parent,
String fullPath,
String unaliasedLocalName,
String localName,
String identifierForTableGroup) {
this.parent = parent;
this.alias = null;
this.fullPath = fullPath;
this.unaliasedLocalName = unaliasedLocalName;
this.localName = localName;
this.identifierForTableGroup = identifierForTableGroup;
}
@ -140,24 +150,29 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
}
public String getLocalName() {
return parent == null ? fullPath : StringHelper.unqualify( fullPath );
return localName;
}
public String getUnaliasedLocalName() {
return unaliasedLocalName;
public String getAlias() {
return alias;
}
public String getFullPath() {
return fullPath;
public boolean isAliased() {
return alias != null;
}
public String getIdentifierForTableGroup() {
// todo (6.0) : is this `if` really needed? seems this is already handled in constructors
if ( parent == null ) {
return fullPath;
}
return identifierForTableGroup;
}
public String getFullPath() {
return fullPath;
}
public boolean isParent(NavigablePath navigablePath) {
while ( navigablePath != null ) {
if ( this.equals( navigablePath.getParent() ) ) {

View File

@ -41,11 +41,6 @@ public class TreatedNavigablePath extends NavigablePath {
return new TreatedNavigablePath( getRealParent(), entityName, alias );
}
@Override
public String getLocalName() {
return getUnaliasedLocalName();
}
@Override
public int hashCode() {
return getFullPath().hashCode();

View File

@ -108,9 +108,9 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
);
// We never want to create empty composites for the FK target or PK, otherwise collections would break
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getUnaliasedLocalName() )
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getLocalName() )
&& embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
@ -232,8 +232,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// so we can't use the fetch parent access in that case.
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() )
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) {
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() ) ) {
fetchParentAccess.resolveInstance( processingState );
compositeInstance = fetchParentAccess.getInitializedInstance();
}
@ -255,8 +255,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
private void extractRowState(RowProcessingState processingState) {
stateAllNull = true;
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|| EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() );
for ( int i = 0; i < assemblers.size(); i++ ) {
final DomainResultAssembler<?> assembler = assemblers.get( i );

View File

@ -112,7 +112,7 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
&& fetchable.getFetchableName().equals( navigablePath.getLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath;
}

View File

@ -56,12 +56,11 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
@Override
public NavigablePath resolveNavigablePath(Fetchable fetchable) {
if ( fetchable instanceof TableGroupProducer &&
!getNavigablePath().getUnaliasedLocalName().equals( getNavigablePath().getLocalName() ) ) {
if ( fetchable instanceof TableGroupProducer && getNavigablePath().isAliased() ) {
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
&& fetchable.getFetchableName().equals( navigablePath.getLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath;
}

View File

@ -88,8 +88,8 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
NavigablePath np = navigablePath.getParent();
while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getUnaliasedLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getUnaliasedLocalName() )) {
|| ForeignKeyDescriptor.PART_NAME.equals( np.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getLocalName() )) {
initializeInstance( rowProcessingState );
return;
}

View File

@ -0,0 +1,114 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.spi.path;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
public class NavigablePathTests {
@Test
public void testRoots() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
assertThat( root.equals( root ) ).isTrue();
assertThat( root.getFullPath() ).isEqualTo( "org.hibernate.Root(r)" );
assertThat( root.getLocalName() ).isEqualTo( "org.hibernate.Root" );
assertThat( root.isAliased() ).isTrue();
assertThat( root.getAlias() ).isEqualTo( "r" );
final NavigablePath root2 = new NavigablePath( "org.hibernate.Root", "r" );
assertThat( root.equals( root2 ) ).isTrue();
}
@Test
public void testSubPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath name1 = root.append( "name" );
final NavigablePath name2 = root.append( "name" );
assertThat( name1.equals( name2 ) ).isTrue();
final NavigablePath id = root.append( "id" );
assertThat( name1.equals( root ) ).isFalse();
assertThat( id.equals( root ) ).isFalse();
}
@Test
public void testParallelSubPaths() {
final NavigablePath root1 = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath root2 = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath name1 = root1.append( "name" );
final NavigablePath name2 = root2.append( "name" );
assertThat( name1.equals( name2 ) ).isTrue();
}
@Test
public void testNestedPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath comp1 = root.append( "comp" );
final NavigablePath comp2 = root.append( "comp" );
final NavigablePath comp1Name = comp1.append( "name" );
final NavigablePath comp2Name = comp2.append( "name" );
assertThat( comp1Name.equals( comp2Name ) ).isTrue();
}
@Test
public void testDivergentNestedPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath comp = root.append( "comp" );
final NavigablePath other = root.append( "other" );
final NavigablePath compName = comp.append( "name" );
final NavigablePath otherName = other.append( "name" );
assertThat( compName.equals( otherName ) ).isFalse();
}
@Test
public void testStringification() {
final String rootStr = "org.hibernate.Root";
final String aliasedRootStr = "org.hibernate.Root(r)";
final String nameStr = "name";
final String namePathStr = aliasedRootStr + "." + nameStr;
final NavigablePath root = new NavigablePath( rootStr, "r" );
final NavigablePath name = root.append( "name" );
assertThat( name.getLocalName() ).isEqualTo( nameStr );
assertThat( name.getFullPath() ).isEqualTo( namePathStr );
}
@Test
public void testIdentifierPaths() {
final String rootStr = "org.hibernate.Root";
final String aliasedRootStr = "org.hibernate.Root(r)";
final String pkStr = "pk";
final String pkFullPathStr = aliasedRootStr + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
final NavigablePath root = new NavigablePath( rootStr, "r" );
final NavigablePath idPath = new EntityIdentifierNavigablePath( root, pkStr );
assertThat( idPath.getLocalName() ).isEqualTo( EntityIdentifierMapping.ROLE_LOCAL_NAME );
assertThat( idPath.getFullPath() ).isEqualTo( pkFullPathStr );
}
}