support for canonical reference to id and version. consider other entity parts - natural-id, tenant-discriminator, etc
This commit is contained in:
parent
c2bb7d65f2
commit
b23e5ba54a
|
@ -141,6 +141,10 @@ ARROW : '->';
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Keywords
|
||||
|
||||
ID : [iI][dD];
|
||||
VERSION : [vV] [eE] [rR] [sS] [iI] [oO] [nN];
|
||||
NATURALID : [nN] [aA] [tT] [uU] [rR] [aA] [lL] [iI] [dD];
|
||||
|
||||
ABS : [aA] [bB] [sS];
|
||||
ALL : [aA] [lL] [lL];
|
||||
AND : [aA] [nN] [dD];
|
||||
|
|
|
@ -413,6 +413,9 @@ expression
|
|||
| literal # LiteralExpression
|
||||
| parameter # ParameterExpression
|
||||
| entityTypeReference # EntityTypeExpression
|
||||
| entityIdReference # EntityIdExpression
|
||||
| entityVersionReference # EntityVersionExpression
|
||||
| entityNaturalIdReference # EntityNaturalIdExpression
|
||||
| path # PathExpression
|
||||
| function # FunctionExpression
|
||||
| LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression
|
||||
|
@ -422,6 +425,18 @@ entityTypeReference
|
|||
: TYPE LEFT_PAREN (path | parameter) RIGHT_PAREN
|
||||
;
|
||||
|
||||
entityIdReference
|
||||
: ID LEFT_PAREN path RIGHT_PAREN pathContinuation?
|
||||
;
|
||||
|
||||
entityVersionReference
|
||||
: VERSION LEFT_PAREN path RIGHT_PAREN
|
||||
;
|
||||
|
||||
entityNaturalIdReference
|
||||
: NATURALID LEFT_PAREN path RIGHT_PAREN pathContinuation?
|
||||
;
|
||||
|
||||
caseStatement
|
||||
: simpleCaseStatement
|
||||
| searchedCaseStatement
|
||||
|
@ -987,6 +1002,7 @@ identifier
|
|||
| GREATEST
|
||||
| GROUP
|
||||
| HOUR
|
||||
| ID
|
||||
| IFNULL
|
||||
| IN
|
||||
| INDEX
|
||||
|
@ -1020,6 +1036,7 @@ identifier
|
|||
| MOD
|
||||
| MONTH
|
||||
| NANOSECOND
|
||||
| NATURALID
|
||||
| NEW
|
||||
| NOT
|
||||
| NULLIF
|
||||
|
@ -1056,6 +1073,7 @@ identifier
|
|||
| UPDATE
|
||||
| UPPER
|
||||
| VALUE
|
||||
| VERSION
|
||||
| WEEK
|
||||
| WHERE
|
||||
| WITH
|
||||
|
|
|
@ -39,11 +39,13 @@ import org.hibernate.metamodel.CollectionClassification;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.IdentifiableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.query.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.PathException;
|
||||
|
@ -1320,6 +1322,70 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
throw new ParsingException( "Could not interpret grammar context as 'entity type' expression : " + ctx.getText() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityIdExpression(HqlParser.EntityIdExpressionContext ctx) {
|
||||
return visitEntityIdReference( ctx.entityIdReference() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx) {
|
||||
final SqmPath sqmPath = consumeDomainPath( ctx.path() );
|
||||
final DomainType sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
|
||||
|
||||
if ( sqmPathType instanceof IdentifiableDomainType ) {
|
||||
//noinspection unchecked
|
||||
final SqmPath idPath = ( (IdentifiableDomainType) sqmPathType ).getIdentifierDescriptor().createSqmPath(
|
||||
sqmPath,
|
||||
this
|
||||
);
|
||||
|
||||
if ( ctx.pathContinuation() == null ) {
|
||||
return idPath;
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception( "Path continuation from `id()` reference not yet implemented" );
|
||||
}
|
||||
|
||||
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityVersionExpression(HqlParser.EntityVersionExpressionContext ctx) {
|
||||
return visitEntityVersionReference( ctx.entityVersionReference() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) {
|
||||
final SqmPath sqmPath = consumeDomainPath( ctx.path() );
|
||||
final DomainType sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
|
||||
|
||||
if ( sqmPathType instanceof IdentifiableDomainType ) {
|
||||
final IdentifiableDomainType identifiableType = (IdentifiableDomainType) sqmPathType;
|
||||
final SingularPersistentAttribute versionAttribute = identifiableType.findVersionAttribute();
|
||||
if ( versionAttribute == null ) {
|
||||
throw new SemanticException(
|
||||
"`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" +
|
||||
identifiableType.getTypeName() + "`) which does not define a version"
|
||||
);
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return versionAttribute.createSqmPath( sqmPath, this );
|
||||
}
|
||||
|
||||
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityNaturalIdExpression(HqlParser.EntityNaturalIdExpressionContext ctx) {
|
||||
return visitEntityNaturalIdReference( ctx.entityNaturalIdReference() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath visitEntityNaturalIdReference(HqlParser.EntityNaturalIdReferenceContext ctx) {
|
||||
throw new NotYetImplementedFor6Exception( "Support for HQL natural-id references not yet implemented" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SqmMapEntryReference visitMapEntrySelection(HqlParser.MapEntrySelectionContext ctx) {
|
||||
|
@ -3551,7 +3617,6 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
private SqmPath consumeDomainPath(HqlParser.PathContext parserPath) {
|
||||
final SemanticPathPart consumedPart = (SemanticPathPart) parserPath.accept( this );
|
||||
if ( consumedPart instanceof SqmPath ) {
|
||||
|
|
|
@ -7,18 +7,16 @@
|
|||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.internal.SingularAttributeImpl;
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.orm.test.query.sqm.domain.Person;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
|
@ -29,8 +27,6 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
|
@ -112,8 +108,6 @@ public class AttributePathTests extends BaseSqmUnitTest {
|
|||
interpretSelect( "select s.mate from Person s where s.id = ?1" );
|
||||
interpretSelect( "select s.mate from Person s where s.pk = ?1" );
|
||||
|
||||
// NOTE: this next form does not (yet) work...
|
||||
interpretSelect( "select s.mate from Person s where s.{id} = ?1" );
|
||||
|
||||
final EntityDomainType<OddOne> entity = sessionFactory().getRuntimeMetamodels()
|
||||
.getJpaMetamodel()
|
||||
|
@ -131,6 +125,14 @@ public class AttributePathTests extends BaseSqmUnitTest {
|
|||
assertThat( ( (SqmPath) pkRef ).getJavaType(), sameInstance( String.class ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanonicalReferences() {
|
||||
final SqmSelectStatement sqm = interpretSelect( "select s.mate from Person s where id(s) = ?1" );
|
||||
assertThat( sqm.getQuerySpec().getRestriction(), notNullValue() );
|
||||
final SqmComparisonPredicate restriction = (SqmComparisonPredicate) sqm.getQuerySpec().getRestriction();
|
||||
assertThat( restriction, notNullValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToOneReference() {
|
||||
final SqmSelectStatement sqm = interpretSelect( "select s.mate from Person s" );
|
||||
|
|
Loading…
Reference in New Issue