diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc index f1fd303c12..a83225c585 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc @@ -1420,6 +1420,24 @@ include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-cont ---- ==== +In addition to that, it is also possible to use the `in` predicate with arrays. + +[[hql-array-in-hql-example]] +==== +[source, JAVA, indent=0] +---- +include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-in-hql-example] +---- +==== + +[[hql-array-in-array-hql-example]] +==== +[source, JAVA, indent=0] +---- +include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-in-array-hql-example] +---- +==== + [[hql-array-overlaps-functions]] [[hql-array-intersects-functions]] ===== `array_intersects()` and `array_intersects_nullable()` diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 index 7cee3e889f..d8ef2153fc 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 @@ -706,6 +706,7 @@ inList | LEFT_PAREN (expressionOrPredicate (COMMA expressionOrPredicate)*)? RIGHT_PAREN# ExplicitTupleInList | LEFT_PAREN subquery RIGHT_PAREN # SubqueryInList | parameter # ParamInList + | expression # ArrayInList ; /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index acdd97c30c..d7e1de9d91 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -2846,6 +2846,28 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem creationContext.getNodeBuilder() ); } + else if ( inListContext instanceof HqlParser.ArrayInListContext ) { + if ( getCreationOptions().useStrictJpaCompliance() ) { + throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION ); + } + final HqlParser.ArrayInListContext arrayInListContext = + (HqlParser.ArrayInListContext) inListContext; + + final SqmExpression arrayExpr = (SqmExpression) arrayInListContext.expression().accept( this ); + final SqmExpressible arrayExpressible = arrayExpr.getExpressible(); + if ( arrayExpressible != null && !( arrayExpressible.getSqmType() instanceof BasicPluralType) ) { + throw new SemanticException( + "Right operand for in-array predicate must be a basic plural type expression, but found: " + arrayExpressible.getSqmType(), + query + ); + } + final SelfRenderingSqmFunction contains = getFunctionDescriptor( "array_contains" ).generateSqmExpression( + asList( arrayExpr, testExpression ), + null, + creationContext.getQueryEngine() + ); + return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() ); + } else { throw new ParsingException( "Unexpected IN predicate type [" + ctx.getClass().getSimpleName() + "] : " + ctx.getText() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java index 96f47df597..abf84a852e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java @@ -211,4 +211,16 @@ public class ArrayContainsArrayTest { } ); } + @Test + public void testInArraySyntax(SessionFactoryScope scope) { + scope.inSession( em -> { + //tag::hql-array-in-array-hql-example[] + List results = em.createQuery( "from EntityWithArrays e where ['abc', 'def'] in e.theArray", EntityWithArrays.class ) + .getResultList(); + //end::hql-array-in-array-hql-example[] + assertEquals( 1, results.size() ); + assertEquals( 2L, results.get( 0 ).getId() ); + } ); + } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java index 5cd28ecdc7..2167a8ed5a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java @@ -145,4 +145,16 @@ public class ArrayContainsTest { } ); } + @Test + public void testInSyntax(SessionFactoryScope scope) { + scope.inSession( em -> { + //tag::hql-array-in-hql-example[] + List results = em.createQuery( "from EntityWithArrays e where 'abc' in e.theArray", EntityWithArrays.class ) + .getResultList(); + //end::hql-array-in-hql-example[] + assertEquals( 1, results.size() ); + assertEquals( 2L, results.get( 0 ).getId() ); + } ); + } + } diff --git a/release-announcement.adoc b/release-announcement.adoc index 7437439809..a137cb1cb5 100644 --- a/release-announcement.adoc +++ b/release-announcement.adoc @@ -128,7 +128,7 @@ Plenty of syntax sugar for array operations was added: |Support casting array to string |`array_contains(array, element)` -|`array contains element` +|`array contains element` or `element in array` |Contains predicate for containment check |`array_intersects(array, array(1, 2))`