removing a questionable grammar rule seems to make implicit collection joins work

This commit is contained in:
Gavin King 2022-02-09 13:28:17 +01:00
parent 9ebac67737
commit 437da23961
6 changed files with 228 additions and 133 deletions

View File

@ -425,10 +425,10 @@ collectionValueNavigablePath
;
/**
* A 'key()' function that "breaks" a path expression
* A 'key()' or 'index()' function that "breaks" a path expression
*/
mapKeyNavigablePath
: KEY LEFT_PAREN path RIGHT_PAREN pathContinuation?
: (KEY|INDEX) LEFT_PAREN path RIGHT_PAREN pathContinuation?
;
@ -947,7 +947,7 @@ parameter
function
: standardFunction
| aggregateFunction
| jpaCollectionFunction
| collectionSizeFunction
| indexAggregateFunction
| elementAggregateFunction
| collectionFunctionMisuse
@ -995,11 +995,10 @@ genericFunctionArguments
;
/**
* The special 'size()' and 'index()' functions defined by JPQL
* The special 'size()' function defined by JPQL
*/
jpaCollectionFunction
: SIZE LEFT_PAREN path RIGHT_PAREN # CollectionSizeFunction
| INDEX LEFT_PAREN identifier RIGHT_PAREN # CollectionIndexFunction
collectionSizeFunction
: SIZE LEFT_PAREN path RIGHT_PAREN
;
/**

View File

@ -6,11 +6,8 @@
*/
package org.hibernate.query.hql.internal;
import java.util.Locale;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.SemanticException;
import org.hibernate.query.hql.HqlInterpretationException;
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmPathRegistry;

View File

@ -104,6 +104,7 @@ import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
import org.hibernate.query.sqm.tree.domain.SqmListJoin;
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
import org.hibernate.query.sqm.tree.domain.SqmMapJoin;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -4210,24 +4211,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
@Override
public SqmPath<?> visitCollectionIndexFunction(HqlParser.CollectionIndexFunctionContext ctx) {
final String alias = ctx.getChild( 2 ).getText();
final SqmFrom<?, ?> sqmFrom = processingStateStack.getCurrent().getPathRegistry().findFromByAlias( alias );
if ( sqmFrom == null ) {
throw new ParsingException( "Alias '" + alias + "' did not resolve to a declared identification variable" );
}
final SqmPathSource<?> pluralAttribute = sqmFrom.getReferencedPathSource();
if ( !( pluralAttribute instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new ParsingException( "Alias '" + alias + "' did not resolve to a many-valued attribute" );
}
return sqmFrom.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this );
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isIndexedPluralAttribute(SqmPath<?> path) {
return path.getReferencedPathSource() instanceof PluralPersistentAttribute;
@ -4529,41 +4512,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPath<?> visitCollectionValueNavigablePath(HqlParser.CollectionValueNavigablePathContext ctx) {
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException(
String.format(
"Argument of '%s' is not a plural path '%s'",
firstNode.getSymbol().getText(),
pluralAttributePath.getNavigablePath()
)
);
}
final PluralPersistentAttribute<?, ?, ?> attribute = (PluralPersistentAttribute<?, ?, ?>) referencedPathSource;
if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP );
}
}
SqmPath<?> result = pluralAttributePath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this );
if ( ctx.getChildCount() == 5 ) {
result = consumeDomainPath( (HqlParser.SimplePathContext) ctx.getChild( 4 ).getChild( 1 ) );
}
return result;
}
@Override
@SuppressWarnings("rawtypes")
public SqmPath visitMapKeyNavigablePath(HqlParser.MapKeyNavigablePathContext ctx) {
final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.getCurrent();
final boolean madeNested;
if ( consumer instanceof QualifiedJoinPathConsumer) {
@ -4579,6 +4527,91 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final boolean hasContinuation = ctx.getChildCount() == 5;
final SqmPathSource<?> referencedPathSource = sqmPath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
checkPluralPath( sqmPath, referencedPathSource, firstNode );
if ( getCreationOptions().useStrictJpaCompliance() ) {
final PluralPersistentAttribute<?, ?, ?> attribute = (PluralPersistentAttribute<?, ?, ?>) referencedPathSource;
if ( attribute.getCollectionClassification() != CollectionClassification.MAP
&& firstNode.getSymbol().getType() == HqlParser.VALUE ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP );
}
}
SqmPath<?> result;
if ( consumer instanceof QualifiedJoinPathConsumer) {
if ( madeNested && !hasContinuation ) {
// Reset the nested state before consuming the terminal identifier
( (QualifiedJoinPathConsumer) consumer ).setNested( false );
}
consumer.consumeIdentifier( CollectionPart.Nature.ELEMENT.getName(), false, !hasContinuation );
result = (SqmPath<?>) consumer.getConsumedPart();
}
else {
result = sqmPath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this );
}
if ( hasContinuation ) {
if ( madeNested ) {
// Reset the nested state before consuming the terminal identifier
( (QualifiedJoinPathConsumer) consumer ).setNested( false );
}
final HqlParser.SimplePathContext identCtx = (HqlParser.SimplePathContext) ctx.getChild( 4 )
.getChild( 1 );
if ( consumer instanceof QualifiedJoinPathConsumer) {
result = consumeDomainPath( identCtx );
}
else {
dotIdentifierConsumerStack.push(
new BasicDotIdentifierConsumer( result, this ) {
@Override
protected void reset() {
}
}
);
try {
result = consumeDomainPath( identCtx );
}
finally {
dotIdentifierConsumerStack.pop();
}
}
}
return result;
}
@Override
public SqmPath<?> visitMapKeyNavigablePath(HqlParser.MapKeyNavigablePathContext ctx) {
final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.getCurrent();
final boolean madeNested;
if ( consumer instanceof QualifiedJoinPathConsumer) {
final QualifiedJoinPathConsumer qualifiedJoinPathConsumer = (QualifiedJoinPathConsumer) consumer;
madeNested = !qualifiedJoinPathConsumer.isNested();
if ( madeNested ) {
qualifiedJoinPathConsumer.setNested( true );
}
}
else {
madeNested = false;
}
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final boolean hasContinuation = ctx.getChildCount() == 5;
final SqmPathSource<?> referencedPathSource = sqmPath.getReferencedPathSource();
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
checkPluralPath( sqmPath, referencedPathSource, firstNode );
if ( getCreationOptions().useStrictJpaCompliance() ) {
final PluralPersistentAttribute<?, ?, ?> attribute = (PluralPersistentAttribute<?, ?, ?>) referencedPathSource;
if ( attribute.getCollectionClassification() != CollectionClassification.MAP
&& firstNode.getSymbol().getType() == HqlParser.KEY ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.KEY_FUNCTION_ON_NON_MAP );
}
}
SqmPath<?> result;
if ( sqmPath instanceof SqmMapJoin ) {
final SqmMapJoin<?, ?, ?> sqmMapJoin = (SqmMapJoin<?, ?, ?>) sqmPath;
@ -4594,6 +4627,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
result = sqmMapJoin.key();
}
}
else if ( sqmPath instanceof SqmListJoin ) {
if ( hasContinuation ) {
throw new SemanticException("list index may not be dereferenced");
}
SqmListJoin<?,?> listJoin = (SqmListJoin<?,?>) sqmPath;
result = listJoin.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this );
}
else {
assert sqmPath instanceof SqmPluralValuedSimplePath;
final SqmPluralValuedSimplePath<?> mapPath = (SqmPluralValuedSimplePath<?>) sqmPath;
@ -4630,6 +4670,18 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return result;
}
private void checkPluralPath(SqmPath<?> pluralAttributePath, SqmPathSource<?> referencedPathSource, TerminalNode firstNode) {
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException(
String.format(
"Argument of '%s' is not a plural path '%s'",
firstNode.getSymbol().getText(),
pluralAttributePath.getNavigablePath()
)
);
}
}
private <X> SqmPath<X> consumeDomainPath(HqlParser.PathContext parserPath) {
final SemanticPathPart consumedPart = (SemanticPathPart) parserPath.accept( this );
if ( consumedPart instanceof SqmPath ) {
@ -4667,7 +4719,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return sqmPath;
}
throw new SemanticException( "Expecting plural attribute valued path [" + sqmPath.getNavigablePath() + "], but found : " + sqmPath.getReferencedPathSource().getSqmPathType() );
throw new SemanticException( "Expecting plural attribute valued path [" + sqmPath.getNavigablePath() + "], but found : "
+ sqmPath.getReferencedPathSource().getSqmPathType() );
}
private void checkFQNEntityNameJpaComplianceViolationIfNeeded(String name, EntityDomainType<?> entityDescriptor) {

View File

@ -21,6 +21,7 @@ public class StrictJpaComplianceViolation extends SemanticException {
FUNCTION_CALL( "improper non-standard function call" ),
HQL_COLLECTION_FUNCTION( "use of HQL collection functions (maxelement, minelement, maxindex, minindex, elements, indices)"),
VALUE_FUNCTION_ON_NON_MAP( "use of value() function for non-Map type" ),
KEY_FUNCTION_ON_NON_MAP( "use of key() function for non-Map type" ),
RESERVED_WORD_USED_AS_ALIAS( "use of reserved word as alias (identification variable or result variable)" ),
INDEXED_ELEMENT_REFERENCE( "use of HQL indexed element reference syntax" ),
TUPLES( "use of tuples/row value constructors" ),

View File

@ -16,6 +16,7 @@ import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
import org.hibernate.testing.orm.domain.gambit.EntityOfLists;
import org.hibernate.testing.orm.domain.gambit.EntityOfMaps;
import org.hibernate.testing.orm.domain.gambit.SimpleEntity;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialect;
@ -66,6 +67,12 @@ public class FunctionTests {
eol.addBasic("hello");
eol.addNumber(1.0);
eol.addNumber(2.0);
SimpleEntity hello = new SimpleEntity(3, "hello", 5L, 7);
SimpleEntity goodbye = new SimpleEntity(6, "goodbye", 10L, 9);
em.persist(hello);
em.persist(goodbye);
eol.addOneToMany(hello);
eol.addManyToMany(goodbye);
em.persist(eol);
EntityOfMaps eom = new EntityOfMaps(2,"");
@ -89,85 +96,112 @@ public class FunctionTests {
}
);
}
//
// @Test
// public void testMaxMinSumIndexElement(SessionFactoryScope scope) {
// scope.inTransaction(
// session -> {
// assertThat( session.createQuery("select max(index eol.listOfNumbers) from EntityOfLists eol")
// .getSingleResult(), is(1) );
// assertThat( session.createQuery("select max(element eol.listOfNumbers) from EntityOfLists eol")
// .getSingleResult(), is(2.0) );
//
// assertThat( session.createQuery("select sum(index eol.listOfNumbers) from EntityOfLists eol")
// .getSingleResult(), is(1) );
// assertThat( session.createQuery("select sum(element eol.listOfNumbers) from EntityOfLists eol")
// .getSingleResult(), is(3.0) );
//
// //TODO: why does this fail??
//// assertThat( session.createQuery("select avg(index eol.listOfNumbers) from EntityOfLists eol")
//// .getSingleResult(), is(0.5) );
// assertThat( session.createQuery("select avg(element eol.listOfNumbers) from EntityOfLists eol")
// .getSingleResult(), is(1.5) );
//
// assertThat( session.createQuery("select max(index eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1) );
// assertThat( session.createQuery("select max(element eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1.0) );
//
// assertThat( session.createQuery("select sum(index eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1) );
// assertThat( session.createQuery("select sum(element eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1.0) );
//
// assertThat( session.createQuery("select avg(index eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1) );
// assertThat( session.createQuery("select avg(element eom.numberByNumber) from EntityOfMaps eom")
// .getSingleResult(), is(1.0) );
// }
// );
// }
//
@Test
public void testAltMaxMinSumIndexElement(SessionFactoryScope scope) {
//TODO: make the commented tests work!
public void testImplicitCollectionJoinInSelect(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
// assertThat( session.createQuery("select max(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
// .getSingleResult(), is(1) );
assertThat( session.createQuery("select index(eol.listOfNumbers) from EntityOfLists eol", Integer.class)
.getResultList(), hasItems(0,1) );
assertThat( session.createQuery("select element(eol.listOfNumbers) from EntityOfLists eol", Double.class)
.getResultList(), hasItems(1.0, 2.0) );
assertThat( session.createQuery("select key(eom.numberByNumber) from EntityOfMaps eom", Integer.class)
.getResultList(), hasItems(1) );
assertThat( session.createQuery("select value(eom.numberByNumber) from EntityOfMaps eom", Double.class)
.getResultList(), hasItems(1.0) );
assertThat( session.createQuery("select key(eom.basicByBasic) from EntityOfMaps eom", String.class)
.getResultList(), hasItems("hello") );
assertThat( session.createQuery("select value(eom.basicByBasic) from EntityOfMaps eom", String.class)
.getResultList(), hasItems("world") );
assertThat( session.createQuery("select element(eol.listOfOneToMany) from EntityOfLists eol", SimpleEntity.class).getSingleResult().getId(), is(3) ) ;
assertThat( session.createQuery("select element(eol.listOfManyToMany) from EntityOfLists eol", SimpleEntity.class).getSingleResult().getId(), is(6) );
assertThat( session.createQuery("select element(se).someLong from EntityOfLists eol join eol.listOfOneToMany se", Long.class)
.getSingleResult(), is(5L) );
assertThat( session.createQuery("select element(eol.listOfOneToMany).someLong from EntityOfLists eol", Long.class)
.getSingleResult(), is(5L) );
assertThat( session.createQuery("select element(se).someLong from EntityOfLists eol join eol.listOfManyToMany se", Long.class)
.getSingleResult(), is(10L) );
assertThat( session.createQuery("select element(eol.listOfManyToMany).someLong from EntityOfLists eol", Long.class)
.getSingleResult(), is(10L) );
}
);
}
@Test
public void testImplicitCollectionJoinInWhere(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery("from EntityOfLists eol where index(eol.listOfNumbers)=0")
.getResultList();
session.createQuery("from EntityOfLists eol where element(eol.listOfNumbers)=1.0")
.getResultList();
session.createQuery("from EntityOfMaps eom where key(eom.numberByNumber)=1")
.getResultList();
session.createQuery("from EntityOfMaps eom where value(eom.numberByNumber)=1.0")
.getResultList();
session.createQuery("from EntityOfMaps eom where key(eom.basicByBasic)='hello'")
.getResultList();
session.createQuery("from EntityOfMaps eom where value(eom.basicByBasic)='world'")
.getResultList();
session.createQuery("from EntityOfLists eol join eol.listOfOneToMany se where element(se).someLong=5")
.getSingleResult();
session.createQuery("from EntityOfLists eol where element(eol.listOfOneToMany).someLong=5")
.getSingleResult();
session.createQuery("from EntityOfLists eol join eol.listOfManyToMany se where element(se).someLong=10")
.getSingleResult();
session.createQuery("from EntityOfLists eol where element(eol.listOfManyToMany).someLong=10")
.getSingleResult();
}
);
}
@Test
public void testImplicitCollectionJoinInSelectAggregate(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertThat( session.createQuery("select max(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(1) );
assertThat( session.createQuery("select max(element(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(2.0) );
// assertThat( session.createQuery("select sum(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
// .getSingleResult(), is(1) );
assertThat( session.createQuery("select sum(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(element(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(3.0) );
// assertThat( session.createQuery("select avg(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
// .getSingleResult(), is(0.5) );
assertThat( session.createQuery("select avg(index(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(0.5) );
assertThat( session.createQuery("select avg(element(eol.listOfNumbers)) from EntityOfLists eol group by eol")
.getSingleResult(), is(1.5) );
// assertThat( session.createQuery("select max(index(eom.numberByNumber)) from EntityOfMaps eom group by eom")
// .getSingleResult(), is(1) );
assertThat( session.createQuery("select max(element(eom.numberByNumber)) from EntityOfMaps eom group by eom")
assertThat( session.createQuery("select max(key(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1) );
assertThat( session.createQuery("select max(value(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1.0) );
// assertThat( session.createQuery("select sum(index(eom.numberByNumber)) from EntityOfMaps eom group by eom")
// .getSingleResult(), is(1) );
assertThat( session.createQuery("select sum(element(eom.numberByNumber)) from EntityOfMaps eom group by eom")
assertThat( session.createQuery("select sum(key(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(value(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1.0) );
// assertThat( session.createQuery("select avg(index(eom.numberByNumber)) from EntityOfMaps eom group by eom")
// .getSingleResult(), is(1) );
assertThat( session.createQuery("select avg(element(eom.numberByNumber)) from EntityOfMaps eom group by eom")
assertThat( session.createQuery("select avg(key(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(value(eom.numberByNumber)) from EntityOfMaps eom group by eom")
.getSingleResult(), is(1.0) );
}
);
}
@Test
public void testMaxMinSumIndicesElements(SessionFactoryScope scope) {
public void testAggregateIndicesElementsWithPath(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertThat( session.createQuery("select max(indices(eol.listOfNumbers)) from EntityOfLists eol")
@ -176,12 +210,12 @@ public class FunctionTests {
.getSingleResult(), is(2.0) );
assertThat( session.createQuery("select sum(indices(eol.listOfNumbers)) from EntityOfLists eol")
.getSingleResult(), is(1) ); //TODO: should be Long
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(elements(eol.listOfNumbers)) from EntityOfLists eol")
.getSingleResult(), is(3.0) );
// assertThat( session.createQuery("select avg(indices(eol.listOfNumbers)) from EntityOfLists eol")
// .getSingleResult(), is(0.5) ); //TODO: FIX!!
assertThat( session.createQuery("select avg(indices(eol.listOfNumbers)) from EntityOfLists eol")
.getSingleResult(), is(0.5) );
assertThat( session.createQuery("select avg(elements(eol.listOfNumbers)) from EntityOfLists eol")
.getSingleResult(), is(1.5) );
@ -191,12 +225,12 @@ public class FunctionTests {
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select sum(indices(eom.numberByNumber)) from EntityOfMaps eom")
.getSingleResult(), is(1) ); //TODO: should be Long
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(elements(eom.numberByNumber)) from EntityOfMaps eom")
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(indices(eom.numberByNumber)) from EntityOfMaps eom")
.getSingleResult(), is(1) ); //TODO: should be Double
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(elements(eom.numberByNumber)) from EntityOfMaps eom")
.getSingleResult(), is(1.0) );
}
@ -204,7 +238,7 @@ public class FunctionTests {
}
@Test
public void testNoMaxMinSumIndexElement(SessionFactoryScope scope) {
public void testAggregateIndexElementKeyValueWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertThat( session.createQuery("select max(index(l)) from EntityOfLists eol join eol.listOfNumbers l group by eol")
@ -222,19 +256,19 @@ public class FunctionTests {
assertThat( session.createQuery("select avg(element(l)) from EntityOfLists eol join eol.listOfNumbers l group by eol")
.getSingleResult(), is(1.5) );
assertThat( session.createQuery("select max(index(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select max(key(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1) );
assertThat( session.createQuery("select max(element(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select max(value(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select sum(index(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select sum(key(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1L) );
assertThat( session.createQuery("select sum(element(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select sum(value(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(index(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select avg(key(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1.0) );
assertThat( session.createQuery("select avg(element(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
assertThat( session.createQuery("select avg(value(m)) from EntityOfMaps eom join eom.numberByNumber m group by eom")
.getSingleResult(), is(1.0) );
}
);

View File

@ -50,6 +50,17 @@ public class SimpleEntity {
this.someLong = someLong;
}
public SimpleEntity(
Integer id,
String someString,
Long someLong,
Integer someInteger) {
this.id = id;
this.someString = someString;
this.someLong = someLong;
this.someInteger = someInteger;
}
public SimpleEntity(
Integer id,
Date someDate,