HHH-16715 clean up the code surrounding this stuff

This commit is contained in:
Gavin 2023-05-29 22:55:22 +02:00 committed by Gavin King
parent 3a40f9c829
commit 6c36e98b1a
5 changed files with 178 additions and 82 deletions

View File

@ -215,6 +215,7 @@ INTO : [iI] [nN] [tT] [oO];
IS : [iI] [sS];
JOIN : [jJ] [oO] [iI] [nN];
KEY : [kK] [eE] [yY];
KEYS : [kK] [eE] [yY] [sS];
LAST : [lL] [aA] [sS] [tT];
LATERAL : [lL] [aA] [tT] [eE] [rR] [aA] [lL];
LEADING : [lL] [eE] [aA] [dD] [iI] [nN] [gG];

View File

@ -450,14 +450,14 @@ treatedNavigablePath
* A 'value()' function that "breaks" a path expression
*/
collectionValueNavigablePath
: (VALUE|ELEMENT) LEFT_PAREN path RIGHT_PAREN pathContinuation?
: elementValueQuantifier LEFT_PAREN path RIGHT_PAREN pathContinuation?
;
/**
* A 'key()' or 'index()' function that "breaks" a path expression
*/
mapKeyNavigablePath
: (KEY|INDEX) LEFT_PAREN path RIGHT_PAREN pathContinuation?
: indexKeyQuantifier LEFT_PAREN path RIGHT_PAREN pathContinuation?
;
@ -626,7 +626,7 @@ predicate
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate
| EXISTS (ELEMENTS|INDICES) LEFT_PAREN simplePath RIGHT_PAREN # ExistsCollectionPartPredicate
| EXISTS collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN # ExistsCollectionPartPredicate
| EXISTS expression # ExistsPredicate
| expression NOT? MEMBER OF? path # MemberOfPredicate
| NOT predicate # NegatedPredicate
@ -655,7 +655,7 @@ comparisonOperator
* A list of values, a parameter (for a parameterized list of values), a subquery, or an 'elements()' or 'indices()' function
*/
inList
: (ELEMENTS|INDICES) LEFT_PAREN simplePath RIGHT_PAREN # PersistentCollectionReferenceInList
: collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN # PersistentCollectionReferenceInList
| LEFT_PAREN (expressionOrPredicate (COMMA expressionOrPredicate)*)? RIGHT_PAREN# ExplicitTupleInList
| LEFT_PAREN subquery RIGHT_PAREN # SubqueryInList
| parameter # ParamInList
@ -715,6 +715,31 @@ expressionOrPredicate
| predicate
;
collectionQuantifier
: elementsValuesQuantifier
| indicesKeysQuantifier
;
elementValueQuantifier
: ELEMENT
| VALUE
;
indexKeyQuantifier
: INDEX
| KEY
;
elementsValuesQuantifier
: ELEMENTS
| VALUES
;
indicesKeysQuantifier
: INDICES
| KEYS
;
/**
* A binary operator with the same precedence as *
*/
@ -1024,8 +1049,7 @@ function
: standardFunction
| aggregateFunction
| collectionSizeFunction
| indexAggregateFunction
| elementAggregateFunction
| collectionAggregateFunction
| collectionFunctionMisuse
| jpaNonstandardFunction
| genericFunction
@ -1079,27 +1103,14 @@ collectionSizeFunction
;
/**
* The special aggregate collection functions defined by HQL
* Special rule for 'max(elements())`, 'avg(keys())', 'sum(indices())`, etc., as defined by HQL
* Also the deprecated 'maxindex()', 'maxelement()', 'minindex()', 'minelement()' functions from old HQL
*/
indexAggregateFunction
: MAXINDEX LEFT_PAREN path RIGHT_PAREN
| MININDEX LEFT_PAREN path RIGHT_PAREN
| MAX LEFT_PAREN INDICES LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| MIN LEFT_PAREN INDICES LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| SUM LEFT_PAREN INDICES LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| AVG LEFT_PAREN INDICES LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
;
/**
* The special aggregate collection functions defined by HQL
*/
elementAggregateFunction
: MAXELEMENT LEFT_PAREN path RIGHT_PAREN
| MINELEMENT LEFT_PAREN path RIGHT_PAREN
| MAX LEFT_PAREN ELEMENTS LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| MIN LEFT_PAREN ELEMENTS LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| SUM LEFT_PAREN ELEMENTS LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
| AVG LEFT_PAREN ELEMENTS LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN
collectionAggregateFunction
: (MAX|MIN|SUM|AVG) LEFT_PAREN elementsValuesQuantifier LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN # ElementAggregateFunction
| (MAX|MIN|SUM|AVG) LEFT_PAREN indicesKeysQuantifier LEFT_PAREN path RIGHT_PAREN RIGHT_PAREN # IndexAggregateFunction
| (MAXELEMENT|MINELEMENT) LEFT_PAREN path RIGHT_PAREN # ElementAggregateFunction
| (MAXINDEX|MININDEX) LEFT_PAREN path RIGHT_PAREN # IndexAggregateFunction
;
/**
@ -1109,8 +1120,8 @@ elementAggregateFunction
* and so we have tests that insist they're interchangeable. Ugh.)
*/
collectionFunctionMisuse
: ELEMENTS LEFT_PAREN path RIGHT_PAREN
| INDICES LEFT_PAREN path RIGHT_PAREN
: elementsValuesQuantifier LEFT_PAREN path RIGHT_PAREN
| indicesKeysQuantifier LEFT_PAREN path RIGHT_PAREN
;
/**
@ -1128,20 +1139,30 @@ aggregateFunction
* The functions 'every()' and 'all()' are synonyms
*/
everyFunction
: (EVERY|ALL) LEFT_PAREN predicate RIGHT_PAREN filterClause? overClause?
| (EVERY|ALL) LEFT_PAREN subquery RIGHT_PAREN
| (EVERY|ALL) (ELEMENTS|INDICES) LEFT_PAREN simplePath RIGHT_PAREN
: everyAllQuantifier LEFT_PAREN predicate RIGHT_PAREN filterClause? overClause?
| everyAllQuantifier LEFT_PAREN subquery RIGHT_PAREN
| everyAllQuantifier collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN
;
/**
* The functions 'any()' and 'some()' are synonyms
*/
anyFunction
: (ANY|SOME) LEFT_PAREN predicate RIGHT_PAREN filterClause? overClause?
| (ANY|SOME) LEFT_PAREN subquery RIGHT_PAREN
| (ANY|SOME) (ELEMENTS|INDICES) LEFT_PAREN simplePath RIGHT_PAREN
: anySomeQuantifier LEFT_PAREN predicate RIGHT_PAREN filterClause? overClause?
| anySomeQuantifier LEFT_PAREN subquery RIGHT_PAREN
| anySomeQuantifier collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN
;
everyAllQuantifier
: EVERY
| ALL
;
anySomeQuantifier
: ANY
| SOME
;
/**
* The 'listagg()' ordered set-aggregate function
*/
@ -1623,6 +1644,7 @@ rollup
| IS
| JOIN
| KEY
| KEYS
| LAST
| LATERAL
| LEADING

View File

@ -2656,7 +2656,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
try {
return new SqmInListPredicate(
testExpression,
singletonList( tupleExpressionListContext.getChild( 0 ).accept( this ) ),
singletonList( tupleExpressionListContext.parameter().accept( this ) ),
negated,
creationContext.getNodeBuilder()
);
@ -2669,7 +2669,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final HqlParser.SubqueryInListContext subQueryOrParamInListContext = (HqlParser.SubqueryInListContext) inListContext;
return new SqmInSubQueryPredicate(
testExpression,
visitSubquery( (HqlParser.SubqueryContext) subQueryOrParamInListContext.getChild( 1 ) ),
visitSubquery( subQueryOrParamInListContext.subquery() ),
negated,
creationContext.getNodeBuilder()
);
@ -2682,8 +2682,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return new SqmInSubQueryPredicate<>(
testExpression,
createCollectionReferenceSubQuery(
(HqlParser.SimplePathContext) collectionReferenceInListContext.getChild( 2 ),
(TerminalNode) collectionReferenceInListContext.getChild( 0 )
collectionReferenceInListContext.simplePath(),
(TerminalNode) collectionReferenceInListContext.collectionQuantifier().getChild(0).getChild(0)
),
negated,
creationContext.getNodeBuilder()
@ -2697,7 +2697,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPredicate visitExistsCollectionPartPredicate(HqlParser.ExistsCollectionPartPredicateContext ctx) {
final SqmSubQuery<Object> subQuery = createCollectionReferenceSubQuery(
(HqlParser.SimplePathContext) ctx.getChild( 3 ),
ctx.simplePath(),
null
);
return new SqmExistsPredicate( subQuery, creationContext.getNodeBuilder() );
@ -2705,18 +2705,18 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPredicate visitExistsPredicate(HqlParser.ExistsPredicateContext ctx) {
final SqmExpression<?> expression = (SqmExpression<?>) ctx.getChild( 1 ).accept( this );
final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression().accept( this );
return new SqmExistsPredicate( expression, creationContext.getNodeBuilder() );
}
@Override @SuppressWarnings("rawtypes")
@Override
public SqmPredicate visitBooleanExpressionPredicate(HqlParser.BooleanExpressionPredicateContext ctx) {
final SqmExpression expression = (SqmExpression) ctx.expression().accept( this );
final SqmExpression<?> expression = (SqmExpression<?>) ctx.expression().accept( this );
if ( expression.getJavaType() != Boolean.class ) {
throw new SemanticException( "Non-boolean expression used in predicate context: " + ctx.getText() );
}
@SuppressWarnings("unchecked")
final SqmExpression<Boolean> booleanExpression = expression;
final SqmExpression<Boolean> booleanExpression = (SqmExpression<Boolean>) expression;
return new SqmBooleanExpressionPredicate( booleanExpression, creationContext.getNodeBuilder() );
}
@ -4497,7 +4497,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
return new SqmEvery<>(
createCollectionReferenceSubQuery( ctx.simplePath(), (TerminalNode) ctx.getChild( 1 ) ),
createCollectionReferenceSubQuery(
ctx.simplePath(),
(TerminalNode) ctx.collectionQuantifier().getChild(0).getChild(0)
),
creationContext.getNodeBuilder()
);
}
@ -4530,7 +4533,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
return new SqmAny<>(
createCollectionReferenceSubQuery( ctx.simplePath(), (TerminalNode) ctx.getChild( 1 ) ),
createCollectionReferenceSubQuery(
ctx.simplePath(),
(TerminalNode) ctx.collectionQuantifier().getChild(0).getChild(0)
),
creationContext.getNodeBuilder()
);
}
@ -4910,14 +4916,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
// Note: this is a total misuse of the elements() and indices() functions,
// which are supposed to be a shortcut way to write a subquery!
// used this way, they're just a worse way to write value()/index()
log.warn("Misuse of HQL elements() or indices() function, use element() or index() instead");
if ( getCreationOptions().useStrictJpaCompliance() ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPath<?> pluralAttributePath = consumeDomainPath( ctx.path() );
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 ).getChild( 0 );
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException(
@ -4945,40 +4952,71 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
@Override
public SqmElementAggregateFunction<?> visitElementAggregateFunction(HqlParser.ElementAggregateFunctionContext ctx) {
public SqmExpression<?> visitElementAggregateFunction(HqlParser.ElementAggregateFunctionContext ctx) {
if ( creationOptions.useStrictJpaCompliance() ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
if ( !(pluralPath instanceof SqmPluralValuedSimplePath) ) {
throw new SemanticException( "Path '" + ctx.path().getText() + "' did not resolve to a many-valued attribute" );
}
// the actual function name might be 'minelement' or 'maxelement', so trim it
final String functionName = ctx.getChild(0).getText().substring(0, 3);
String functionName = ctx.getChild(0).getText().substring(0, 3);
return new SqmElementAggregateFunction<>( pluralPath, functionName );
final SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
if ( pluralPath instanceof SqmPluralValuedSimplePath ) {
return new SqmElementAggregateFunction<>( pluralPath, functionName );
}
else {
// elements() and values() and only apply to compound paths
if ( pluralPath instanceof SqmMapJoin ) {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' resolved to a joined map instead of a compound path" );
}
else if ( pluralPath instanceof SqmListJoin ) {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' resolved to a joined list instead of a compound path" );
}
else {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' did not resolve to a many-valued attribute" );
}
}
}
@Override
public SqmIndexAggregateFunction<?> visitIndexAggregateFunction(HqlParser.IndexAggregateFunctionContext ctx) {
public SqmExpression<?> visitIndexAggregateFunction(HqlParser.IndexAggregateFunctionContext ctx) {
if ( creationOptions.useStrictJpaCompliance() ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
final SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
if ( !(pluralPath instanceof SqmPluralValuedSimplePath) ) {
throw new SemanticException( "Path '" + ctx.path().getText() + "' did not resolve to a many-valued attribute" );
}
if ( !isIndexedPluralAttribute( pluralPath ) ) {
throw new SemanticException(
"maxindex() function can only be applied to path expressions which resolve to an " +
"indexed collection (list,map); specified path [" + ctx.path() +
"] resolved to " + pluralPath.getReferencedPathSource()
);
}
// the actual function name might be 'minindex' or 'maxindex', so trim it
final String functionName = ctx.getChild(0).getText().substring(0, 3);
String functionName = ctx.getChild(0).getText().substring(0, 3);
return new SqmIndexAggregateFunction<>( pluralPath, functionName );
final SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
if ( pluralPath instanceof SqmPluralValuedSimplePath ) {
if ( isIndexedPluralAttribute( pluralPath ) ) {
return new SqmIndexAggregateFunction<>(pluralPath, functionName);
}
else {
throw new SemanticException( "Path '" + ctx.path()
+ "' resolved to '"
+ pluralPath.getReferencedPathSource()
+ "' which is not an indexed collection" );
}
}
else {
// indices() and keys() only apply to compound paths
if ( pluralPath instanceof SqmMapJoin ) {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' resolved to a joined map instead of a compound path" );
}
else if ( pluralPath instanceof SqmListJoin ) {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' resolved to a joined list instead of a compound path" );
}
else {
throw new SemanticException( "Path '" + ctx.path().getText()
+ "' did not resolve to a many-valued attribute" );
}
}
}
@Override
@ -5122,7 +5160,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final boolean hasContinuations = numberOfContinuations != 0;
final DotIdentifierConsumer dotIdentifierConsumer = dotIdentifierConsumerStack.getCurrent();
final HqlParser.IdentifierContext identifierContext = (HqlParser.IdentifierContext) ctx.getChild( 0 );
final HqlParser.IdentifierContext identifierContext = ctx.identifier();
assert identifierContext.getChildCount() == 1;
dotIdentifierConsumer.consumeIdentifier(
@ -5134,7 +5172,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( hasContinuations ) {
for ( int i = 1; i < ctx.getChildCount(); i++ ) {
final HqlParser.SimplePathElementContext continuation = (HqlParser.SimplePathElementContext) ctx.getChild( i );
final HqlParser.IdentifierContext identifier = (HqlParser.IdentifierContext) continuation.getChild( 1 );
final HqlParser.IdentifierContext identifier = continuation.identifier();
assert identifier.getChildCount() == 1;
dotIdentifierConsumer.consumeIdentifier(
visitIdentifier( identifier ),
@ -5161,9 +5199,9 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else {
madeNested = false;
}
consumeManagedTypeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
consumeManagedTypeReference( ctx.path() );
final String treatTargetName = ctx.getChild( 4 ).getText();
final String treatTargetName = ctx.simplePath().getText();
final String treatTargetEntityName = getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
final boolean hasContinuation = ctx.getChildCount() == 7;
@ -5186,7 +5224,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
try {
result = consumeDomainPath( (HqlParser.SimplePathContext) ctx.getChild( 6 ).getChild( 1 ) );
result = consumeDomainPath( ctx.pathContinuation().simplePath() );
}
finally {
if ( addConsumer ) {
@ -5212,11 +5250,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else {
madeNested = false;
}
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
final boolean hasContinuation = ctx.getChildCount() == 5;
final SqmPathSource<?> referencedPathSource = sqmPath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
final TerminalNode firstNode = (TerminalNode) ctx.elementValueQuantifier().getChild(0);
checkPluralPath( sqmPath, referencedPathSource, firstNode );
if ( getCreationOptions().useStrictJpaCompliance() ) {
@ -5245,8 +5283,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
// Reset the nested state before consuming the terminal identifier
( (QualifiedJoinPathConsumer) consumer ).setNested( false );
}
final HqlParser.SimplePathContext identCtx = (HqlParser.SimplePathContext) ctx.getChild( 4 )
.getChild( 1 );
final HqlParser.SimplePathContext identCtx = ctx.pathContinuation().simplePath();
if ( consumer instanceof QualifiedJoinPathConsumer) {
result = consumeDomainPath( identCtx );
}
@ -5285,11 +5322,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else {
madeNested = false;
}
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
final boolean hasContinuation = ctx.getChildCount() == 5;
final SqmPathSource<?> referencedPathSource = sqmPath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
final TerminalNode firstNode = (TerminalNode) ctx.indexKeyQuantifier().getChild(0);
checkPluralPath( sqmPath, referencedPathSource, firstNode );
if ( getCreationOptions().useStrictJpaCompliance() ) {
@ -5333,8 +5370,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
// Reset the nested state before consuming the terminal identifier
( (QualifiedJoinPathConsumer) consumer ).setNested( false );
}
final HqlParser.SimplePathContext identCtx = (HqlParser.SimplePathContext) ctx.getChild( 4 )
.getChild( 1 );
final HqlParser.SimplePathContext identCtx = ctx.pathContinuation().simplePath();
if ( consumer instanceof QualifiedJoinPathConsumer) {
result = consumeDomainPath( identCtx );
}

View File

@ -106,7 +106,7 @@ public class SqmMapJoin<O, K, V>
}
@Override
public Path<V> value() {
public SqmPath<V> value() {
final SqmPathSource<V> elementPathSource = getReferencedPathSource().getElementPathSource();
return resolvePath( elementPathSource.getPathName(), elementPathSource );
}

View File

@ -294,6 +294,43 @@ public class FunctionTests {
);
}
@Test
public void testAggregateIndexElementWithPath(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertThat( session.createQuery("select max(index(eol.listOfNumbers)) from EntityOfLists eol", Integer.class)
.getSingleResult(), is(1) );
assertThat( session.createQuery("select max(element(eol.listOfNumbers)) from EntityOfLists eol", Double.class)
.getSingleResult(), is(2.0) );
assertThat( session.createQuery("select sum(index(eol.listOfNumbers)) from EntityOfLists eol", Long.class)
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(element(eol.listOfNumbers)) from EntityOfLists eol", Double.class)
.getSingleResult(), is(3.0) );
assertThat( session.createQuery("select avg(index(eol.listOfNumbers)) from EntityOfLists eol", Double.class)
.getSingleResult(), is(0.5) );
assertThat( session.createQuery("select avg(element(eol.listOfNumbers)) from EntityOfLists eol", Double.class)
.getSingleResult(), is(1.5) );
assertThat( session.createQuery("select max(key(eom.numberByNumber)) from EntityOfMaps eom", Integer.class)
.getSingleResult(), is(1) );
assertThat( session.createQuery("select max(element(eom.numberByNumber)) from EntityOfMaps eom", Double.class)
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select sum(key(eom.numberByNumber)) from EntityOfMaps eom", Long.class)
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(element(eom.numberByNumber)) from EntityOfMaps eom", Double.class)
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(key(eom.numberByNumber)) from EntityOfMaps eom", Double.class)
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(element(eom.numberByNumber)) from EntityOfMaps eom", Double.class)
.getSingleResult(), is(1.0) );
}
);
}
@Test
public void testAggregateIndexElementKeyValueWithAlias(SessionFactoryScope scope) {
scope.inTransaction(