Skip to content

Commit ab37d15

Browse files
committed
HHH-18604 Add json_mergepatch function
1 parent 051bc78 commit ab37d15

File tree

20 files changed

+516
-6
lines changed

20 files changed

+516
-6
lines changed

documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,7 @@ it is necessary to enable the `hibernate.query.hql.json_functions_enabled` confi
16411641
| `json_objectagg()` | Creates a JSON object by aggregating values
16421642
| `json_set()` | Inserts/Replaces a value by JSON path within a JSON document
16431643
| `json_remove()` | Removes a value by JSON path within a JSON document
1644+
| `json_mergepatch()` | Merges JSON documents by performing an https://tools.ietf.org/html/rfc7396[RFC 7396] compliant merge
16441645
|===
16451646
16461647
@@ -2083,6 +2084,35 @@ include::{json-example-dir-hql}/JsonInsertTest.java[tags=hql-json-insert-example
20832084
20842085
WARNING: SAP HANA, DB2, H2 and HSQLDB do not support this function.
20852086
2087+
[[hql-json-mergepatch-function]]
2088+
===== `json_mergepatch()`
2089+
2090+
Merges JSON documents by performing an https://tools.ietf.org/html/rfc7396[RFC 7396] compliant merge, which is
2091+
2092+
* When the first JSON value is not an object, the result is as if the first argument was an empty object
2093+
* When the second JSON value is not an object, the result is the second argument
2094+
* When both JSON values are objects, members are merged
2095+
** Retain first JSON object members when the second JSON object has no members with matching keys
2096+
** Retain second JSON object members when the first JSON object has no members with matching keys and the value is not equal to the JSON `null` literal
2097+
** Recursively merge values that exist in both JSON objects, except if the second JSON object member is a JSON `null`
2098+
2099+
In simple terms this means
2100+
2101+
* The second JSON overrides members of the first, with JSON `null` values causing members to be removed
2102+
* JSON objects are merged recursively
2103+
2104+
NOTE: Arrays and hence objects within arrays are not merged, but replaced.
2105+
2106+
[[hql-json-mergepatch-example]]
2107+
====
2108+
[source, java, indent=0]
2109+
----
2110+
include::{json-example-dir-hql}/JsonMergepatchTest.java[tags=hql-json-mergepatch-example]
2111+
----
2112+
====
2113+
2114+
WARNING: SAP HANA, DB2, SQL Server, H2 and HSQLDB do not support this function. On PostgreSQL, this function is emulated.
2115+
20862116
[[hql-user-defined-functions]]
20872117
==== Native and user-defined functions
20882118

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
512512
functionFactory.jsonRemove_cockroachdb();
513513
functionFactory.jsonReplace_postgresql();
514514
functionFactory.jsonInsert_postgresql();
515+
functionFactory.jsonMergepatch_postgresql();
515516

516517
// Postgres uses # instead of ^ for XOR
517518
functionContributions.getFunctionRegistry().patternDescriptorBuilder( "bitxor", "(?1#?2)" )

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
664664
functionFactory.jsonRemove_mysql();
665665
functionFactory.jsonReplace_mysql();
666666
functionFactory.jsonInsert_mysql();
667+
functionFactory.jsonMergepatch_mysql();
667668
}
668669
}
669670

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
321321
functionFactory.jsonRemove_oracle();
322322
functionFactory.jsonReplace_oracle();
323323
functionFactory.jsonInsert_oracle();
324+
functionFactory.jsonMergepatch_oracle();
324325
}
325326
}
326327

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
662662
functionFactory.jsonRemove_postgresql();
663663
functionFactory.jsonReplace_postgresql();
664664
functionFactory.jsonInsert_postgresql();
665+
functionFactory.jsonMergepatch_postgresql();
665666

666667
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
667668
functionFactory.makeDateTimeTimestamp();

hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
479479
functionFactory.jsonRemove_cockroachdb();
480480
functionFactory.jsonReplace_postgresql();
481481
functionFactory.jsonInsert_postgresql();
482+
functionFactory.jsonMergepatch_postgresql();
482483

483484
// Postgres uses # instead of ^ for XOR
484485
functionContributions.getFunctionRegistry().patternDescriptorBuilder( "bitxor", "(?1#?2)" )

hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
649649
functionFactory.jsonRemove_mysql();
650650
functionFactory.jsonReplace_mysql();
651651
functionFactory.jsonInsert_mysql();
652+
functionFactory.jsonMergepatch_mysql();
652653
}
653654

654655
@Override

hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
412412
functionFactory.jsonRemove_oracle();
413413
functionFactory.jsonReplace_oracle();
414414
functionFactory.jsonInsert_oracle();
415+
functionFactory.jsonMergepatch_oracle();
415416
}
416417

417418
@Override

hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
623623
functionFactory.jsonRemove_postgresql();
624624
functionFactory.jsonReplace_postgresql();
625625
functionFactory.jsonInsert_postgresql();
626+
functionFactory.jsonMergepatch_postgresql();
626627

627628
functionFactory.makeDateTimeTimestamp();
628629
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions

hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,8 @@
9797
import org.hibernate.dialect.function.json.HSQLJsonArrayAggFunction;
9898
import org.hibernate.dialect.function.json.HSQLJsonArrayFunction;
9999
import org.hibernate.dialect.function.json.HSQLJsonObjectFunction;
100-
import org.hibernate.dialect.function.json.JsonArrayAggFunction;
101100
import org.hibernate.dialect.function.json.JsonArrayFunction;
102101
import org.hibernate.dialect.function.json.JsonExistsFunction;
103-
import org.hibernate.dialect.function.json.JsonObjectAggFunction;
104102
import org.hibernate.dialect.function.json.JsonObjectFunction;
105103
import org.hibernate.dialect.function.json.JsonQueryFunction;
106104
import org.hibernate.dialect.function.json.JsonValueFunction;
@@ -119,6 +117,7 @@
119117
import org.hibernate.dialect.function.json.OracleJsonArrayAggFunction;
120118
import org.hibernate.dialect.function.json.OracleJsonArrayFunction;
121119
import org.hibernate.dialect.function.json.OracleJsonInsertFunction;
120+
import org.hibernate.dialect.function.json.OracleJsonMergepatchFunction;
122121
import org.hibernate.dialect.function.json.OracleJsonObjectAggFunction;
123122
import org.hibernate.dialect.function.json.OracleJsonObjectFunction;
124123
import org.hibernate.dialect.function.json.OracleJsonRemoveFunction;
@@ -128,6 +127,7 @@
128127
import org.hibernate.dialect.function.json.PostgreSQLJsonArrayFunction;
129128
import org.hibernate.dialect.function.json.PostgreSQLJsonExistsFunction;
130129
import org.hibernate.dialect.function.json.PostgreSQLJsonInsertFunction;
130+
import org.hibernate.dialect.function.json.PostgreSQLJsonMergepatchFunction;
131131
import org.hibernate.dialect.function.json.PostgreSQLJsonObjectAggFunction;
132132
import org.hibernate.dialect.function.json.PostgreSQLJsonObjectFunction;
133133
import org.hibernate.dialect.function.json.PostgreSQLJsonQueryFunction;
@@ -3977,4 +3977,34 @@ public void jsonInsert_oracle() {
39773977
public void jsonInsert_sqlserver() {
39783978
functionRegistry.register( "json_insert", new SQLServerJsonInsertFunction( typeConfiguration ) );
39793979
}
3980+
3981+
/**
3982+
* PostgreSQL json_mergepatch() function
3983+
*/
3984+
public void jsonMergepatch_postgresql() {
3985+
functionRegistry.register( "json_mergepatch", new PostgreSQLJsonMergepatchFunction( typeConfiguration ) );
3986+
}
3987+
3988+
/**
3989+
* MySQL json_mergepatch() function
3990+
*/
3991+
public void jsonMergepatch_mysql() {
3992+
functionRegistry.namedDescriptorBuilder( "json_mergepatch", "json_merge_patch" )
3993+
.setArgumentsValidator( new ArgumentTypesValidator(
3994+
StandardArgumentsValidators.min( 2 ),
3995+
FunctionParameterType.IMPLICIT_JSON,
3996+
FunctionParameterType.IMPLICIT_JSON
3997+
) )
3998+
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant(
3999+
typeConfiguration.getBasicTypeRegistry().resolve( String.class, SqlTypes.JSON )
4000+
) )
4001+
.register();
4002+
}
4003+
4004+
/**
4005+
* Oracle json_mergepatch() function
4006+
*/
4007+
public void jsonMergepatch_oracle() {
4008+
functionRegistry.register( "json_mergepatch", new OracleJsonMergepatchFunction( typeConfiguration ) );
4009+
}
39804010
}

0 commit comments

Comments
 (0)