HHH-17375 Introduce array_includes() and INCLUDES predicate for checking if array contains all elements of subarray as replacement to array_contains() overload
This commit is contained in:
parent
dcedc5cf18
commit
c8aa4f39da
|
@ -1189,8 +1189,10 @@ The following functions deal with SQL array types, which are not supported on ev
|
|||
| `array_concat()` | Concatenates array with each other in order
|
||||
| `array_prepend()` | Prepends element to array
|
||||
| `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_contains()` | Whether an array contains an element
|
||||
| `array_contains_nullable()` | Whether an array contains an element, supporting `null` element
|
||||
| `array_includes()` | Whether an array contains another array
|
||||
| `array_includes_nullable()` | Whether an array contains 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
|
||||
|
@ -1367,7 +1369,7 @@ include::{array-example-dir-hql}/ArrayAppendTest.java[tags=hql-array-append-exam
|
|||
[[hql-array-contains-functions]]
|
||||
===== `array_contains()` and `array_contains_nullable()`
|
||||
|
||||
Checks if the first array argument contains the element(s) of the second argument.
|
||||
Checks if the first array argument contains the element represented by the second argument.
|
||||
Returns `null` if the first argument is `null`. The result of the `array_contains` function
|
||||
is undefined when the second argument, the element to search, is `null`.
|
||||
|
||||
|
@ -1379,29 +1381,8 @@ include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-
|
|||
----
|
||||
====
|
||||
|
||||
The second argument may be an array of the same type as the first argument.
|
||||
The result of `array_contains` is undefined when the second argument is an array that contains a `null` element.
|
||||
|
||||
[[hql-array-contains-array-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-example]
|
||||
----
|
||||
====
|
||||
|
||||
To search for `null` elements, the `array_contains_nullable` function must be used with an array argument.
|
||||
|
||||
[[hql-array-contains-array-nullable-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-nullable-example]
|
||||
----
|
||||
====
|
||||
|
||||
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.
|
||||
where the left hand side of the predicate is the array and the right hand side the value to check.
|
||||
This is syntax sugar that translates to the `array_contains` function.
|
||||
|
||||
[[hql-array-contains-hql-example]]
|
||||
|
@ -1412,29 +1393,42 @@ include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-
|
|||
----
|
||||
====
|
||||
|
||||
[[hql-array-contains-array-hql-example]]
|
||||
[[hql-array-includes-functions]]
|
||||
===== `array_includes()` and `array_includes_nullable()`
|
||||
|
||||
Checks if the first array argument contains the elements of the second array argument.
|
||||
Returns `null` if the first argument is `null`. The result of the `array_includes` function
|
||||
is undefined when the second argument contains a `null`.
|
||||
|
||||
[[hql-array-contains-array-example]]
|
||||
[[hql-array-includes-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-hql-example]
|
||||
include::{array-example-dir-hql}/ArrayIncludesTest.java[tags=hql-array-includes-example]
|
||||
----
|
||||
====
|
||||
|
||||
In addition to that, it is also possible to use the `in` predicate with arrays.
|
||||
To search for `null` elements, the `array_includes_nullable` function must be used.
|
||||
|
||||
[[hql-array-in-hql-example]]
|
||||
[[hql-array-contains-array-nullable-example]]
|
||||
[[hql-array-includes-nullable-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-in-hql-example]
|
||||
include::{array-example-dir-hql}/ArrayIncludesTest.java[tags=hql-array-includes-nullable-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-array-in-array-hql-example]]
|
||||
Alternatively, it's also possible to use the `includes` predicate,
|
||||
where the left hand side of the predicate is the array and the right hand side the array of values to check.
|
||||
This is syntax sugar that translates to the `array_includes` function.
|
||||
|
||||
[[hql-array-includes-hql-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-in-array-hql-example]
|
||||
include::{array-example-dir-hql}/ArrayIncludesTest.java[tags=hql-array-includes-hql-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -210,6 +210,7 @@ HOUR : [hH] [oO] [uU] [rR];
|
|||
IGNORE : [iI] [gG] [nN] [oO] [rR] [eE];
|
||||
ILIKE : [iI] [lL] [iI] [kK] [eE];
|
||||
IN : [iI] [nN];
|
||||
INCLUDES : [iI] [nN] [cC] [lL] [uU] [dD] [eE] [sS];
|
||||
INDEX : [iI] [nN] [dD] [eE] [xX];
|
||||
INDICES : [iI] [nN] [dD] [iI] [cC] [eE] [sS];
|
||||
INNER : [iI] [nN] [nN] [eE] [rR];
|
||||
|
|
|
@ -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? INCLUDES expression # IncludesPredicate
|
||||
| expression NOT? INTERSECTS expression # IntersectsPredicate
|
||||
| expression comparisonOperator expression # ComparisonPredicate
|
||||
| EXISTS collectionQuantifier LEFT_PAREN simplePath RIGHT_PAREN # ExistsCollectionPartPredicate
|
||||
|
@ -1703,6 +1704,7 @@ rollup
|
|||
| ILIKE
|
||||
| IN
|
||||
| INDEX
|
||||
| INCLUDES
|
||||
| INDICES
|
||||
// | INNER
|
||||
| INSERT
|
||||
|
|
|
@ -109,7 +109,7 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
"return arr.count; " +
|
||||
"end;",
|
||||
createOrReplaceConcatFunction( arrayTypeName ),
|
||||
"create or replace function " + arrayTypeName + "_contains(haystack in " + arrayTypeName +
|
||||
"create or replace function " + arrayTypeName + "_includes(haystack in " + arrayTypeName +
|
||||
", needle in " + arrayTypeName + ", nullable in number) return number deterministic is found number(1,0); begin " +
|
||||
"if haystack is null or needle is null then return null; end if; " +
|
||||
"for i in 1 .. needle.count loop " +
|
||||
|
@ -295,7 +295,7 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
"drop function " + arrayTypeName + "_position",
|
||||
"drop function " + arrayTypeName + "_length",
|
||||
"drop function " + arrayTypeName + "_concat",
|
||||
"drop function " + arrayTypeName + "_contains",
|
||||
"drop function " + arrayTypeName + "_includes",
|
||||
"drop function " + arrayTypeName + "_intersects",
|
||||
"drop function " + arrayTypeName + "_get",
|
||||
"drop function " + arrayTypeName + "_set",
|
||||
|
|
|
@ -21,6 +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.ArrayIncludesOperatorFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayIncludesUnnestFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayIntersectsOperatorFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayIntersectsUnnestFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayGetUnnestFunction;
|
||||
|
@ -34,6 +36,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.H2ArrayIncludesFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayIntersectsFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayPositionFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayPositionsFunction;
|
||||
|
@ -52,6 +55,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.OracleArrayIncludesFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayIntersectsFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayGetFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
|
||||
|
@ -2681,6 +2685,14 @@ public class CommonFunctionFactory {
|
|||
"array_contains_nullable",
|
||||
new H2ArrayContainsFunction( true, maximumArraySize, typeConfiguration )
|
||||
);
|
||||
functionRegistry.register(
|
||||
"array_includes",
|
||||
new H2ArrayIncludesFunction( false, maximumArraySize, typeConfiguration )
|
||||
);
|
||||
functionRegistry.register(
|
||||
"array_includes_nullable",
|
||||
new H2ArrayIncludesFunction( true, maximumArraySize, typeConfiguration )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2695,6 +2707,14 @@ public class CommonFunctionFactory {
|
|||
"array_contains_nullable",
|
||||
new ArrayContainsUnnestFunction( true, typeConfiguration )
|
||||
);
|
||||
functionRegistry.register(
|
||||
"array_includes",
|
||||
new ArrayIncludesUnnestFunction( false, typeConfiguration )
|
||||
);
|
||||
functionRegistry.register(
|
||||
"array_includes_nullable",
|
||||
new ArrayIncludesUnnestFunction( true, typeConfiguration )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2703,6 +2723,8 @@ public class CommonFunctionFactory {
|
|||
public void arrayContains_postgresql() {
|
||||
functionRegistry.register( "array_contains", new ArrayContainsOperatorFunction( false, typeConfiguration ) );
|
||||
functionRegistry.register( "array_contains_nullable", new ArrayContainsOperatorFunction( true, typeConfiguration ) );
|
||||
functionRegistry.register( "array_includes", new ArrayIncludesOperatorFunction( false, typeConfiguration ) );
|
||||
functionRegistry.register( "array_includes_nullable", new ArrayIncludesOperatorFunction( true, typeConfiguration ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2711,6 +2733,8 @@ public class CommonFunctionFactory {
|
|||
public void arrayContains_oracle() {
|
||||
functionRegistry.register( "array_contains", new OracleArrayContainsFunction( false, typeConfiguration ) );
|
||||
functionRegistry.register( "array_contains_nullable", new OracleArrayContainsFunction( true, typeConfiguration ) );
|
||||
functionRegistry.register( "array_includes", new OracleArrayIncludesFunction( false, typeConfiguration ) );
|
||||
functionRegistry.register( "array_includes_nullable", new OracleArrayIncludesFunction( true, typeConfiguration ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,17 +6,22 @@
|
|||
*/
|
||||
package org.hibernate.dialect.function.array;
|
||||
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Encapsulates the validator, return type and argument type resolvers for the array_contains function.
|
||||
* Subclasses only have to implement the rendering.
|
||||
*/
|
||||
public abstract class AbstractArrayContainsFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
protected static final DeprecationLogger LOG = Logger.getMessageLogger( DeprecationLogger.class, AbstractArrayContainsFunction.class.getName() );
|
||||
|
||||
protected final boolean nullable;
|
||||
|
||||
public AbstractArrayContainsFunction(boolean nullable, TypeConfiguration typeConfiguration) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Encapsulates the validator, return type and argument type resolvers for the array_includes function.
|
||||
* Subclasses only have to implement the rendering.
|
||||
*/
|
||||
public abstract class AbstractArrayIncludesFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
protected final boolean nullable;
|
||||
|
||||
public AbstractArrayIncludesFunction(boolean nullable, TypeConfiguration typeConfiguration) {
|
||||
super(
|
||||
"array_includes" + ( nullable ? "_nullable" : "" ),
|
||||
StandardArgumentsValidators.composite(
|
||||
StandardArgumentsValidators.exactly( 2 ),
|
||||
ArrayIncludesArgumentValidator.INSTANCE
|
||||
),
|
||||
StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ),
|
||||
ArrayIncludesArgumentTypeResolver.INSTANCE
|
||||
);
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(ARRAY haystackArray, OBJECT needleArray)";
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ public class ArrayContainsOperatorFunction extends ArrayContainsUnnestFunction {
|
|||
final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType();
|
||||
final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping();
|
||||
if ( needleType == null || needleType instanceof BasicPluralType<?, ?> ) {
|
||||
LOG.deprecatedArrayContainsWithArray();
|
||||
if ( nullable ) {
|
||||
super.render( sqlAppender, sqlAstArguments, returnType, walker );
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class ArrayContainsUnnestFunction extends AbstractArrayContainsFunction {
|
|||
final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType();
|
||||
final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping();
|
||||
if ( needleType == null || needleType instanceof BasicPluralType<?, ?> ) {
|
||||
LOG.deprecatedArrayContainsWithArray();
|
||||
sqlAppender.append( '(' );
|
||||
if ( ArrayHelper.isNullable( haystackExpression ) ) {
|
||||
walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
|
||||
/**
|
||||
* A {@link FunctionArgumentTypeResolver} that resolves the argument types for the {@code array_includes} function.
|
||||
*/
|
||||
public class ArrayIncludesArgumentTypeResolver implements FunctionArgumentTypeResolver {
|
||||
|
||||
public static final FunctionArgumentTypeResolver INSTANCE = new ArrayIncludesArgumentTypeResolver();
|
||||
|
||||
@Override
|
||||
public MappingModelExpressible<?> resolveFunctionArgumentType(
|
||||
SqmFunction<?> function,
|
||||
int argumentIndex,
|
||||
SqmToSqlAstConverter converter) {
|
||||
if ( argumentIndex == 0 ) {
|
||||
final SqmTypedNode<?> node = function.getArguments().get( 1 );
|
||||
if ( node instanceof SqmExpression<?> ) {
|
||||
return converter.determineValueMapping( (SqmExpression<?>) node );
|
||||
}
|
||||
}
|
||||
else if ( argumentIndex == 1 ) {
|
||||
final SqmTypedNode<?> node = function.getArguments().get( 0 );
|
||||
if ( node instanceof SqmExpression<?> ) {
|
||||
return converter.determineValueMapping( (SqmExpression<?>) node );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* A {@link ArgumentsValidator} that validates the arguments for the {@code array_includes} function.
|
||||
*/
|
||||
public class ArrayIncludesArgumentValidator extends ArrayArgumentValidator {
|
||||
|
||||
public static final ArgumentsValidator INSTANCE = new ArrayIncludesArgumentValidator();
|
||||
|
||||
protected ArrayIncludesArgumentValidator() {
|
||||
super( 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(
|
||||
List<? extends SqmTypedNode<?>> arguments,
|
||||
String functionName,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
final BasicPluralType<?, ?> haystackType =
|
||||
getPluralType( 0, arguments, functionName, typeConfiguration );
|
||||
final BasicPluralType<?, ?> needleType =
|
||||
getPluralType( 1, arguments, functionName, typeConfiguration );
|
||||
if ( haystackType != null && needleType != null
|
||||
&& !haystackType.equals( needleType )
|
||||
&& !haystackType.getElementType().equals( needleType ) ) {
|
||||
throw new FunctionArgumentException(
|
||||
String.format(
|
||||
"Parameter 1 of function '%s()' has type %s, but argument is of type '%s'",
|
||||
functionName,
|
||||
haystackType.getJavaTypeDescriptor().getTypeName(),
|
||||
needleType.getTypeName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Special array includes implementation that uses the PostgreSQL {@code @>} operator.
|
||||
*/
|
||||
public class ArrayIncludesOperatorFunction extends ArrayIncludesUnnestFunction {
|
||||
|
||||
public ArrayIncludesOperatorFunction(boolean nullable, TypeConfiguration typeConfiguration) {
|
||||
super( nullable, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final Expression needleExpression = (Expression) sqlAstArguments.get( 1 );
|
||||
if ( nullable ) {
|
||||
super.render( sqlAppender, sqlAstArguments, returnType, walker );
|
||||
}
|
||||
else {
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( "@>" );
|
||||
needleExpression.accept( walker );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Implement the array includes function by using {@code unnest}.
|
||||
*/
|
||||
public class ArrayIncludesUnnestFunction extends AbstractArrayIncludesFunction {
|
||||
|
||||
public ArrayIncludesUnnestFunction(boolean nullable, TypeConfiguration typeConfiguration) {
|
||||
super( nullable, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final Expression needleExpression = (Expression) sqlAstArguments.get( 1 );
|
||||
sqlAppender.append( '(' );
|
||||
if ( ArrayHelper.isNullable( haystackExpression ) ) {
|
||||
walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( " is not null and " );
|
||||
}
|
||||
if ( ArrayHelper.isNullable( needleExpression ) ) {
|
||||
walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( " is not null and " );
|
||||
}
|
||||
if ( !nullable ) {
|
||||
sqlAppender.append( "not exists(select 1 from unnest(" );
|
||||
walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( ") t(i) where t.i is null) and " );
|
||||
}
|
||||
sqlAppender.append( "not exists(select * from unnest(" );
|
||||
walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( ") except select * from unnest(" );
|
||||
walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( ")))" );
|
||||
}
|
||||
|
||||
}
|
|
@ -44,6 +44,7 @@ public class H2ArrayContainsFunction extends AbstractArrayContainsFunction {
|
|||
final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType();
|
||||
final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping();
|
||||
if ( needleType == null || needleType instanceof BasicPluralType<?, ?> ) {
|
||||
LOG.deprecatedArrayContainsWithArray();
|
||||
sqlAppender.append( '(' );
|
||||
if ( ArrayHelper.isNullable( haystackExpression ) ) {
|
||||
haystackExpression.accept( walker );
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* H2 requires a very special emulation, because {@code unnest} is pretty much useless,
|
||||
* 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 H2ArrayIncludesFunction extends AbstractArrayIncludesFunction {
|
||||
|
||||
private final int maximumArraySize;
|
||||
|
||||
public H2ArrayIncludesFunction(boolean nullable, int maximumArraySize, TypeConfiguration typeConfiguration) {
|
||||
super( nullable, typeConfiguration );
|
||||
this.maximumArraySize = maximumArraySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final Expression needleExpression = (Expression) sqlAstArguments.get( 1 );
|
||||
sqlAppender.append( '(' );
|
||||
if ( ArrayHelper.isNullable( haystackExpression ) ) {
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( " is not null and " );
|
||||
}
|
||||
if ( ArrayHelper.isNullable( needleExpression ) ) {
|
||||
needleExpression.accept( walker );
|
||||
sqlAppender.append( " is not null and " );
|
||||
}
|
||||
if ( !nullable ) {
|
||||
sqlAppender.append( "not array_contains(" );
|
||||
needleExpression.accept( walker );
|
||||
sqlAppender.append( ",null) and " );
|
||||
}
|
||||
sqlAppender.append( "not " );
|
||||
sqlAppender.append( "exists(select array_get(" );
|
||||
walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
sqlAppender.append( ",t.i) from system_range(1," );
|
||||
sqlAppender.append( Integer.toString( maximumArraySize ) );
|
||||
sqlAppender.append( ") t(i) where array_length(" );
|
||||
needleExpression.accept( walker );
|
||||
sqlAppender.append( ")>=t.i" );
|
||||
sqlAppender.append( " except " );
|
||||
sqlAppender.append( "select array_get(" );
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( ",t.i) from system_range(1," );
|
||||
sqlAppender.append( Integer.toString( maximumArraySize ) );
|
||||
sqlAppender.append( ") t(i) where array_length(" );
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( ")>=t.i))" );
|
||||
}
|
||||
|
||||
}
|
|
@ -40,7 +40,8 @@ public class OracleArrayContainsFunction extends AbstractArrayContainsFunction {
|
|||
);
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
if ( needleType == null || needleType instanceof BasicPluralType<?, ?> ) {
|
||||
sqlAppender.append( "_contains(" );
|
||||
LOG.deprecatedArrayContainsWithArray();
|
||||
sqlAppender.append( "_includes(" );
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( ',' );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
public class OracleArrayIncludesFunction extends AbstractArrayIncludesFunction {
|
||||
|
||||
public OracleArrayIncludesFunction(boolean nullable, TypeConfiguration typeConfiguration) {
|
||||
super( nullable, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
haystackExpression.getExpressionType(),
|
||||
walker.getSessionFactory().getTypeConfiguration()
|
||||
);
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_includes(" );
|
||||
haystackExpression.accept( walker );
|
||||
sqlAppender.append( ',' );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( ',' );
|
||||
sqlAppender.append( nullable ? "1" : "0" );
|
||||
sqlAppender.append( ")>0" );
|
||||
}
|
||||
}
|
|
@ -290,4 +290,11 @@ public interface DeprecationLogger extends BasicLogger {
|
|||
)
|
||||
void deprecatedNativeQueryColonEscaping(String oldOperator, String newOperator);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id = 90000032,
|
||||
value = "The support for passing arrays to array_contains() is deprecated and will be removed. Use array_includes() instead."
|
||||
)
|
||||
void deprecatedArrayContainsWithArray();
|
||||
|
||||
}
|
||||
|
|
|
@ -2745,52 +2745,124 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
|||
<T> JpaPredicate arrayContainsNullable(T[] array, Expression<T> elementExpression);
|
||||
|
||||
/**
|
||||
* Whether an array contains another array.
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludes(Expression, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludes( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array contains another array.
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludes(Expression, T[])}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return arrayIncludes( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array contains another array.
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludes(T[], Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludes( array, subArrayExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array contains another array with nullable elements.
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludesNullable(Expression, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludesNullable( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array contains another array with nullable elements.
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludesNullable(Expression, T[])}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return arrayIncludesNullable( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array contains another array with nullable elements.
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #arrayIncludesNullable(T[], Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <T> JpaPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludesNullable( array, subArrayExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludes(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludes(Expression<T[]> arrayExpression, T[] subArray);
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludes(T[] array, Expression<T[]> subArrayExpression);
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, T[] subArray);
|
||||
|
||||
/**
|
||||
* Whether an array is a subset of another array with nullable elements.
|
||||
*
|
||||
* @since 6.6
|
||||
*/
|
||||
@Incubating
|
||||
<T> JpaPredicate arrayIncludesNullable(T[] array, Expression<T[]> subArrayExpression);
|
||||
|
||||
/**
|
||||
* Whether one array has any elements common with another array.
|
||||
|
@ -3296,52 +3368,124 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
|||
<E> JpaPredicate collectionContainsNullable(Collection<E> collection, Expression<E> elementExpression);
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection.
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludes(Expression, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludes( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection.
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludes(Expression, Collection)}
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection) {
|
||||
return collectionIncludes( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection.
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludes(Collection, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAll(Collection<E> collection, Expression<? extends Collection<? extends E>> subArrayExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAll(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludes( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection with nullable elements.
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludesNullable(Expression, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludesNullable( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection with nullable elements.
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludesNullable(Expression, Collection)}
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection) {
|
||||
return collectionIncludesNullable( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection contains another basic collection with nullable elements.
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
* @deprecated Replaced with {@link #collectionIncludesNullable(Collection, Expression)}
|
||||
*/
|
||||
@Incubating
|
||||
@Deprecated(forRemoval = true)
|
||||
default <E> JpaPredicate collectionContainsAllNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludesNullable( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionContainsAllNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
<E> JpaPredicate collectionIncludes(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionIncludes(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionIncludes(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionIncludesNullable(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionIncludesNullable(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
|
||||
/**
|
||||
* Whether a basic collection is a subset of another basic collection with nullable elements.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
<E> JpaPredicate collectionIncludesNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
/**
|
||||
* Whether one basic collection has any elements common with another basic collection.
|
||||
|
|
|
@ -2493,24 +2493,28 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayContainsAll( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return criteriaBuilder.arrayContainsAll( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayContainsAll( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAllNullable(
|
||||
Expression<T[]> arrayExpression,
|
||||
|
@ -2519,17 +2523,57 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return criteriaBuilder.arrayContainsAllNullable( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayContainsAllNullable( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludes(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayIncludes( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludes(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return criteriaBuilder.arrayIncludes( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludes(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayIncludes( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludesNullable(
|
||||
Expression<T[]> arrayExpression,
|
||||
Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayIncludesNullable( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return criteriaBuilder.arrayIncludesNullable( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <T> JpaPredicate arrayIncludesNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return criteriaBuilder.arrayIncludesNullable( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
|
@ -2979,6 +3023,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAll(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
|
@ -2987,6 +3032,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAll(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
|
@ -2995,14 +3041,16 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAll(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subArrayExpression) {
|
||||
return criteriaBuilder.collectionContainsAll( collection, subArrayExpression );
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return criteriaBuilder.collectionContainsAll( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAllNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
|
@ -3011,6 +3059,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAllNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
|
@ -3019,6 +3068,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionContainsAllNullable(
|
||||
Collection<E> collection,
|
||||
|
@ -3026,6 +3076,54 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
|||
return criteriaBuilder.collectionContainsAllNullable( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludes(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return criteriaBuilder.collectionIncludes( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludes(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return criteriaBuilder.collectionIncludes( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludes(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subArrayExpression) {
|
||||
return criteriaBuilder.collectionIncludes( collection, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludesNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return criteriaBuilder.collectionIncludesNullable( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludesNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return criteriaBuilder.collectionIncludesNullable( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Incubating
|
||||
public <E> JpaPredicate collectionIncludesNullable(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return criteriaBuilder.collectionIncludesNullable( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
@Incubating
|
||||
|
|
|
@ -2661,6 +2661,33 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPredicate visitIncludesPredicate(HqlParser.IncludesPredicateContext 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();
|
||||
final SqmExpressible<?> rhsExpressible = rhs.getExpressible();
|
||||
if ( lhsExpressible != null && !( lhsExpressible.getSqmType() instanceof BasicPluralType<?, ?>) ) {
|
||||
throw new SemanticException(
|
||||
"First operand for includes predicate must be a basic plural type expression, but found: " + lhsExpressible.getSqmType(),
|
||||
query
|
||||
);
|
||||
}
|
||||
if ( rhsExpressible != null && !( rhsExpressible.getSqmType() instanceof BasicPluralType<?, ?>) ) {
|
||||
throw new SemanticException(
|
||||
"Second operand for includes predicate must be a basic plural type expression, but found: " + rhsExpressible.getSqmType(),
|
||||
query
|
||||
);
|
||||
}
|
||||
final SelfRenderingSqmFunction<Boolean> contains = getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( lhs, rhs ),
|
||||
null,
|
||||
creationContext.getQueryEngine()
|
||||
);
|
||||
return new SqmBooleanExpressionPredicate( contains, negated, creationContext.getNodeBuilder() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPredicate visitIntersectsPredicate(HqlParser.IntersectsPredicateContext ctx) {
|
||||
final boolean negated = ctx.NOT() != null;
|
||||
|
|
|
@ -265,22 +265,52 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
|
|||
<T> SqmPredicate arrayContainsNullable(T[] array, Expression<T> elementExpression);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAll(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
default <T> SqmPredicate arrayContainsAll(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludes( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray);
|
||||
default <T> SqmPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return arrayIncludes( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression);
|
||||
default <T> SqmPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludes( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
default <T> SqmPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludesNullable( arrayExpression, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray);
|
||||
default <T> SqmPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return arrayIncludesNullable( arrayExpression, subArray );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression);
|
||||
default <T> SqmPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return arrayIncludesNullable( array, subArrayExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludes(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludes(Expression<T[]> arrayExpression, T[] subArray);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludes(T[] array, Expression<T[]> subArrayExpression);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, Expression<T[]> subArrayExpression);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, T[] subArray);
|
||||
|
||||
@Override
|
||||
<T> SqmPredicate arrayIncludesNullable(T[] array, Expression<T[]> subArrayExpression);
|
||||
|
||||
@Override
|
||||
default <T> SqmPredicate arrayOverlaps(Expression<T[]> arrayExpression1, Expression<T[]> arrayExpression2) {
|
||||
|
@ -475,22 +505,62 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
|
|||
<E> SqmPredicate collectionContainsNullable(Collection<E> collection, Expression<E> elementExpression);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
default <E> SqmPredicate collectionContainsAll(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludes( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAll(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
default <E> SqmPredicate collectionContainsAll(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return collectionIncludes( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAll(Collection<E> collection, Expression<? extends Collection<? extends E>> subArrayExpression);
|
||||
default <E> SqmPredicate collectionContainsAll(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludes( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
default <E> SqmPredicate collectionContainsAllNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludesNullable( collectionExpression, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAllNullable(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
default <E> SqmPredicate collectionContainsAllNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return collectionIncludesNullable( collectionExpression, subCollection );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionContainsAllNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
default <E> SqmPredicate collectionContainsAllNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return collectionIncludesNullable( collection, subCollectionExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludes(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludes(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludes(Collection<E> collection, Expression<? extends Collection<? extends E>> subArrayExpression);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludesNullable(Expression<? extends Collection<E>> collectionExpression, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludesNullable(Expression<? extends Collection<E>> collectionExpression, Collection<? extends E> subCollection);
|
||||
|
||||
@Override
|
||||
<E> SqmPredicate collectionIncludesNullable(Collection<E> collection, Expression<? extends Collection<? extends E>> subCollectionExpression);
|
||||
|
||||
@Override
|
||||
default <E> SqmPredicate collectionOverlaps(Expression<? extends Collection<E>> collectionExpression1, Expression<? extends Collection<? extends E>> collectionExpression2) {
|
||||
|
|
|
@ -3929,10 +3929,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAll(
|
||||
public <T> SqmPredicate arrayIncludes(
|
||||
Expression<T[]> arrayExpression,
|
||||
Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) arrayExpression, (SqmExpression<?>) subArrayExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -3940,8 +3940,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAll(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
public <T> SqmPredicate arrayIncludes(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) arrayExpression, value( subArray, (SqmExpression<?>) arrayExpression ) ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -3949,8 +3949,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAll(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
public <T> SqmPredicate arrayIncludes(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( value( array, (SqmExpression<?>) subArrayExpression ), (SqmExpression<?>) subArrayExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -3958,10 +3958,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAllNullable(
|
||||
public <T> SqmPredicate arrayIncludesNullable(
|
||||
Expression<T[]> arrayExpression,
|
||||
Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) arrayExpression, (SqmExpression<?>) subArrayExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -3969,8 +3969,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAllNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
public <T> SqmPredicate arrayIncludesNullable(Expression<T[]> arrayExpression, T[] subArray) {
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) arrayExpression, value( subArray, (SqmExpression<?>) arrayExpression ) ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -3978,8 +3978,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> SqmPredicate arrayContainsAllNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
public <T> SqmPredicate arrayIncludesNullable(T[] array, Expression<T[]> subArrayExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( value( array, (SqmExpression<?>) subArrayExpression ), (SqmExpression<?>) subArrayExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4548,10 +4548,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAll(
|
||||
public <E> SqmPredicate collectionIncludes(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) collectionExpression, (SqmExpression<?>) subCollectionExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4559,10 +4559,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAll(
|
||||
public <E> SqmPredicate collectionIncludes(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) collectionExpression, value( subCollection, (SqmExpression<?>) collectionExpression ) ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4570,10 +4570,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAll(
|
||||
public <E> SqmPredicate collectionIncludes(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes" ).generateSqmExpression(
|
||||
asList( value( collection, (SqmExpression<?>) subCollectionExpression ), (SqmExpression<?>) subCollectionExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4581,10 +4581,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAllNullable(
|
||||
public <E> SqmPredicate collectionIncludesNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) collectionExpression, (SqmExpression<?>) subCollectionExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4592,10 +4592,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAllNullable(
|
||||
public <E> SqmPredicate collectionIncludesNullable(
|
||||
Expression<? extends Collection<E>> collectionExpression,
|
||||
Collection<? extends E> subCollection) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( (SqmExpression<?>) collectionExpression, value( subCollection, (SqmExpression<?>) collectionExpression ) ),
|
||||
null,
|
||||
queryEngine
|
||||
|
@ -4603,10 +4603,10 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
}
|
||||
|
||||
@Override
|
||||
public <E> SqmPredicate collectionContainsAllNullable(
|
||||
public <E> SqmPredicate collectionIncludesNullable(
|
||||
Collection<E> collection,
|
||||
Expression<? extends Collection<? extends E>> subCollectionExpression) {
|
||||
return isTrue( getFunctionDescriptor( "array_contains_nullable" ).generateSqmExpression(
|
||||
return isTrue( getFunctionDescriptor( "array_includes_nullable" ).generateSqmExpression(
|
||||
asList( value( collection, (SqmExpression<?>) subCollectionExpression ), (SqmExpression<?>) subCollectionExpression ),
|
||||
null,
|
||||
queryEngine
|
||||
|
|
|
@ -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 ArrayContainsArrayTest {
|
||||
public class ArrayIncludesTest {
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
|
@ -55,39 +55,39 @@ public class ArrayContainsArrayTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArray(SessionFactoryScope scope) {
|
||||
public void testIncludesArray(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-contains-array-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
|
||||
//tag::hql-array-includes-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_includes(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
//end::hql-array-contains-array-example[]
|
||||
//end::hql-array-includes-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotContainArray(SessionFactoryScope scope) {
|
||||
public void testDoesNotIncludeArray(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('xyz'))", EntityWithArrays.class )
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_includes(e.theArray, array('xyz'))", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
assertEquals( 0, results.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArrayPartly(SessionFactoryScope scope) {
|
||||
public void testIncludesArrayPartly(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_includes(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
assertEquals( 0, results.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArrayWithNullElementOnly(SessionFactoryScope scope) {
|
||||
public void testIncludesArrayWithNullElementOnly(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_nullable(e.theArray, array(null))", EntityWithArrays.class )
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_includes_nullable(e.theArray, array(null))", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
|
@ -95,34 +95,22 @@ public class ArrayContainsArrayTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArrayWithNullElement(SessionFactoryScope scope) {
|
||||
public void testIncludesArrayWithNullElement(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-contains-array-nullable-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_nullable(e.theArray, array('abc',null))", EntityWithArrays.class )
|
||||
//tag::hql-array-includes-nullable-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_includes_nullable(e.theArray, array('abc',null))", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
//end::hql-array-contains-array-nullable-example[]
|
||||
//end::hql-array-includes-nullable-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsElementParameter(SessionFactoryScope scope) {
|
||||
public void testIncludesArrayParameter(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery(
|
||||
"from EntityWithArrays e where array_contains_nullable(e.theArray, :param)",
|
||||
EntityWithArrays.class
|
||||
).setParameter( "param", "abc" ).getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArrayParameter(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery(
|
||||
"from EntityWithArrays e where array_contains_nullable(e.theArray, :param)",
|
||||
"from EntityWithArrays e where array_includes_nullable(e.theArray, :param)",
|
||||
EntityWithArrays.class
|
||||
).setParameter( "param", new String[]{ "abc", null } ).getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
|
@ -131,10 +119,10 @@ public class ArrayContainsArrayTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContainsNullParameter(SessionFactoryScope scope) {
|
||||
public void testIncludesNullParameter(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<EntityWithArrays> results = em.createQuery(
|
||||
"from EntityWithArrays e where array_contains_nullable(e.theArray, :param)",
|
||||
"from EntityWithArrays e where array_includes_nullable(e.theArray, :param)",
|
||||
EntityWithArrays.class
|
||||
).setParameter( "param", null ).getResultList();
|
||||
assertEquals( 0, results.size() );
|
||||
|
@ -149,24 +137,24 @@ public class ArrayContainsArrayTest {
|
|||
final JpaRoot<EntityWithArrays> root = cq.from( EntityWithArrays.class );
|
||||
cq.multiselect(
|
||||
root.get( "id" ),
|
||||
cb.arrayContainsAll( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayContainsAll( root.get( "theArray" ), new String[]{ "xyz" } ),
|
||||
cb.arrayContainsAll( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayContainsAllNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayContainsAllNullable( root.get( "theArray" ), new String[]{ "xyz" } ),
|
||||
cb.arrayContainsAllNullable( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) )
|
||||
cb.arrayIncludes( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayIncludes( root.get( "theArray" ), new String[]{ "xyz" } ),
|
||||
cb.arrayIncludes( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayIncludesNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ),
|
||||
cb.arrayIncludesNullable( root.get( "theArray" ), new String[]{ "xyz" } ),
|
||||
cb.arrayIncludesNullable( new String[]{ "abc", "xyz" }, cb.arrayLiteral( "xyz" ) )
|
||||
);
|
||||
em.createQuery( cq ).getResultList();
|
||||
|
||||
// Should all fail to compile
|
||||
// cb.arrayContainsAll( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
|
||||
// cb.arrayContainsAll( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
|
||||
// cb.arrayContainsAll( new String[0], cb.literal( 1 ) );
|
||||
// cb.arrayContainsAll( new Integer[0], cb.literal( "" ) );
|
||||
// cb.arrayContainsAllNullable( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
|
||||
// cb.arrayContainsAllNullable( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
|
||||
// cb.arrayContainsAllNullable( new String[0], cb.literal( 1 ) );
|
||||
// cb.arrayContainsAllNullable( new Integer[0], cb.literal( "" ) );
|
||||
// cb.arrayIncludes( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
|
||||
// cb.arrayIncludes( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
|
||||
// cb.arrayIncludes( new String[0], cb.literal( 1 ) );
|
||||
// cb.arrayIncludes( new Integer[0], cb.literal( "" ) );
|
||||
// cb.arrayIncludesNullable( root.<Integer[]>get( "theArray" ), cb.arrayLiteral( "xyz" ) );
|
||||
// cb.arrayIncludesNullable( root.<Integer[]>get( "theArray" ), new String[]{ "xyz" } );
|
||||
// cb.arrayIncludesNullable( new String[0], cb.literal( 1 ) );
|
||||
// cb.arrayIncludesNullable( new Integer[0], cb.literal( "" ) );
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -178,46 +166,34 @@ public class ArrayContainsArrayTest {
|
|||
final JpaRoot<EntityWithArrays> root = cq.from( EntityWithArrays.class );
|
||||
cq.multiselect(
|
||||
root.get( "id" ),
|
||||
cb.collectionContainsAll( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionContainsAll( root.get( "theCollection" ), List.of( "xyz" ) ),
|
||||
cb.collectionContainsAll( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionContainsAllNullable( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionContainsAllNullable( root.get( "theCollection" ), List.of( "xyz" ) ),
|
||||
cb.collectionContainsAllNullable( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) )
|
||||
cb.collectionIncludes( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionIncludes( root.get( "theCollection" ), List.of( "xyz" ) ),
|
||||
cb.collectionIncludes( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionIncludesNullable( root.<Collection<String>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ),
|
||||
cb.collectionIncludesNullable( root.get( "theCollection" ), List.of( "xyz" ) ),
|
||||
cb.collectionIncludesNullable( List.of( "abc", "xyz" ), cb.collectionLiteral( "xyz" ) )
|
||||
);
|
||||
em.createQuery( cq ).getResultList();
|
||||
|
||||
// Should all fail to compile
|
||||
// cb.collectionContainsAll( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
|
||||
// cb.collectionContainsAll( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
|
||||
// cb.collectionContainsAll( Collections.<String>emptyList(), cb.literal( 1 ) );
|
||||
// cb.collectionContainsAll( Collections.<Integer>emptyList(), cb.literal( "" ) );
|
||||
// cb.collectionContainsAllNullable( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
|
||||
// cb.collectionContainsAllNullable( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
|
||||
// cb.collectionContainsAllNullable( Collections.<String>emptyList(), cb.literal( 1 ) );
|
||||
// cb.collectionContainsAllNullable( Collections.<Integer>emptyList(), cb.literal( "" ) );
|
||||
// cb.collectionIncludes( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
|
||||
// cb.collectionIncludes( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
|
||||
// cb.collectionIncludes( Collections.<String>emptyList(), cb.literal( 1 ) );
|
||||
// cb.collectionIncludes( Collections.<Integer>emptyList(), cb.literal( "" ) );
|
||||
// cb.collectionIncludesNullable( root.<Collection<Integer>>get( "theCollection" ), cb.collectionLiteral( "xyz" ) );
|
||||
// cb.collectionIncludesNullable( root.<Collection<Integer>>get( "theCollection" ), List.of( "xyz" ) );
|
||||
// cb.collectionIncludesNullable( Collections.<String>emptyList(), cb.literal( 1 ) );
|
||||
// cb.collectionIncludesNullable( Collections.<Integer>emptyList(), cb.literal( "" ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsArraySyntax(SessionFactoryScope scope) {
|
||||
public void testIncludesSyntax(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 )
|
||||
//tag::hql-array-includes-hql-example[]
|
||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where e.theArray includes ['abc', 'def']", EntityWithArrays.class )
|
||||
.getResultList();
|
||||
//end::hql-array-contains-array-hql-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
||||
}
|
||||
|
||||
@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[]
|
||||
//end::hql-array-includes-hql-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertEquals( 2L, results.get( 0 ).getId() );
|
||||
} );
|
|
@ -31,6 +31,7 @@ and would now be `BigIntegerBigDecimalArray`, because the preferred Java type fo
|
|||
To specify a custom array type name, annotate the persistent property with `@Column(columnDefinition = "BigIntegerArray")`.
|
||||
|
||||
[[user-defined-type]]
|
||||
== Changes to `UserDefinedType`
|
||||
|
||||
`UserDefinedType` was renamed to `UserDefinedObjectType` and everything except access to column information
|
||||
was abstracted in a new interface named `UserDefinedType`. This was done to allow modelling dependencies between
|
||||
|
@ -48,3 +49,11 @@ to make it clear that these contracts might still evolve.
|
|||
|
||||
Another change is to the already incubating `ColumnOrderingStrategy`,
|
||||
where the argument type of `orderUserDefinedTypeColumns` was changed from `UserDefinedType` to `UserDefinedObjectType`.
|
||||
|
||||
[[array-contains-array-deprecation]]
|
||||
== Subset check for arrays to use `array_includes`
|
||||
|
||||
Support for `array_contains()` to accept an array as element argument is deprecated and will emit a warning.
|
||||
To check if an array is a subset of another array, use the `array_includes()` function,
|
||||
or the new `INCLUDES` predicate i.e. `array INCLUDES subarray`.
|
||||
|
||||
|
|
|
@ -131,6 +131,10 @@ Plenty of syntax sugar for array operations was added:
|
|||
|`array contains element` or `element in array`
|
||||
|Contains predicate for containment check
|
||||
|
||||
|`array_includes(array, array)`
|
||||
|`array includes subArray`
|
||||
|Predicate to for subset checking
|
||||
|
||||
|`array_intersects(array, array(1, 2))`
|
||||
|`array intersects [1, 2]`
|
||||
|Overlaps predicate for overlaps check
|
||||
|
|
Loading…
Reference in New Issue