diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java index 190c68239a..bddf172aa1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java @@ -25,6 +25,7 @@ import org.hibernate.engine.query.spi.NativeQueryInterpreter; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.jpa.spi.JpaCompliance; import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.query.criteria.ValueHandlingMode; import org.hibernate.query.hql.HqlTranslator; @@ -57,10 +58,7 @@ import org.jboss.logging.Logger; public class QueryEngine { private static final Logger LOG_HQL_FUNCTIONS = CoreLogging.logger( "org.hibernate.LOG_HQL_FUNCTIONS" ); - public static QueryEngine from( - SessionFactoryImplementor sessionFactory, - MetadataImplementor metadata) { - final SqmCreationContext sqmCreationContext = sessionFactory; + public static QueryEngine from(SessionFactoryImplementor sessionFactory, MetadataImplementor metadata) { final QueryEngineOptions queryEngineOptions = sessionFactory.getSessionFactoryOptions(); final SqmCreationOptions sqmCreationOptions = new SqmCreationOptionsStandard( sessionFactory ); @@ -68,7 +66,7 @@ public class QueryEngine { final HqlTranslator hqlTranslator = resolveHqlTranslator( queryEngineOptions, dialect, - sqmCreationContext, + sessionFactory, sqmCreationOptions ); @@ -91,6 +89,7 @@ public class QueryEngine { return new QueryEngine( sessionFactory.getUuid(), sessionFactory.getName(), + sessionFactory.getSessionFactoryOptions().getJpaCompliance(), () -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(), sessionFactory.getSessionFactoryOptions().getCriteriaValueHandlingMode(), sessionFactory.getSessionFactoryOptions().getPreferredSqlTypeCodeForBoolean(), @@ -119,6 +118,7 @@ public class QueryEngine { public QueryEngine( String uuid, String name, + JpaCompliance jpaCompliance, Supplier jpaMetamodelAccess, ValueHandlingMode criteriaValueHandlingMode, int preferredSqlTypeCodeForBoolean, @@ -140,6 +140,7 @@ public class QueryEngine { this.criteriaBuilder = new SqmCriteriaNodeBuilder( uuid, name, + jpaCompliance.isJpaQueryComplianceEnabled(), this, jpaMetamodelAccess, serviceRegistry, @@ -212,6 +213,7 @@ public class QueryEngine { this.criteriaBuilder = new SqmCriteriaNodeBuilder( uuid, name, + false, this, () -> jpaMetamodel, serviceRegistry, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java index a62d32735c..32faf8c040 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java @@ -78,6 +78,8 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { return getDomainModel().getTypeConfiguration(); } + boolean isJpaQueryComplianceEnabled(); + ServiceRegistry getServiceRegistry(); QueryEngine getQueryEngine(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index d08d841f4f..4ddaa177d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -150,6 +150,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, return new SqmCriteriaNodeBuilder( sf.getUuid(), sf.getName(), + sf.getSessionFactoryOptions().getJpaCompliance().isJpaQueryComplianceEnabled(), sf.getQueryEngine(), () -> sf.getRuntimeMetamodels().getJpaMetamodel(), sf.getServiceRegistry(), @@ -159,6 +160,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, private final String uuid; private final String name; + private final transient boolean jpaComplianceEnabled; private final transient QueryEngine queryEngine; private final transient Supplier domainModelAccess; private final transient ServiceRegistry serviceRegistry; @@ -169,12 +171,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, public SqmCriteriaNodeBuilder( String uuid, String name, + boolean jpaComplianceEnabled, QueryEngine queryEngine, Supplier domainModelAccess, ServiceRegistry serviceRegistry, ValueHandlingMode criteriaValueHandlingMode) { this.uuid = uuid; this.name = name; + this.jpaComplianceEnabled = jpaComplianceEnabled; this.queryEngine = queryEngine; this.domainModelAccess = domainModelAccess; this.serviceRegistry = serviceRegistry; @@ -186,6 +190,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, return domainModelAccess.get(); } + @Override + public boolean isJpaQueryComplianceEnabled() { + return jpaComplianceEnabled; + } + @Override public BasicType getBooleanType() { final BasicType booleanType = this.booleanType; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java index f42d060a74..d5534b3d63 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java @@ -16,6 +16,7 @@ import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmTreeCreationLogger; +import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder; import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection; import org.hibernate.query.sqm.tree.predicate.SqmInPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; @@ -32,6 +33,11 @@ public abstract class AbstractSqmExpression extends AbstractJpaSelection i super( type, criteriaBuilder ); } + @Override + public SqmCriteriaNodeBuilder nodeBuilder() { + return (SqmCriteriaNodeBuilder) super.nodeBuilder(); + } + @Override public void applyInferableType(SqmExpressable type) { // if ( type == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java index 1b8efd44de..23a5728860 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractNegatableSqmPredicate.java @@ -33,10 +33,16 @@ public abstract class AbstractNegatableSqmPredicate extends AbstractSqmPredicate this.negated = !this.negated; } + protected abstract SqmNegatablePredicate createNegatedNode(); + @Override public SqmNegatablePredicate not() { // in certain cases JPA required that this always return - // a new instance. we may need to allow for that here (compliance?) + // a new instance. + if ( nodeBuilder().isJpaQueryComplianceEnabled() ) { + return createNegatedNode(); + } + negate(); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java index 9ad73db736..94b5055811 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java @@ -8,12 +8,12 @@ package org.hibernate.query.sqm.tree.predicate; import java.util.Collections; import java.util.List; -import jakarta.persistence.criteria.Expression; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression; -import org.hibernate.type.StandardBasicTypes; + +import jakarta.persistence.criteria.Expression; /** * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java index e796d173ed..a8b8fcdae0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBetweenPredicate.java @@ -8,8 +8,8 @@ package org.hibernate.query.sqm.tree.predicate; import org.hibernate.query.internal.QueryHelper; import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SemanticQueryWalker; +import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.tree.expression.SqmExpression; /** @@ -70,4 +70,9 @@ public class SqmBetweenPredicate extends AbstractNegatableSqmPredicate { sb.append( " and " ); upperBound.appendHqlString( sb ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmBetweenPredicate( expression, lowerBound, upperBound, ! isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java index 5eabc927a3..3ef31fd6a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java @@ -22,8 +22,17 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression; public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate { private final SqmExpression booleanExpression; - public SqmBooleanExpressionPredicate(SqmExpression booleanExpression, NodeBuilder nodeBuilder) { - super( nodeBuilder ); + public SqmBooleanExpressionPredicate( + SqmExpression booleanExpression, + NodeBuilder nodeBuilder) { + this( booleanExpression, false, nodeBuilder ); + } + + public SqmBooleanExpressionPredicate( + SqmExpression booleanExpression, + boolean negated, + NodeBuilder nodeBuilder) { + super( negated, nodeBuilder ); assert booleanExpression.getNodeType() != null; final Class expressionJavaType = booleanExpression.getNodeType().getExpressableJavaTypeDescriptor().getJavaTypeClass(); @@ -50,4 +59,9 @@ public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate public void appendHqlString(StringBuilder sb) { booleanExpression.appendHqlString( sb ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmBooleanExpressionPredicate( booleanExpression, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java index 5515638487..8e9f99d790 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java @@ -40,6 +40,13 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate { rightHandExpression.applyInferableType( expressableType ); } + private SqmComparisonPredicate(SqmComparisonPredicate affirmativeForm) { + super( true, affirmativeForm.nodeBuilder() ); + this.leftHandExpression = affirmativeForm.leftHandExpression; + this.rightHandExpression = affirmativeForm.rightHandExpression; + this.operator = affirmativeForm.operator; + } + public SqmExpression getLeftHandExpression() { return leftHandExpression; } @@ -53,13 +60,13 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate { } @Override - public boolean isNegated() { - return false; + public void negate() { + this.operator = this.operator.negated(); } @Override - public void negate() { - this.operator = this.operator.negated(); + protected SqmNegatablePredicate createNegatedNode() { + return new SqmComparisonPredicate( this ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java index 3aa6c9bda5..d066e412d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmEmptinessPredicate.java @@ -43,4 +43,9 @@ public class SqmEmptinessPredicate extends AbstractNegatableSqmPredicate { sb.append( " is empty" ); } } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmEmptinessPredicate( pluralPath, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java index e7da3d7651..71939b01fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmExistsPredicate.java @@ -19,7 +19,14 @@ public class SqmExistsPredicate extends AbstractNegatableSqmPredicate { public SqmExistsPredicate( SqmExpression expression, NodeBuilder nodeBuilder) { - super( nodeBuilder ); + this( expression, false, nodeBuilder ); + } + + public SqmExistsPredicate( + SqmExpression expression, + boolean negated, + NodeBuilder nodeBuilder) { + super( negated, nodeBuilder ); this.expression = expression; expression.applyInferableType( expression.getNodeType() ); @@ -44,4 +51,9 @@ public class SqmExistsPredicate extends AbstractNegatableSqmPredicate { } expression.appendHqlString( sb ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmExistsPredicate( expression, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java index c8c6bc982c..907326aff2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInListPredicate.java @@ -139,4 +139,9 @@ public class SqmInListPredicate extends AbstractNegatableSqmPredicate impleme } sb.append( ')' ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmInListPredicate<>( testExpression, listExpressions, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java index 3cd9e4ce2c..e2ac2e3f97 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmInSubQueryPredicate.java @@ -92,4 +92,14 @@ public class SqmInSubQueryPredicate extends AbstractNegatableSqmPredicate imp sb.append( " in " ); subQueryExpression.appendHqlString( sb ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmInSubQueryPredicate<>( + testExpression, + subQueryExpression, + !isNegated(), + nodeBuilder() + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java index c11f78bdb3..cb584d048e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmLikePredicate.java @@ -100,4 +100,9 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate { escapeCharacter.appendHqlString( sb ); } } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmLikePredicate( matchExpression, pattern, escapeCharacter, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java index 4a8c4a1ca0..82602aa5ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmMemberOfPredicate.java @@ -56,4 +56,9 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate { sb.append( " member of " ); pluralPath.appendHqlString( sb ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmMemberOfPredicate( leftHandExpression, pluralPath, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java index 052dd0223b..077bffbfc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNegatedPredicate.java @@ -44,4 +44,9 @@ public class SqmNegatedPredicate extends AbstractNegatableSqmPredicate { wrappedPredicate.appendHqlString( sb ); sb.append( ')' ); } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmNegatedPredicate( this, nodeBuilder() ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java index 83e03c6427..9f9d939ff7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmNullnessPredicate.java @@ -44,4 +44,9 @@ public class SqmNullnessPredicate extends AbstractNegatableSqmPredicate { sb.append( " is null" ); } } + + @Override + protected SqmNegatablePredicate createNegatedNode() { + return new SqmNullnessPredicate( expression, !isNegated(), nodeBuilder() ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/LocateTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/LocateTests.java new file mode 100644 index 0000000000..ba722822c2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/LocateTests.java @@ -0,0 +1,74 @@ +/* + * 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.query.criteria; + +import java.util.List; + +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.criteria.JpaRoot; + +import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@DomainModel( annotatedClasses = EntityOfBasics.class ) +@SessionFactory +public class LocateTests { + + @Test + public void simpleLocateTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final HibernateCriteriaBuilder nodeBuilder = session.getFactory().getCriteriaBuilder(); + final JpaCriteriaQuery criteria = nodeBuilder.createQuery( Integer.class ); + final JpaRoot root = criteria.from( EntityOfBasics.class ); + criteria.select( root.get( "id" ) ); + + criteria.where( + nodeBuilder.greaterThan( + nodeBuilder.locate( + root.get( "theString" ), + nodeBuilder.literal("def") + ), + 0 + ) + ); + + final List list = session.createQuery( criteria ).list(); + assertThat( list ).hasSize( 1 ); + assertThat( list.get( 0 ) ).isEqualTo( 2 ); + } ); + } + + @BeforeEach + public void createTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final EntityOfBasics entity1 = new EntityOfBasics( 1 ); + entity1.setTheString( "abc" ); + session.persist( entity1 ); + + final EntityOfBasics entity2 = new EntityOfBasics( 2 ); + entity2.setTheString( "def" ); + session.persist( entity2 ); + } ); + } + + @BeforeEach + public void dropTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + session.createQuery( "delete EntityOfBasics" ).executeUpdate(); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/MultiSelectTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/MultiSelectTests.java index b96d3d1205..eb67b65f6e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/MultiSelectTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/MultiSelectTests.java @@ -217,6 +217,26 @@ public class MultiSelectTests { } ); } + @Test + public void tupleSelectionArrayTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final CriteriaBuilder nodeBuilder = session.getFactory().getNodeBuilder(); + + final CriteriaQuery criteria = nodeBuilder.createTupleQuery(); + final Root root = criteria.from( BasicEntity.class ); + + Selection[] s = { root.get("id"), root.get("data") }; + criteria.select(nodeBuilder.tuple(s)); + + final List results = session.createQuery( criteria ).list(); + assertThat( results ).hasSize( 1 ); + final Tuple firstResult = results.get( 0 ); + assertThat( firstResult.getElements() ).hasSize( 2 ); + assertThat( firstResult.get(0) ).isEqualTo( 1 ); + assertThat( firstResult.get(1) ).isEqualTo( "abc" ); + } ); + } + @BeforeEach public void createTestData(SessionFactoryScope scope) { scope.inTransaction( (session) -> session.persist( new BasicEntity( 1, "abc" ) ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NegationTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NegationTests.java new file mode 100644 index 0000000000..1b4c55c95d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/criteria/NegationTests.java @@ -0,0 +1,55 @@ +/* + * 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.query.criteria; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaPredicate; + +import org.hibernate.testing.orm.domain.gambit.BasicEntity; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry( + settings = @Setting( name = AvailableSettings.JPA_QUERY_COMPLIANCE, value = "true" ) +) +@DomainModel( annotatedClasses = BasicEntity.class ) +@SessionFactory +public class NegationTests { + @Test + public void simpleTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final HibernateCriteriaBuilder nodeBuilder = session.getFactory().getCriteriaBuilder(); + final JpaPredicate equality = nodeBuilder.equal( nodeBuilder.literal( 1 ), nodeBuilder.literal( 1 ) ); + final JpaPredicate inequality = equality.not(); + assertThat( equality ).isNotSameAs( inequality ); + assertThat( equality.isNegated() ).isFalse(); + assertThat( inequality.isNegated() ).isTrue(); + } ); + } + + @BeforeEach + public void createTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> session.persist( new BasicEntity( 1, "abc" ) ) ); + } + + @AfterEach + public void dropTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> session.createQuery( "delete BasicEntity" ).executeUpdate() ); + } +}