HHH-17375 Introduce intersects predicate for easy array_intersects, the replacement of array_overlaps

This commit is contained in:
Christian Beikov 2024-05-07 13:56:28 +02:00
parent 6c34a0a4a6
commit 5c6a2f4a7d
28 changed files with 562 additions and 156 deletions

View File

@ -1191,8 +1191,8 @@ The following functions deal with SQL array types, which are not supported on ev
| `array_append()` | Appends element to array
| `array_contains()` | Whether an array contains element(s)
| `array_contains_nullable()` | Whether an array contains element(s), supporting `null` elements
| `array_overlaps()` | Whether an array holds at least one element of another array
| `array_overlaps_nullable()` | Whether an array holds at least one element of another array, supporting `null` elements
| `array_intersects()` | Whether an array holds at least one element of another array
| `array_intersects_nullable()` | Whether an array holds at least one element of another array, supporting `null` elements
| `array_get()` | Accesses the element of an array by index
| `array_set()` | Creates array copy with given element at given index
| `array_remove()` | Creates array copy with given element removed
@ -1421,26 +1421,41 @@ include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-cont
====
[[hql-array-overlaps-functions]]
===== `array_overlaps()` and `array_overlaps_nullable()`
[[hql-array-intersects-functions]]
===== `array_intersects()` and `array_intersects_nullable()`
Checks if the first array argument any of the elements of the second array argument.
Returns `null` if either of the arguments is `null`. The result of `array_overlaps`
Returns `null` if either of the arguments is `null`. The result of `array_intersects`
is undefined when the second array argument contains a `null` array element.
Only `array_overlaps_nullable` is guaranteed to produce correct results for `null` array elements.
Only `array_intersects_nullable` is guaranteed to produce correct results for `null` array elements.
[[hql-array-overlaps-example]]
[[hql-array-intersects-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayOverlapsTest.java[tags=hql-array-overlaps-example]
include::{array-example-dir-hql}/ArrayIntersectsTest.java[tags=hql-array-intersects-example]
----
====
[[hql-array-overlaps-nullable-example]]
[[hql-array-intersects-nullable-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayOverlapsTest.java[tags=hql-array-overlaps-nullable-example]
include::{array-example-dir-hql}/ArrayIntersectsTest.java[tags=hql-array-intersects-nullable-example]
----
====
Alternatively, it's also possible to check for intersection with the `intersects` predicate.
This is syntax sugar that translates to the `array_intersects` function.
[[hql-array-overlaps-hql-example]]
[[hql-array-intersects-hql-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayIntersectsTest.java[tags=hql-array-intersects-hql-example]
----
====
@ -1865,6 +1880,20 @@ include::{extrasdir}/predicate_contains_bnf.txt[]
For further details, refer to the <<hql-array-contains-example,`array_contains` section>>.
[[hql-intersects-predicate]]
==== `intersects`
The `intersects` predicates evaluates to true if the value to its left has at least one element common with the value to its right.
Currently, this predicate only works with an array typed expressions.
[[hql-intersects-predicate-bnf]]
[source, antlrv4, indent=0]
----
include::{extrasdir}/predicate_intersects_bnf.txt[]
----
For further details, refer to the <<hql-array-intersects-example,`array_intersects` section>>.
[[hql-relational-comparisons-subqueries]]
==== Relational operators and subqueries

View File

@ -0,0 +1 @@
expression "NOT"? "INTERSECTS" expression

View File

@ -62,7 +62,6 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
@ -468,7 +467,7 @@ public class CockroachLegacyDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContains_postgresql();
functionFactory.arrayOverlaps_postgresql();
functionFactory.arrayIntersects_postgresql();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -384,7 +384,7 @@ public class H2LegacyDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContains_h2( getMaximumArraySize() );
functionFactory.arrayOverlaps_h2( getMaximumArraySize() );
functionFactory.arrayIntersects_h2( getMaximumArraySize() );
functionFactory.arrayGet_h2();
functionFactory.arraySet_h2( getMaximumArraySize() );
functionFactory.arrayRemove_h2( getMaximumArraySize() );

View File

@ -259,7 +259,7 @@ public class HSQLLegacyDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContains_hsql();
functionFactory.arrayOverlaps_hsql();
functionFactory.arrayIntersects_hsql();
functionFactory.arrayGet_unnest();
functionFactory.arraySet_hsql();
functionFactory.arrayRemove_hsql();

View File

@ -101,7 +101,6 @@ import org.hibernate.type.NullType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
@ -308,7 +307,7 @@ public class OracleLegacyDialect extends Dialect {
functionFactory.arrayPrepend_oracle();
functionFactory.arrayAppend_oracle();
functionFactory.arrayContains_oracle();
functionFactory.arrayOverlaps_oracle();
functionFactory.arrayIntersects_oracle();
functionFactory.arrayGet_oracle();
functionFactory.arraySet_oracle();
functionFactory.arrayRemove_oracle();

View File

@ -77,7 +77,6 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -600,7 +599,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContains_postgresql();
functionFactory.arrayOverlaps_postgresql();
functionFactory.arrayIntersects_postgresql();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -216,6 +216,7 @@ INNER : [iI] [nN] [nN] [eE] [rR];
INSERT : [iI] [nN] [sS] [eE] [rR] [tT];
INSTANT : [iI] [nN] [sS] [tT] [aA] [nN] [tT];
INTERSECT : [iI] [nN] [tT] [eE] [rR] [sS] [eE] [cC] [tT];
INTERSECTS : [iI] [nN] [tT] [eE] [rR] [sS] [eE] [cC] [tT] [sS];
INTO : [iI] [nN] [tT] [oO];
IS : [iI] [sS];
JOIN : [jJ] [oO] [iI] [nN];

View File

@ -674,6 +674,7 @@ predicate
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate
| expression NOT? CONTAINS expression # ContainsPredicate
| expression NOT? INTERSECTS expression # IntersectsPredicate
| expression comparisonOperator expression # ComparisonPredicate
| EXISTS collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN # ExistsCollectionPartPredicate
| EXISTS expression # ExistsPredicate
@ -1706,6 +1707,7 @@ rollup
| INSERT
| INSTANT
| INTERSECT
| INTERSECTS
| INTO
| IS
| JOIN

View File

@ -469,7 +469,7 @@ public class CockroachDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContains_postgresql();
functionFactory.arrayOverlaps_postgresql();
functionFactory.arrayIntersects_postgresql();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -322,7 +322,7 @@ public class H2Dialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContains_h2( getMaximumArraySize() );
functionFactory.arrayOverlaps_h2( getMaximumArraySize() );
functionFactory.arrayIntersects_h2( getMaximumArraySize() );
functionFactory.arrayGet_h2();
functionFactory.arraySet_h2( getMaximumArraySize() );
functionFactory.arrayRemove_h2( getMaximumArraySize() );

View File

@ -199,7 +199,7 @@ public class HSQLDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContains_hsql();
functionFactory.arrayOverlaps_hsql();
functionFactory.arrayIntersects_hsql();
functionFactory.arrayGet_unnest();
functionFactory.arraySet_hsql();
functionFactory.arrayRemove_hsql();

View File

@ -84,7 +84,6 @@ import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -355,7 +354,7 @@ public class OracleDialect extends Dialect {
functionFactory.arrayPrepend_oracle();
functionFactory.arrayAppend_oracle();
functionFactory.arrayContains_oracle();
functionFactory.arrayOverlaps_oracle();
functionFactory.arrayIntersects_oracle();
functionFactory.arrayGet_oracle();
functionFactory.arraySet_oracle();
functionFactory.arrayRemove_oracle();

View File

@ -121,7 +121,7 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
"end loop; " +
"return 1; " +
"end;",
"create or replace function " + arrayTypeName + "_overlaps(haystack in " + arrayTypeName +
"create or replace function " + arrayTypeName + "_intersects(haystack in " + arrayTypeName +
", needle in " + arrayTypeName + ", nullable in number) return number deterministic is begin " +
"if haystack is null or needle is null then return null; end if; " +
"if needle.count = 0 then return 1; end if; " +
@ -296,7 +296,7 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
"drop function " + arrayTypeName + "_length",
"drop function " + arrayTypeName + "_concat",
"drop function " + arrayTypeName + "_contains",
"drop function " + arrayTypeName + "_overlaps",
"drop function " + arrayTypeName + "_intersects",
"drop function " + arrayTypeName + "_get",
"drop function " + arrayTypeName + "_set",
"drop function " + arrayTypeName + "_remove",

View File

@ -79,7 +79,6 @@ import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -652,7 +651,7 @@ public class PostgreSQLDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContains_postgresql();
functionFactory.arrayOverlaps_postgresql();
functionFactory.arrayIntersects_postgresql();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -21,8 +21,8 @@ import org.hibernate.dialect.function.array.ArrayConcatFunction;
import org.hibernate.dialect.function.array.ArrayConstructorFunction;
import org.hibernate.dialect.function.array.ArrayContainsOperatorFunction;
import org.hibernate.dialect.function.array.ArrayContainsUnnestFunction;
import org.hibernate.dialect.function.array.ArrayOverlapsOperatorFunction;
import org.hibernate.dialect.function.array.ArrayOverlapsUnnestFunction;
import org.hibernate.dialect.function.array.ArrayIntersectsOperatorFunction;
import org.hibernate.dialect.function.array.ArrayIntersectsUnnestFunction;
import org.hibernate.dialect.function.array.ArrayGetUnnestFunction;
import org.hibernate.dialect.function.array.ArrayRemoveIndexUnnestFunction;
import org.hibernate.dialect.function.array.ArrayReplaceUnnestFunction;
@ -34,7 +34,7 @@ import org.hibernate.dialect.function.array.CockroachArrayFillFunction;
import org.hibernate.dialect.function.array.ElementViaArrayArgumentReturnTypeResolver;
import org.hibernate.dialect.function.array.H2ArrayContainsFunction;
import org.hibernate.dialect.function.array.H2ArrayFillFunction;
import org.hibernate.dialect.function.array.H2ArrayOverlapsFunction;
import org.hibernate.dialect.function.array.H2ArrayIntersectsFunction;
import org.hibernate.dialect.function.array.H2ArrayPositionFunction;
import org.hibernate.dialect.function.array.H2ArrayPositionsFunction;
import org.hibernate.dialect.function.array.H2ArrayRemoveFunction;
@ -52,7 +52,7 @@ import org.hibernate.dialect.function.array.HSQLArrayToStringFunction;
import org.hibernate.dialect.function.array.OracleArrayConcatElementFunction;
import org.hibernate.dialect.function.array.OracleArrayConcatFunction;
import org.hibernate.dialect.function.array.OracleArrayFillFunction;
import org.hibernate.dialect.function.array.OracleArrayOverlapsFunction;
import org.hibernate.dialect.function.array.OracleArrayIntersectsFunction;
import org.hibernate.dialect.function.array.OracleArrayGetFunction;
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
import org.hibernate.dialect.function.array.OracleArrayPositionFunction;
@ -2714,53 +2714,61 @@ public class CommonFunctionFactory {
}
/**
* H2 array_overlaps() function
* H2 array_intersects() function
*/
public void arrayOverlaps_h2(int maximumArraySize) {
public void arrayIntersects_h2(int maximumArraySize) {
functionRegistry.register(
"array_overlaps",
new H2ArrayOverlapsFunction( false, maximumArraySize, typeConfiguration )
"array_intersects",
new H2ArrayIntersectsFunction( false, maximumArraySize, typeConfiguration )
);
functionRegistry.register(
"array_overlaps_nullable",
new H2ArrayOverlapsFunction( true, maximumArraySize, typeConfiguration )
"array_intersects_nullable",
new H2ArrayIntersectsFunction( true, maximumArraySize, typeConfiguration )
);
functionRegistry.registerAlternateKey( "array_overlaps", "array_intersects" );
functionRegistry.registerAlternateKey( "array_overlaps_nullable", "array_intersects_nullable" );
}
/**
* HSQL array_overlaps() function
* HSQL array_intersects() function
*/
public void arrayOverlaps_hsql() {
public void arrayIntersects_hsql() {
functionRegistry.register(
"array_overlaps",
new ArrayOverlapsUnnestFunction( false, typeConfiguration )
"array_intersects",
new ArrayIntersectsUnnestFunction( false, typeConfiguration )
);
functionRegistry.register(
"array_overlaps_nullable",
new ArrayOverlapsUnnestFunction( true, typeConfiguration )
"array_intersects_nullable",
new ArrayIntersectsUnnestFunction( true, typeConfiguration )
);
functionRegistry.registerAlternateKey( "array_overlaps", "array_intersects" );
functionRegistry.registerAlternateKey( "array_overlaps_nullable", "array_intersects_nullable" );
}
/**
* CockroachDB and PostgreSQL array overlaps operator
* CockroachDB and PostgreSQL array intersects operator
*/
public void arrayOverlaps_postgresql() {
functionRegistry.register( "array_overlaps", new ArrayOverlapsOperatorFunction( false, typeConfiguration ) );
functionRegistry.register( "array_overlaps_nullable", new ArrayOverlapsOperatorFunction( true, typeConfiguration ) );
public void arrayIntersects_postgresql() {
functionRegistry.register( "array_intersects", new ArrayIntersectsOperatorFunction( false, typeConfiguration ) );
functionRegistry.register( "array_intersects_nullable", new ArrayIntersectsOperatorFunction( true, typeConfiguration ) );
functionRegistry.registerAlternateKey( "array_overlaps", "array_intersects" );
functionRegistry.registerAlternateKey( "array_overlaps_nullable", "array_intersects_nullable" );
}
/**
* Oracle array_overlaps() function
* Oracle array_intersects() function
*/
public void arrayOverlaps_oracle() {
public void arrayIntersects_oracle() {
functionRegistry.register(
"array_overlaps",
new OracleArrayOverlapsFunction( typeConfiguration, false )
"array_intersects",
new OracleArrayIntersectsFunction( typeConfiguration, false )
);
functionRegistry.register(
"array_overlaps_nullable",
new OracleArrayOverlapsFunction( typeConfiguration, true )
"array_intersects_nullable",
new OracleArrayIntersectsFunction( typeConfiguration, true )
);
functionRegistry.registerAlternateKey( "array_overlaps", "array_intersects" );
functionRegistry.registerAlternateKey( "array_overlaps_nullable", "array_intersects_nullable" );
}
/**

View File

@ -13,16 +13,16 @@ import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolv
import org.hibernate.type.spi.TypeConfiguration;
/**
* Encapsulates the validator, return type and argument type resolvers for the array_overlaps function.
* Encapsulates the validator, return type and argument type resolvers for the array_intersects function.
* Subclasses only have to implement the rendering.
*/
public abstract class AbstractArrayOverlapsFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
public abstract class AbstractArrayIntersectsFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
protected final boolean nullable;
public AbstractArrayOverlapsFunction(boolean nullable, TypeConfiguration typeConfiguration) {
public AbstractArrayIntersectsFunction(boolean nullable, TypeConfiguration typeConfiguration) {
super(
"array_overlaps" + ( nullable ? "_nullable" : "" ),
"array_intersects" + ( nullable ? "_nullable" : "" ),
StandardArgumentsValidators.composite(
StandardArgumentsValidators.exactly( 2 ),
ArraysOfSameTypeArgumentValidator.INSTANCE

View File

@ -16,11 +16,11 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Array overlaps function that uses the PostgreSQL {@code &&} operator.
* Array intersects function that uses the PostgreSQL {@code &&} operator.
*/
public class ArrayOverlapsOperatorFunction extends ArrayOverlapsUnnestFunction {
public class ArrayIntersectsOperatorFunction extends ArrayIntersectsUnnestFunction {
public ArrayOverlapsOperatorFunction(boolean nullable, TypeConfiguration typeConfiguration) {
public ArrayIntersectsOperatorFunction(boolean nullable, TypeConfiguration typeConfiguration) {
super( nullable, typeConfiguration );
}

View File

@ -16,11 +16,11 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Implement the overlaps function by using {@code unnest}.
* Implement the intersects function by using {@code unnest}.
*/
public class ArrayOverlapsUnnestFunction extends AbstractArrayOverlapsFunction {
public class ArrayIntersectsUnnestFunction extends AbstractArrayIntersectsFunction {
public ArrayOverlapsUnnestFunction(boolean nullable, TypeConfiguration typeConfiguration) {
public ArrayIntersectsUnnestFunction(boolean nullable, TypeConfiguration typeConfiguration) {
super( nullable, typeConfiguration );
}

View File

@ -20,11 +20,11 @@ import org.hibernate.type.spi.TypeConfiguration;
* due to https://github.com/h2database/h2database/issues/1815.
* This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same.
*/
public class H2ArrayOverlapsFunction extends AbstractArrayOverlapsFunction {
public class H2ArrayIntersectsFunction extends AbstractArrayIntersectsFunction {
private final int maximumArraySize;
public H2ArrayOverlapsFunction(boolean nullable, int maximumArraySize, TypeConfiguration typeConfiguration) {
public H2ArrayIntersectsFunction(boolean nullable, int maximumArraySize, TypeConfiguration typeConfiguration) {
super( nullable, typeConfiguration );
this.maximumArraySize = maximumArraySize;
}

View File

@ -15,9 +15,9 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.spi.TypeConfiguration;
public class OracleArrayOverlapsFunction extends AbstractArrayOverlapsFunction {
public class OracleArrayIntersectsFunction extends AbstractArrayIntersectsFunction {
public OracleArrayOverlapsFunction(TypeConfiguration typeConfiguration, boolean nullable) {
public OracleArrayIntersectsFunction(TypeConfiguration typeConfiguration, boolean nullable) {
super( nullable, typeConfiguration );
}
@ -33,7 +33,7 @@ public class OracleArrayOverlapsFunction extends AbstractArrayOverlapsFunction {
walker.getSessionFactory().getTypeConfiguration()
);
sqlAppender.appendSql( arrayTypeName );
sqlAppender.append( "_overlaps(" );
sqlAppender.append( "_intersects(" );
haystackExpression.accept( walker );
sqlAppender.append( ',' );
sqlAstArguments.get( 1 ).accept( walker );

View File

@ -2796,49 +2796,121 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
* Whether one array has any elements common with another array.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersects(Expression, Expression)}
*/
@Incubating
<T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return arrayIntersects( arrayExpression1, arrayExpression2 );
}
/**
* Whether one array has any elements common with another array.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersects(Expression, T[])}
*/
@Incubating
<T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2) {
return arrayIntersects( arrayExpression1, array2 );
}
/**
* Whether one array has any elements common with another array.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersects(T[], Expression)}
*/
@Incubating
<T> JpaPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2) {
return arrayIntersects( array1, arrayExpression2 );
}
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersectsNullable(Expression, Expression)}
*/
@Incubating
<T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return arrayIntersectsNullable( arrayExpression1, arrayExpression2 );
}
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersectsNullable(Expression, T[])}
*/
@Incubating
<T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return arrayIntersectsNullable( arrayExpression1, array2 );
}
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #arrayIntersectsNullable(T[], Expression)}
*/
@Incubating
<T> JpaPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2);
@Deprecated(forRemoval = true)
default <T> JpaPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return arrayIntersectsNullable( array1, arrayExpression2 );
}
/**
* Whether one array has any elements common with another array.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersects(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
/**
* Whether one array has any elements common with another array.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersects(Expression<T[]> arrayExpression1, T[] array2);
/**
* Whether one array has any elements common with another array.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersects(T[] array1, Expression<T[]> arrayExpression2);
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, T[] array2);
/**
* Whether one array has any elements common with another array, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<T> JpaPredicate arrayIntersectsNullable(T[] array1, Expression<T[]> arrayExpression2);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Array functions for collection types
@ -3275,47 +3347,119 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersects(Expression, Expression)}
*/
@Incubating
<E> JpaPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.4
*/
@Incubating
<E> JpaPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.4
*/
@Incubating
<E> JpaPredicate collectionOverlaps(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
*/
@Incubating
<E> JpaPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
*/
@Incubating
<E> JpaPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
*/
@Incubating
<E> JpaPredicate collectionOverlapsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersects( collectionExpression1, collectionExpression2 );
}
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersects(Expression, Collection)}
*/
@Incubating
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2) {
return collectionIntersects( collectionExpression1, collection2 );
}
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersects(Collection, Expression)}
*/
@Incubating
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlaps(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersects( collection1, collectionExpression2 );
}
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersectsNullable(Expression, Expression)}
*/
@Incubating
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersectsNullable( collectionExpression1, collectionExpression2 );
}
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersectsNullable(Expression, Collection)}
*/
@Incubating
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2) {
return collectionIntersectsNullable( collectionExpression1, collection2 );
}
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.4
* @deprecated Replaced with {@link #collectionIntersectsNullable(Collection, Expression)}
*/
@Incubating
@Deprecated(forRemoval = true)
default <E> JpaPredicate collectionOverlapsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersectsNullable( collection1, collectionExpression2 );
}
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersects(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersects(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
/**
* Whether one basic collection has any elements common with another basic collection.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersects(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersectsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersectsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
/**
* Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements.
*
* @since 6.6
*/
@Incubating
<E> JpaPredicate collectionIntersectsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
}

View File

@ -2531,41 +2531,83 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayOverlaps( arrayExpression1, arrayExpression2 );
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2) {
return criteriaBuilder.arrayOverlaps( arrayExpression1, array2 );
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayOverlaps( array1, arrayExpression2 );
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayOverlapsNullable( arrayExpression1, arrayExpression2 );
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return criteriaBuilder.arrayOverlapsNullable( arrayExpression1, array2 );
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <T> JpaPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayOverlapsNullable( array1, arrayExpression2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersects(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayIntersects( arrayExpression1, arrayExpression2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersects(Expression<T[]> arrayExpression1, T[] array2) {
return criteriaBuilder.arrayIntersects( arrayExpression1, array2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersects(T[] array1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayIntersects( array1, arrayExpression2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayIntersectsNullable( arrayExpression1, arrayExpression2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return criteriaBuilder.arrayIntersectsNullable( arrayExpression1, array2 );
}
@Override
@Incubating
public <T> JpaPredicate arrayIntersectsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return criteriaBuilder.arrayIntersectsNullable( array1, arrayExpression2 );
}
@Override
@Incubating
public <E, C extends Collection<E>> JpaExpression<C> collectionLiteral(E... elements) {
@ -2985,6 +3027,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlaps(
Expression<? extends Collection<E>> collectionExpression1,
@ -2993,6 +3036,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlaps(
Expression<? extends Collection<E>> collectionExpression1,
@ -3001,6 +3045,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlaps(
Collection<E> collection1,
@ -3009,6 +3054,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlapsNullable(
Expression<? extends Collection<E>> collectionExpression1,
@ -3017,6 +3063,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlapsNullable(
Expression<? extends Collection<E>> collectionExpression1,
@ -3025,10 +3072,59 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
}
@Override
@Deprecated(forRemoval = true)
@Incubating
public <E> JpaPredicate collectionOverlapsNullable(
Collection<E> collection1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return criteriaBuilder.collectionOverlapsNullable( collection1, collectionExpression2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersects(
Expression<? extends Collection<E>> collectionExpression1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return criteriaBuilder.collectionIntersects( collectionExpression1, collectionExpression2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersects(
Expression<? extends Collection<E>> collectionExpression1,
Collection<? extends E> collection2) {
return criteriaBuilder.collectionIntersects( collectionExpression1, collection2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersects(
Collection<E> collection1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return criteriaBuilder.collectionIntersects( collection1, collectionExpression2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersectsNullable(
Expression<? extends Collection<E>> collectionExpression1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return criteriaBuilder.collectionIntersectsNullable( collectionExpression1, collectionExpression2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersectsNullable(
Expression<? extends Collection<E>> collectionExpression1,
Collection<? extends E> collection2) {
return criteriaBuilder.collectionIntersectsNullable( collectionExpression1, collection2 );
}
@Override
@Incubating
public <E> JpaPredicate collectionIntersectsNullable(
Collection<E> collection1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return criteriaBuilder.collectionIntersectsNullable( collection1, collectionExpression2 );
}
}

View File

@ -2661,6 +2661,26 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() );
}
@Override
public SqmPredicate visitIntersectsPredicate(HqlParser.IntersectsPredicateContext 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 intersects predicate must be a basic plural type expression, but found: " + lhsExpressible.getSqmType(),
query
);
}
final SelfRenderingSqmFunction<Boolean> contains = getFunctionDescriptor( "array_intersects" ).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;

View File

@ -283,22 +283,52 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
<T> SqmPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression);
@Override
<T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
default <T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return arrayIntersects( arrayExpression1, arrayExpression2 );
}
@Override
<T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2);
default <T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2) {
return arrayIntersects( arrayExpression1, array2 );
}
@Override
<T> SqmPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2);
default <T> SqmPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2) {
return arrayIntersects( array1, arrayExpression2 );
}
@Override
<T> SqmPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
default <T> SqmPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return arrayIntersectsNullable( arrayExpression1, arrayExpression2 );
}
@Override
<T> SqmPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2);
default <T> SqmPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return arrayIntersectsNullable( arrayExpression1, array2 );
}
@Override
<T> SqmPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2);
default <T> SqmPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return arrayIntersectsNullable( array1, arrayExpression2 );
}
@Override
<T> SqmPredicate arrayIntersects(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
@Override
<T> SqmPredicate arrayIntersects(Expression<T[]> arrayExpression1, T[] array2);
@Override
<T> SqmPredicate arrayIntersects(T[] array1, Expression<T[]> arrayExpression2);
@Override
<T> SqmPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2);
@Override
<T> SqmPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, T[] array2);
@Override
<T> SqmPredicate arrayIntersectsNullable(T[] array1, Expression<T[]> arrayExpression2);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Array functions for collection types
@ -463,22 +493,52 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
<E> SqmPredicate collectionContainsAllNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
@Override
<E> SqmPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
default <E> SqmPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersects( collectionExpression1, collectionExpression2 );
}
@Override
<E> SqmPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
default <E> SqmPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2) {
return collectionIntersects( collectionExpression1, collection2 );
}
@Override
<E> SqmPredicate collectionOverlaps(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
default <E> SqmPredicate collectionOverlaps(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersects( collection1, collectionExpression2 );
}
@Override
<E> SqmPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
default <E> SqmPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersectsNullable( collectionExpression1, collectionExpression2 );
}
@Override
<E> SqmPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
default <E> SqmPredicate collectionOverlapsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2) {
return collectionIntersectsNullable( collectionExpression1, collection2 );
}
@Override
<E> SqmPredicate collectionOverlapsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
default <E> SqmPredicate collectionOverlapsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2) {
return collectionIntersectsNullable( collection1, collectionExpression2 );
}
@Override
<E> SqmPredicate collectionIntersects(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
@Override
<E> SqmPredicate collectionIntersects(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
@Override
<E> SqmPredicate collectionIntersects(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
@Override
<E> SqmPredicate collectionIntersectsNullable(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2);
@Override
<E> SqmPredicate collectionIntersectsNullable(Expression<? extends Collection<E>> collectionExpression1, Collection<? extends E> collection2);
@Override
<E> SqmPredicate collectionIntersectsNullable(Collection<E> collection1, Expression<? extends Collection<? extends E>> collectionExpression2);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Covariant overrides

View File

@ -3987,8 +3987,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
public <T> SqmPredicate arrayIntersects(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( (SqmExpression<?>) arrayExpression1, (SqmExpression<?>) arrayExpression2 ),
null,
queryEngine
@ -3996,8 +3996,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, T[] array2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
public <T> SqmPredicate arrayIntersects(Expression<T[]> arrayExpression1, T[] array2) {
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( (SqmExpression<?>) arrayExpression1, value( array2, (SqmExpression<?>) arrayExpression1 ) ),
null,
queryEngine
@ -4005,8 +4005,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlaps(T[] array1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
public <T> SqmPredicate arrayIntersects(T[] array1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( value( array1, (SqmExpression<?>) arrayExpression2 ), (SqmExpression<?>) arrayExpression2 ),
null,
queryEngine
@ -4014,10 +4014,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlapsNullable(
public <T> SqmPredicate arrayIntersectsNullable(
Expression<T[]> arrayExpression1,
Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( (SqmExpression<?>) arrayExpression1, (SqmExpression<?>) arrayExpression2 ),
null,
queryEngine
@ -4025,8 +4025,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlapsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
public <T> SqmPredicate arrayIntersectsNullable(Expression<T[]> arrayExpression1, T[] array2) {
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( (SqmExpression<?>) arrayExpression1, value( array2, (SqmExpression<?>) arrayExpression1 ) ),
null,
queryEngine
@ -4034,8 +4034,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <T> SqmPredicate arrayOverlapsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
public <T> SqmPredicate arrayIntersectsNullable(T[] array1, Expression<T[]> arrayExpression2) {
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( value( array1, (SqmExpression<?>) arrayExpression2 ), (SqmExpression<?>) arrayExpression2 ),
null,
queryEngine
@ -4614,10 +4614,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlaps(
public <E> SqmPredicate collectionIntersects(
Expression<? extends Collection<E>> collectionExpression1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( (SqmExpression<?>) collectionExpression1, (SqmExpression<?>) collectionExpression2 ),
null,
queryEngine
@ -4625,10 +4625,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlaps(
public <E> SqmPredicate collectionIntersects(
Expression<? extends Collection<E>> collectionExpression1,
Collection<? extends E> collection2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( (SqmExpression<?>) collectionExpression1, value( collection2, (SqmExpression<?>) collectionExpression1 ) ),
null,
queryEngine
@ -4636,10 +4636,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlaps(
public <E> SqmPredicate collectionIntersects(
Collection<E> collection1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects" ).generateSqmExpression(
asList( value( collection1, (SqmExpression<?>) collectionExpression2 ), (SqmExpression<?>) collectionExpression2 ),
null,
queryEngine
@ -4647,10 +4647,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlapsNullable(
public <E> SqmPredicate collectionIntersectsNullable(
Expression<? extends Collection<E>> collectionExpression1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( (SqmExpression<?>) collectionExpression1, (SqmExpression<?>) collectionExpression2 ),
null,
queryEngine
@ -4658,10 +4658,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlapsNullable(
public <E> SqmPredicate collectionIntersectsNullable(
Expression<? extends Collection<E>> collectionExpression1,
Collection<? extends E> collection2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( (SqmExpression<?>) collectionExpression1, value( collection2, (SqmExpression<?>) collectionExpression1 ) ),
null,
queryEngine
@ -4669,10 +4669,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
}
@Override
public <E> SqmPredicate collectionOverlapsNullable(
public <E> SqmPredicate collectionIntersectsNullable(
Collection<E> collection1,
Expression<? extends Collection<? extends E>> collectionExpression2) {
return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression(
return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression(
asList( value( collection1, (SqmExpression<?>) collectionExpression2 ), (SqmExpression<?>) collectionExpression2 ),
null,
queryEngine

View File

@ -36,7 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsStructuralArrays.class)
// Clear the type cache, otherwise we might run into ORA-21700: object does not exist or is marked for delete
@BootstrapServiceRegistry(integrators = SharedDriverManagerTypeCacheClearingIntegrator.class)
public class ArrayOverlapsTest {
public class ArrayIntersectsTest {
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
@ -55,30 +55,30 @@ public class ArrayOverlapsTest {
}
@Test
public void testOverlapsFully(SessionFactoryScope scope) {
public void testIntersectsFully(SessionFactoryScope scope) {
scope.inSession( em -> {
//tag::hql-array-overlaps-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
//tag::hql-array-intersects-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_intersects(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
.getResultList();
//end::hql-array-overlaps-example[]
//end::hql-array-intersects-example[]
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
} );
}
@Test
public void testDoesNotOverlap(SessionFactoryScope scope) {
public void testDoesNotIntersect(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('xyz'))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_intersects(e.theArray, array('xyz'))", EntityWithArrays.class )
.getResultList();
assertEquals( 0, results.size() );
} );
}
@Test
public void testOverlaps(SessionFactoryScope scope) {
public void testIntersects(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_intersects(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
.getResultList();
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
@ -86,9 +86,9 @@ public class ArrayOverlapsTest {
}
@Test
public void testOverlapsNullFully(SessionFactoryScope scope) {
public void testIntersectsNullFully(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array(null))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_intersects_nullable(e.theArray, array(null))", EntityWithArrays.class )
.getResultList();
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
@ -96,12 +96,12 @@ public class ArrayOverlapsTest {
}
@Test
public void testOverlapsNull(SessionFactoryScope scope) {
public void testIntersectsNull(SessionFactoryScope scope) {
scope.inSession( em -> {
//tag::hql-array-overlaps-nullable-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array('xyz',null))", EntityWithArrays.class )
//tag::hql-array-intersects-nullable-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_intersects_nullable(e.theArray, array('xyz',null))", EntityWithArrays.class )
.getResultList();
//end::hql-array-overlaps-nullable-example[]
//end::hql-array-intersects-nullable-example[]
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
} );
@ -115,24 +115,24 @@ public class ArrayOverlapsTest {
final JpaRoot<EntityWithArrays> root = cq.from( EntityWithArrays.class );
cq.multiselect(
root.get( "id" ),
cb.arrayOverlaps( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
cb.arrayOverlaps( root.get( "theArray" ), new String[]{ "xyz" } ),
cb.arrayOverlaps( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) ),
cb.arrayOverlapsNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
cb.arrayOverlapsNullable( root.get( "theArray" ), new String[]{ "xyz" } ),
cb.arrayOverlapsNullable( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) )
cb.arrayIntersects( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
cb.arrayIntersects( root.get( "theArray" ), new String[]{ "xyz" } ),
cb.arrayIntersects( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) ),
cb.arrayIntersectsNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
cb.arrayIntersectsNullable( root.get( "theArray" ), new String[]{ "xyz" } ),
cb.arrayIntersectsNullable( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) )
);
em.createQuery( cq ).getResultList();
// Should all fail to compile
// cb.arrayOverlaps( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
// cb.arrayOverlaps( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
// cb.arrayOverlaps( new String[0], cb.literal( 1 ) );
// cb.arrayOverlaps( new Integer[0], cb.literal( "" ) );
// cb.arrayOverlapsNullable( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
// cb.arrayOverlapsNullable( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
// cb.arrayOverlapsNullable( new String[0], cb.literal( 1 ) );
// cb.arrayOverlapsNullable( new Integer[0], cb.literal( "" ) );
// cb.arrayIntersects( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
// cb.arrayIntersects( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
// cb.arrayIntersects( new String[0], cb.literal( 1 ) );
// cb.arrayIntersects( new Integer[0], cb.literal( "" ) );
// cb.arrayIntersectsNullable( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
// cb.arrayIntersectsNullable( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
// cb.arrayIntersectsNullable( new String[0], cb.literal( 1 ) );
// cb.arrayIntersectsNullable( new Integer[0], cb.literal( "" ) );
} );
}
@ -144,24 +144,36 @@ public class ArrayOverlapsTest {
final JpaRoot<EntityWithArrays> root = cq.from( EntityWithArrays.class );
cq.multiselect(
root.get( "id" ),
cb.collectionOverlaps( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionOverlaps( root.get( "theCollection" ), List.of( "xyz" ) ),
cb.collectionOverlaps( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionOverlapsNullable( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionOverlapsNullable( root.get( "theCollection" ), List.of( "xyz" ) ),
cb.collectionOverlapsNullable( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) )
cb.collectionIntersects( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionIntersects( root.get( "theCollection" ), List.of( "xyz" ) ),
cb.collectionIntersects( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionIntersectsNullable( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
cb.collectionIntersectsNullable( root.get( "theCollection" ), List.of( "xyz" ) ),
cb.collectionIntersectsNullable( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) )
);
em.createQuery( cq ).getResultList();
// Should all fail to compile
// cb.collectionOverlaps( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
// cb.collectionOverlaps( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
// cb.collectionOverlaps( Collections.<String>emptyList(), cb.literal( 1 ) );
// cb.collectionOverlaps( Collections.<Integer>emptyList(), cb.literal( "" ) );
// cb.collectionOverlapsNullable( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
// cb.collectionOverlapsNullable( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
// cb.collectionOverlapsNullable( Collections.<String>emptyList(), cb.literal( 1 ) );
// cb.collectionOverlapsNullable( Collections.<Integer>emptyList(), cb.literal( "" ) );
// cb.collectionIntersects( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
// cb.collectionIntersects( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
// cb.collectionIntersects( Collections.<String>emptyList(), cb.literal( 1 ) );
// cb.collectionIntersects( Collections.<Integer>emptyList(), cb.literal( "" ) );
// cb.collectionIntersectsNullable( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
// cb.collectionIntersectsNullable( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
// cb.collectionIntersectsNullable( Collections.<String>emptyList(), cb.literal( 1 ) );
// cb.collectionIntersectsNullable( Collections.<Integer>emptyList(), cb.literal( "" ) );
} );
}
@Test
public void testIntersectsSyntax(SessionFactoryScope scope) {
scope.inSession( em -> {
//tag::hql-array-intersects-hql-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where e.theArray intersects ['abc','xyz']", EntityWithArrays.class )
.getResultList();
//end::hql-array-intersects-hql-example[]
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
} );
}

View File

@ -98,3 +98,41 @@ class MyEmbeddable { ... }
----
[[array-syntax-sugar]]
== Syntax sugar for array functions
Plenty of syntax sugar for array operations was added:
|===
|Function |Syntax sugar |
|`array(1, 2)`
|`[1, 2]`
|Shorthand bracket syntax for array construction
|`array_slice(array, 1, 2)`
|`array[1:2]`
|Shorthand bracket syntax for array slicing
|`array_length(array)`
|`length(array)`
|Overload length function with array_length semantics on array input
|`array_position(array, element)`
|`position(element in array)`
|Overload position function with array_position semantics on array input
|`array_to_string(array, ',', 'null')`
|`cast(array as String)`
|Support casting array to string
|`array_contains(array, element)`
|`array contains element`
|Contains predicate for containment check
|`array_intersects(array, array(1, 2))`
|`array intersects [1, 2]`
|Overlaps predicate for overlaps check
|===