HHH-17375 Introduce contains predicate for easy array containment checking
This commit is contained in:
parent
64dd9e657c
commit
6c34a0a4a6
|
@ -1400,6 +1400,26 @@ include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-cont
|
|||
----
|
||||
====
|
||||
|
||||
Alternatively, it's also possible to check for containment with the `contains` predicate,
|
||||
where the left hand side of the predicate is the array and the right hand side the value(s) to check.
|
||||
This is syntax sugar that translates to the `array_contains` function.
|
||||
|
||||
[[hql-array-contains-hql-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-hql-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-array-contains-array-hql-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-hql-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-array-overlaps-functions]]
|
||||
===== `array_overlaps()` and `array_overlaps_nullable()`
|
||||
|
||||
|
@ -1831,6 +1851,20 @@ include::{example-dir-hql}/HQLTest.java[tags=hql-collection-expressions-in-examp
|
|||
----
|
||||
====
|
||||
|
||||
[[hql-contains-predicate]]
|
||||
==== `contains`
|
||||
|
||||
The `contains` predicates evaluates to true if the value to its right is contained in the value to its left.
|
||||
Currently, this predicate only works with an array typed expression on the left side.
|
||||
|
||||
[[hql-contains-predicate-bnf]]
|
||||
[source, antlrv4, indent=0]
|
||||
----
|
||||
include::{extrasdir}/predicate_contains_bnf.txt[]
|
||||
----
|
||||
|
||||
For further details, refer to the <<hql-array-contains-example,`array_contains` section>>.
|
||||
|
||||
[[hql-relational-comparisons-subqueries]]
|
||||
==== Relational operators and subqueries
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
expression "NOT"? "CONTAINS" expression
|
|
@ -161,6 +161,7 @@ COLLATE : [cC] [oO] [lL] [lL] [aA] [tT] [eE];
|
|||
COLUMN : [cC] [oO] [lL] [uU] [mM] [nN];
|
||||
CONFLICT : [cC] [oO] [nN] [fF] [lL] [iI] [cC] [tT];
|
||||
CONSTRAINT : [cC] [oO] [nN] [sS] [tT] [rR] [aA] [iI] [nN] [tT];
|
||||
CONTAINS : [cC] [oO] [nN] [tT] [aA] [iI] [nN] [sS];
|
||||
COUNT : [cC] [oO] [uU] [nN] [tT];
|
||||
CROSS : [cC] [rR] [oO] [sS] [sS];
|
||||
CUBE : [cC] [uU] [bB] [eE];
|
||||
|
|
|
@ -673,6 +673,7 @@ predicate
|
|||
| expression NOT? IN inList # InPredicate
|
||||
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
|
||||
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate
|
||||
| expression NOT? CONTAINS expression # ContainsPredicate
|
||||
| expression comparisonOperator expression # ComparisonPredicate
|
||||
| EXISTS collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN # ExistsCollectionPartPredicate
|
||||
| EXISTS expression # ExistsPredicate
|
||||
|
@ -1648,6 +1649,7 @@ rollup
|
|||
| COLUMN
|
||||
| CONFLICT
|
||||
| CONSTRAINT
|
||||
| CONTAINS
|
||||
| COUNT
|
||||
| CROSS
|
||||
| CUBE
|
||||
|
|
|
@ -95,6 +95,7 @@ import org.hibernate.query.sqm.UnaryArithmeticOperator;
|
|||
import org.hibernate.query.sqm.UnknownEntityException;
|
||||
import org.hibernate.query.sqm.function.FunctionKind;
|
||||
import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.internal.ParameterCollector;
|
||||
import org.hibernate.query.sqm.internal.SqmCreationProcessingStateImpl;
|
||||
|
@ -2640,6 +2641,26 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPredicate visitContainsPredicate(HqlParser.ContainsPredicateContext ctx) {
|
||||
final boolean negated = ctx.NOT() != null;
|
||||
final SqmExpression<?> lhs = (SqmExpression<?>) ctx.expression( 0 ).accept( this );
|
||||
final SqmExpression<?> rhs = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
|
||||
final SqmExpressible<?> lhsExpressible = lhs.getExpressible();
|
||||
if ( lhsExpressible != null && !( lhsExpressible.getSqmType() instanceof BasicPluralType<?, ?>) ) {
|
||||
throw new SemanticException(
|
||||
"First operand for contains predicate must be a basic plural type expression, but found: " + lhsExpressible.getSqmType(),
|
||||
query
|
||||
);
|
||||
}
|
||||
final SelfRenderingSqmFunction<Boolean> contains = getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
asList( lhs, rhs ),
|
||||
null,
|
||||
creationContext.getQueryEngine()
|
||||
);
|
||||
return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPredicate visitLikePredicate(HqlParser.LikePredicateContext ctx) {
|
||||
final boolean negated = ctx.NOT() != null;
|
||||
|
|
|
@ -199,4 +199,16 @@ public class ArrayContainsArrayTest {
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArraySyntax(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-contains-array-hql-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where e.theArray contains ['abc', 'def']", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
//end::hql-array-contains-array-hql-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -133,4 +133,16 @@ public class ArrayContainsTest {
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsSyntax(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-contains-hql-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where e.theArray contains 'abc'", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
//end::hql-array-contains-hql-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue