From 5c6a2f4a7d180d7e78eed81ce76f024e62febbe2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 7 May 2024 13:56:28 +0200 Subject: [PATCH] HHH-17375 Introduce intersects predicate for easy array_intersects, the replacement of array_overlaps --- .../chapters/query/hql/QueryLanguage.adoc | 43 ++++- .../hql/extras/predicate_intersects_bnf.txt | 1 + .../dialect/CockroachLegacyDialect.java | 3 +- .../community/dialect/H2LegacyDialect.java | 2 +- .../community/dialect/HSQLLegacyDialect.java | 2 +- .../dialect/OracleLegacyDialect.java | 3 +- .../dialect/PostgreSQLLegacyDialect.java | 3 +- .../org/hibernate/grammars/hql/HqlLexer.g4 | 1 + .../org/hibernate/grammars/hql/HqlParser.g4 | 2 + .../hibernate/dialect/CockroachDialect.java | 2 +- .../java/org/hibernate/dialect/H2Dialect.java | 2 +- .../org/hibernate/dialect/HSQLDialect.java | 2 +- .../org/hibernate/dialect/OracleDialect.java | 3 +- .../OracleUserDefinedTypeExporter.java | 4 +- .../hibernate/dialect/PostgreSQLDialect.java | 3 +- .../function/CommonFunctionFactory.java | 60 ++++--- ...a => AbstractArrayIntersectsFunction.java} | 8 +- ...a => ArrayIntersectsOperatorFunction.java} | 6 +- ...ava => ArrayIntersectsUnnestFunction.java} | 6 +- ...on.java => H2ArrayIntersectsFunction.java} | 4 +- ...ava => OracleArrayIntersectsFunction.java} | 6 +- .../criteria/HibernateCriteriaBuilder.java | 168 ++++++++++++++++-- .../spi/HibernateCriteriaBuilderDelegate.java | 96 ++++++++++ .../hql/internal/SemanticQueryBuilder.java | 20 +++ .../org/hibernate/query/sqm/NodeBuilder.java | 84 +++++++-- .../sqm/internal/SqmCriteriaNodeBuilder.java | 48 ++--- ...lapsTest.java => ArrayIntersectsTest.java} | 98 +++++----- release-announcement.adoc | 38 ++++ 28 files changed, 562 insertions(+), 156 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/predicate_intersects_bnf.txt rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{AbstractArrayOverlapsFunction.java => AbstractArrayIntersectsFunction.java} (82%) rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{ArrayOverlapsOperatorFunction.java => ArrayIntersectsOperatorFunction.java} (82%) rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{ArrayOverlapsUnnestFunction.java => ArrayIntersectsUnnestFunction.java} (87%) rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{H2ArrayOverlapsFunction.java => H2ArrayIntersectsFunction.java} (92%) rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{OracleArrayOverlapsFunction.java => OracleArrayIntersectsFunction.java} (85%) rename hibernate-core/src/test/java/org/hibernate/orm/test/function/array/{ArrayOverlapsTest.java => ArrayIntersectsTest.java} (50%) diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc index ec56a6a5b1..f1fd303c12 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc @@ -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-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-relational-comparisons-subqueries]] ==== Relational operators and subqueries diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/predicate_intersects_bnf.txt b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/predicate_intersects_bnf.txt new file mode 100644 index 0000000000..1c09223f6e --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/predicate_intersects_bnf.txt @@ -0,0 +1 @@ +expression "NOT"? "INTERSECTS" expression \ No newline at end of file diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index 609665e787..16472df8d4 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -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(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java index 30c3decba6..1736b82e45 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java @@ -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() ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java index fd27d7b409..b491f19a85 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java @@ -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(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 383fc68274..aee6adb7be 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -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(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index cb566c5c24..62d2cf9cc8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -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(); diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 index 44d45aecf0..4e1e1c6e84 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 @@ -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]; diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 index bf8816acd9..7cee3e889f 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index b840b2a9ca..02932900db 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -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(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 6b71dbf8b5..04e2f588f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -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() ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 5b35eea49a..fa0ca8189f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -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(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 0c5c4d3542..03315e54a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -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(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java index 455cde2df4..e7f60c6902 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java @@ -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", diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 586e15cacc..e129586c6f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -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(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index 005c0af165..6050a970a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -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" ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayIntersectsFunction.java similarity index 82% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayIntersectsFunction.java index eb38aa14ef..0dd73625d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayIntersectsFunction.java @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsOperatorFunction.java similarity index 82% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsOperatorFunction.java index 23969f9d30..d3786af9eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsOperatorFunction.java @@ -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 ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsUnnestFunction.java similarity index 87% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsUnnestFunction.java index 0c58665c8f..e1e612772c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayIntersectsUnnestFunction.java @@ -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 ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayIntersectsFunction.java similarity index 92% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayIntersectsFunction.java index 43992511d7..94f2f731c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayIntersectsFunction.java @@ -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; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java similarity index 85% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java index 89e7863051..95fdad4de8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java @@ -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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java index 1ba88b66bc..e8c084de4e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java @@ -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 - JpaPredicate arrayOverlaps(Expression arrayExpression1, Expression arrayExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlaps(Expression arrayExpression1, Expression 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 - JpaPredicate arrayOverlaps(Expression arrayExpression1, T[] array2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlaps(Expression 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 - JpaPredicate arrayOverlaps(T[] array1, Expression arrayExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlaps(T[] array1, Expression 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 - JpaPredicate arrayOverlapsNullable(Expression arrayExpression1, Expression arrayExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlapsNullable(Expression arrayExpression1, Expression 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 - JpaPredicate arrayOverlapsNullable(Expression arrayExpression1, T[] array2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlapsNullable(Expression 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 - JpaPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2) { + return arrayIntersectsNullable( array1, arrayExpression2 ); + } + + /** + * Whether one array has any elements common with another array. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersects(Expression arrayExpression1, Expression arrayExpression2); + + /** + * Whether one array has any elements common with another array. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersects(Expression arrayExpression1, T[] array2); + + /** + * Whether one array has any elements common with another array. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersects(T[] array1, Expression arrayExpression2); + + /** + * Whether one array has any elements common with another array, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersectsNullable(Expression arrayExpression1, Expression arrayExpression2); + + /** + * Whether one array has any elements common with another array, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersectsNullable(Expression arrayExpression1, T[] array2); + + /** + * Whether one array has any elements common with another array, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate arrayIntersectsNullable(T[] array1, Expression 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 - JpaPredicate collectionOverlaps(Expression> collectionExpression1, Expression> collectionExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlaps(Expression> collectionExpression1, Expression> 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 - JpaPredicate collectionOverlaps(Expression> collectionExpression1, Collection collection2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlaps(Expression> collectionExpression1, Collection 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 - JpaPredicate collectionOverlaps(Collection collection1, Expression> collectionExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlaps(Collection collection1, Expression> 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 - JpaPredicate collectionOverlapsNullable(Expression> collectionExpression1, Expression> collectionExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlapsNullable(Expression> collectionExpression1, Expression> 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 - JpaPredicate collectionOverlapsNullable(Expression> collectionExpression1, Collection collection2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlapsNullable(Expression> collectionExpression1, Collection 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 - JpaPredicate collectionOverlapsNullable(Collection collection1, Expression> collectionExpression2); + @Deprecated(forRemoval = true) + default JpaPredicate collectionOverlapsNullable(Collection collection1, Expression> collectionExpression2) { + return collectionIntersectsNullable( collection1, collectionExpression2 ); + } + + /** + * Whether one basic collection has any elements common with another basic collection. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersects(Expression> collectionExpression1, Expression> collectionExpression2); + + /** + * Whether one basic collection has any elements common with another basic collection. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersects(Expression> collectionExpression1, Collection collection2); + + /** + * Whether one basic collection has any elements common with another basic collection. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersects(Collection collection1, Expression> collectionExpression2); + + /** + * Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersectsNullable(Expression> collectionExpression1, Expression> collectionExpression2); + + /** + * Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersectsNullable(Expression> collectionExpression1, Collection collection2); + + /** + * Whether one basic collection has any elements common with another basic collection, supporting {@code null} elements. + * + * @since 6.6 + */ + @Incubating + JpaPredicate collectionIntersectsNullable(Collection collection1, Expression> collectionExpression2); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java index 234d11333b..1444591163 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/spi/HibernateCriteriaBuilderDelegate.java @@ -2531,41 +2531,83 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlaps(Expression arrayExpression1, Expression arrayExpression2) { return criteriaBuilder.arrayOverlaps( arrayExpression1, arrayExpression2 ); } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlaps(Expression arrayExpression1, T[] array2) { return criteriaBuilder.arrayOverlaps( arrayExpression1, array2 ); } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlaps(T[] array1, Expression arrayExpression2) { return criteriaBuilder.arrayOverlaps( array1, arrayExpression2 ); } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlapsNullable(Expression arrayExpression1, Expression arrayExpression2) { return criteriaBuilder.arrayOverlapsNullable( arrayExpression1, arrayExpression2 ); } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlapsNullable(Expression arrayExpression1, T[] array2) { return criteriaBuilder.arrayOverlapsNullable( arrayExpression1, array2 ); } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2) { return criteriaBuilder.arrayOverlapsNullable( array1, arrayExpression2 ); } + @Override + @Incubating + public JpaPredicate arrayIntersects(Expression arrayExpression1, Expression arrayExpression2) { + return criteriaBuilder.arrayIntersects( arrayExpression1, arrayExpression2 ); + } + + @Override + @Incubating + public JpaPredicate arrayIntersects(Expression arrayExpression1, T[] array2) { + return criteriaBuilder.arrayIntersects( arrayExpression1, array2 ); + } + + @Override + @Incubating + public JpaPredicate arrayIntersects(T[] array1, Expression arrayExpression2) { + return criteriaBuilder.arrayIntersects( array1, arrayExpression2 ); + } + + @Override + @Incubating + public JpaPredicate arrayIntersectsNullable(Expression arrayExpression1, Expression arrayExpression2) { + return criteriaBuilder.arrayIntersectsNullable( arrayExpression1, arrayExpression2 ); + } + + @Override + @Incubating + public JpaPredicate arrayIntersectsNullable(Expression arrayExpression1, T[] array2) { + return criteriaBuilder.arrayIntersectsNullable( arrayExpression1, array2 ); + } + + @Override + @Incubating + public JpaPredicate arrayIntersectsNullable(T[] array1, Expression arrayExpression2) { + return criteriaBuilder.arrayIntersectsNullable( array1, arrayExpression2 ); + } + @Override @Incubating public > JpaExpression collectionLiteral(E... elements) { @@ -2985,6 +3027,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlaps( Expression> collectionExpression1, @@ -2993,6 +3036,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlaps( Expression> collectionExpression1, @@ -3001,6 +3045,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlaps( Collection collection1, @@ -3009,6 +3054,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlapsNullable( Expression> collectionExpression1, @@ -3017,6 +3063,7 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlapsNullable( Expression> collectionExpression1, @@ -3025,10 +3072,59 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde } @Override + @Deprecated(forRemoval = true) @Incubating public JpaPredicate collectionOverlapsNullable( Collection collection1, Expression> collectionExpression2) { return criteriaBuilder.collectionOverlapsNullable( collection1, collectionExpression2 ); } + + @Override + @Incubating + public JpaPredicate collectionIntersects( + Expression> collectionExpression1, + Expression> collectionExpression2) { + return criteriaBuilder.collectionIntersects( collectionExpression1, collectionExpression2 ); + } + + @Override + @Incubating + public JpaPredicate collectionIntersects( + Expression> collectionExpression1, + Collection collection2) { + return criteriaBuilder.collectionIntersects( collectionExpression1, collection2 ); + } + + @Override + @Incubating + public JpaPredicate collectionIntersects( + Collection collection1, + Expression> collectionExpression2) { + return criteriaBuilder.collectionIntersects( collection1, collectionExpression2 ); + } + + @Override + @Incubating + public JpaPredicate collectionIntersectsNullable( + Expression> collectionExpression1, + Expression> collectionExpression2) { + return criteriaBuilder.collectionIntersectsNullable( collectionExpression1, collectionExpression2 ); + } + + @Override + @Incubating + public JpaPredicate collectionIntersectsNullable( + Expression> collectionExpression1, + Collection collection2) { + return criteriaBuilder.collectionIntersectsNullable( collectionExpression1, collection2 ); + } + + @Override + @Incubating + public JpaPredicate collectionIntersectsNullable( + Collection collection1, + Expression> collectionExpression2) { + return criteriaBuilder.collectionIntersectsNullable( collection1, collectionExpression2 ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index edbd1ab9e5..acdd97c30c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -2661,6 +2661,26 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor 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 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; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java index 9aef289a86..0952cb38ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java @@ -283,22 +283,52 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { SqmPredicate arrayContainsAllNullable(T[] array, Expression subArrayExpression); @Override - SqmPredicate arrayOverlaps(Expression arrayExpression1, Expression arrayExpression2); + default SqmPredicate arrayOverlaps(Expression arrayExpression1, Expression arrayExpression2) { + return arrayIntersects( arrayExpression1, arrayExpression2 ); + } @Override - SqmPredicate arrayOverlaps(Expression arrayExpression1, T[] array2); + default SqmPredicate arrayOverlaps(Expression arrayExpression1, T[] array2) { + return arrayIntersects( arrayExpression1, array2 ); + } @Override - SqmPredicate arrayOverlaps(T[] array1, Expression arrayExpression2); + default SqmPredicate arrayOverlaps(T[] array1, Expression arrayExpression2) { + return arrayIntersects( array1, arrayExpression2 ); + } @Override - SqmPredicate arrayOverlapsNullable(Expression arrayExpression1, Expression arrayExpression2); + default SqmPredicate arrayOverlapsNullable(Expression arrayExpression1, Expression arrayExpression2) { + return arrayIntersectsNullable( arrayExpression1, arrayExpression2 ); + } @Override - SqmPredicate arrayOverlapsNullable(Expression arrayExpression1, T[] array2); + default SqmPredicate arrayOverlapsNullable(Expression arrayExpression1, T[] array2) { + return arrayIntersectsNullable( arrayExpression1, array2 ); + } @Override - SqmPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2); + default SqmPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2) { + return arrayIntersectsNullable( array1, arrayExpression2 ); + } + + @Override + SqmPredicate arrayIntersects(Expression arrayExpression1, Expression arrayExpression2); + + @Override + SqmPredicate arrayIntersects(Expression arrayExpression1, T[] array2); + + @Override + SqmPredicate arrayIntersects(T[] array1, Expression arrayExpression2); + + @Override + SqmPredicate arrayIntersectsNullable(Expression arrayExpression1, Expression arrayExpression2); + + @Override + SqmPredicate arrayIntersectsNullable(Expression arrayExpression1, T[] array2); + + @Override + SqmPredicate arrayIntersectsNullable(T[] array1, Expression arrayExpression2); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Array functions for collection types @@ -463,22 +493,52 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { SqmPredicate collectionContainsAllNullable(Collection collection, Expression> subCollectionExpression); @Override - SqmPredicate collectionOverlaps(Expression> collectionExpression1, Expression> collectionExpression2); + default SqmPredicate collectionOverlaps(Expression> collectionExpression1, Expression> collectionExpression2) { + return collectionIntersects( collectionExpression1, collectionExpression2 ); + } @Override - SqmPredicate collectionOverlaps(Expression> collectionExpression1, Collection collection2); + default SqmPredicate collectionOverlaps(Expression> collectionExpression1, Collection collection2) { + return collectionIntersects( collectionExpression1, collection2 ); + } @Override - SqmPredicate collectionOverlaps(Collection collection1, Expression> collectionExpression2); + default SqmPredicate collectionOverlaps(Collection collection1, Expression> collectionExpression2) { + return collectionIntersects( collection1, collectionExpression2 ); + } @Override - SqmPredicate collectionOverlapsNullable(Expression> collectionExpression1, Expression> collectionExpression2); + default SqmPredicate collectionOverlapsNullable(Expression> collectionExpression1, Expression> collectionExpression2) { + return collectionIntersectsNullable( collectionExpression1, collectionExpression2 ); + } @Override - SqmPredicate collectionOverlapsNullable(Expression> collectionExpression1, Collection collection2); + default SqmPredicate collectionOverlapsNullable(Expression> collectionExpression1, Collection collection2) { + return collectionIntersectsNullable( collectionExpression1, collection2 ); + } @Override - SqmPredicate collectionOverlapsNullable(Collection collection1, Expression> collectionExpression2); + default SqmPredicate collectionOverlapsNullable(Collection collection1, Expression> collectionExpression2) { + return collectionIntersectsNullable( collection1, collectionExpression2 ); + } + + @Override + SqmPredicate collectionIntersects(Expression> collectionExpression1, Expression> collectionExpression2); + + @Override + SqmPredicate collectionIntersects(Expression> collectionExpression1, Collection collection2); + + @Override + SqmPredicate collectionIntersects(Collection collection1, Expression> collectionExpression2); + + @Override + SqmPredicate collectionIntersectsNullable(Expression> collectionExpression1, Expression> collectionExpression2); + + @Override + SqmPredicate collectionIntersectsNullable(Expression> collectionExpression1, Collection collection2); + + @Override + SqmPredicate collectionIntersectsNullable(Collection collection1, Expression> collectionExpression2); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Covariant overrides diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index fd645b964d..470687b39d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -3987,8 +3987,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, } @Override - public SqmPredicate arrayOverlaps(Expression arrayExpression1, Expression arrayExpression2) { - return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression( + public SqmPredicate arrayIntersects(Expression arrayExpression1, Expression 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 SqmPredicate arrayOverlaps(Expression arrayExpression1, T[] array2) { - return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression( + public SqmPredicate arrayIntersects(Expression 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 SqmPredicate arrayOverlaps(T[] array1, Expression arrayExpression2) { - return isTrue( getFunctionDescriptor( "array_overlaps" ).generateSqmExpression( + public SqmPredicate arrayIntersects(T[] array1, Expression 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 SqmPredicate arrayOverlapsNullable( + public SqmPredicate arrayIntersectsNullable( Expression arrayExpression1, Expression 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 SqmPredicate arrayOverlapsNullable(Expression arrayExpression1, T[] array2) { - return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression( + public SqmPredicate arrayIntersectsNullable(Expression 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 SqmPredicate arrayOverlapsNullable(T[] array1, Expression arrayExpression2) { - return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression( + public SqmPredicate arrayIntersectsNullable(T[] array1, Expression 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 SqmPredicate collectionOverlaps( + public SqmPredicate collectionIntersects( Expression> collectionExpression1, Expression> 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 SqmPredicate collectionOverlaps( + public SqmPredicate collectionIntersects( Expression> collectionExpression1, Collection 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 SqmPredicate collectionOverlaps( + public SqmPredicate collectionIntersects( Collection collection1, Expression> 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 SqmPredicate collectionOverlapsNullable( + public SqmPredicate collectionIntersectsNullable( Expression> collectionExpression1, Expression> 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 SqmPredicate collectionOverlapsNullable( + public SqmPredicate collectionIntersectsNullable( Expression> collectionExpression1, Collection 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 SqmPredicate collectionOverlapsNullable( + public SqmPredicate collectionIntersectsNullable( Collection collection1, Expression> collectionExpression2) { - return isTrue( getFunctionDescriptor( "array_overlaps_nullable" ).generateSqmExpression( + return isTrue( getFunctionDescriptor( "array_intersects_nullable" ).generateSqmExpression( asList( value( collection1, (SqmExpression) collectionExpression2 ), (SqmExpression) collectionExpression2 ), null, queryEngine diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayIntersectsTest.java similarity index 50% rename from hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayIntersectsTest.java index 75fa2fbf9d..ad9029f1f9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayIntersectsTest.java @@ -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 results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc', 'def'))", EntityWithArrays.class ) + //tag::hql-array-intersects-example[] + List 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 results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('xyz'))", EntityWithArrays.class ) + List 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 results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc','xyz'))", EntityWithArrays.class ) + List 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 results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array(null))", EntityWithArrays.class ) + List 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 results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array('xyz',null))", EntityWithArrays.class ) + //tag::hql-array-intersects-nullable-example[] + List 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 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.get( "theArray" ), cb.arrayLiteral( "xyz" ) ); -// cb.arrayOverlaps( root.get( "theArray" ), new String[]{ "xyz" } ); -// cb.arrayOverlaps( new String[0], cb.literal( 1 ) ); -// cb.arrayOverlaps( new Integer[0], cb.literal( "" ) ); -// cb.arrayOverlapsNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ); -// cb.arrayOverlapsNullable( root.get( "theArray" ), new String[]{ "xyz" } ); -// cb.arrayOverlapsNullable( new String[0], cb.literal( 1 ) ); -// cb.arrayOverlapsNullable( new Integer[0], cb.literal( "" ) ); +// cb.arrayIntersects( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ); +// cb.arrayIntersects( root.get( "theArray" ), new String[]{ "xyz" } ); +// cb.arrayIntersects( new String[0], cb.literal( 1 ) ); +// cb.arrayIntersects( new Integer[0], cb.literal( "" ) ); +// cb.arrayIntersectsNullable( root.get( "theArray" ), cb.arrayLiteral( "xyz" ) ); +// cb.arrayIntersectsNullable( root.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 root = cq.from( EntityWithArrays.class ); cq.multiselect( root.get( "id" ), - cb.collectionOverlaps( root.>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.>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.>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.>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.>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ); -// cb.collectionOverlaps( root.>get( "theCollection" ), List.of( "xyz" ) ); -// cb.collectionOverlaps( Collections.emptyList(), cb.literal( 1 ) ); -// cb.collectionOverlaps( Collections.emptyList(), cb.literal( "" ) ); -// cb.collectionOverlapsNullable( root.>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ); -// cb.collectionOverlapsNullable( root.>get( "theCollection" ), List.of( "xyz" ) ); -// cb.collectionOverlapsNullable( Collections.emptyList(), cb.literal( 1 ) ); -// cb.collectionOverlapsNullable( Collections.emptyList(), cb.literal( "" ) ); +// cb.collectionIntersects( root.>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ); +// cb.collectionIntersects( root.>get( "theCollection" ), List.of( "xyz" ) ); +// cb.collectionIntersects( Collections.emptyList(), cb.literal( 1 ) ); +// cb.collectionIntersects( Collections.emptyList(), cb.literal( "" ) ); +// cb.collectionIntersectsNullable( root.>get( "theCollection" ), cb.collectionLiteral( "xyz" ) ); +// cb.collectionIntersectsNullable( root.>get( "theCollection" ), List.of( "xyz" ) ); +// cb.collectionIntersectsNullable( Collections.emptyList(), cb.literal( 1 ) ); +// cb.collectionIntersectsNullable( Collections.emptyList(), cb.literal( "" ) ); + } ); + } + + @Test + public void testIntersectsSyntax(SessionFactoryScope scope) { + scope.inSession( em -> { + //tag::hql-array-intersects-hql-example[] + List 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() ); } ); } diff --git a/release-announcement.adoc b/release-announcement.adoc index 172ad37bc1..7437439809 100644 --- a/release-announcement.adoc +++ b/release-announcement.adoc @@ -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 +|=== +