HHH-17375 Support array on RHS of in predicate

This commit is contained in:
Christian Beikov 2024-05-08 19:19:40 +02:00
parent 5c6a2f4a7d
commit dcedc5cf18
6 changed files with 66 additions and 1 deletions

View File

@ -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-overlaps-functions]]
[[hql-array-intersects-functions]] [[hql-array-intersects-functions]]
===== `array_intersects()` and `array_intersects_nullable()` ===== `array_intersects()` and `array_intersects_nullable()`

View File

@ -706,6 +706,7 @@ inList
| LEFT_PAREN (expressionOrPredicate (COMMA expressionOrPredicate)*)? RIGHT_PAREN# ExplicitTupleInList | LEFT_PAREN (expressionOrPredicate (COMMA expressionOrPredicate)*)? RIGHT_PAREN# ExplicitTupleInList
| LEFT_PAREN subquery RIGHT_PAREN # SubqueryInList | LEFT_PAREN subquery RIGHT_PAREN # SubqueryInList
| parameter # ParamInList | parameter # ParamInList
| expression # ArrayInList
; ;
/** /**

View File

@ -2846,6 +2846,28 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
creationContext.getNodeBuilder() 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<Boolean> contains = getFunctionDescriptor( "array_contains" ).generateSqmExpression(
asList( arrayExpr, testExpression ),
null,
creationContext.getQueryEngine()
);
return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() );
}
else { else {
throw new ParsingException( "Unexpected IN predicate type [" + ctx.getClass().getSimpleName() + "] : " + ctx.getText() ); throw new ParsingException( "Unexpected IN predicate type [" + ctx.getClass().getSimpleName() + "] : " + ctx.getText() );
} }

View File

@ -211,4 +211,16 @@ public class ArrayContainsArrayTest {
} ); } );
} }
@Test
public void testInArraySyntax(SessionFactoryScope scope) {
scope.inSession( em -> {
//tag::hql-array-in-array-hql-example[]
List<EntityWithArrays> 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() );
} );
}
} }

View File

@ -145,4 +145,16 @@ public class ArrayContainsTest {
} ); } );
} }
@Test
public void testInSyntax(SessionFactoryScope scope) {
scope.inSession( em -> {
//tag::hql-array-in-hql-example[]
List<EntityWithArrays> 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() );
} );
}
} }

View File

@ -128,7 +128,7 @@ Plenty of syntax sugar for array operations was added:
|Support casting array to string |Support casting array to string
|`array_contains(array, element)` |`array_contains(array, element)`
|`array contains element` |`array contains element` or `element in array`
|Contains predicate for containment check |Contains predicate for containment check
|`array_intersects(array, array(1, 2))` |`array_intersects(array, array(1, 2))`