Skip to content

Commit 6b4cc28

Browse files
committed
HHH-18496 Add json_query
1 parent 6454aaf commit 6b4cc28

File tree

48 files changed

+1837
-110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1837
-110
lines changed

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

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,7 @@ The following functions deal with SQL JSON types, which are not supported on eve
16331633
| `json_array()` | Constructs a JSON array from arguments
16341634
| `json_value()` | Extracts a value from a JSON document by JSON path
16351635
| `json_exists()` | Checks if a JSON path exists in a JSON document
1636+
| `json_query()` | Queries non-scalar values by JSON path in a JSON document
16361637
|===
16371638
16381639
@@ -1712,7 +1713,7 @@ include::{extrasdir}/json_value_bnf.txt[]
17121713
17131714
The first argument is an expression to a JSON document. The second argument is a JSON path as String expression.
17141715
1715-
WARNING: Some databases might also return non-scalar values. Beware that this behavior is not portable.
1716+
WARNING: Some databases might also allow extracting non-scalar values. Beware that this behavior is not portable.
17161717
17171718
NOTE: It is recommended to only us the dot notation for JSON paths instead of the bracket notation,
17181719
since most databases support only that.
@@ -1832,6 +1833,92 @@ include::{json-example-dir-hql}/JsonExistsTest.java[tags=hql-json-exists-on-erro
18321833
18331834
NOTE: The H2 emulation only supports absolute JSON paths using the dot notation.
18341835
1836+
[[hql-json-query-function]]
1837+
===== `json_query()`
1838+
1839+
Queries non-scalar values from a JSON document by a https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html[JSON path].
1840+
1841+
[[hql-json-query-bnf]]
1842+
[source, antlrv4, indent=0]
1843+
----
1844+
include::{extrasdir}/json_query_bnf.txt[]
1845+
----
1846+
1847+
The first argument is an expression to a JSON document. The second argument is a JSON path as String expression.
1848+
1849+
WARNING: Some databases might also allow querying scalar values. Beware that this behavior is not portable.
1850+
1851+
NOTE: It is recommended to only us the dot notation for JSON paths instead of the bracket notation,
1852+
since most databases support only that.
1853+
1854+
[[hql-json-query-example]]
1855+
====
1856+
[source, java, indent=0]
1857+
----
1858+
include::{json-example-dir-hql}/JsonQueryTest.java[tags=hql-json-query-example]
1859+
----
1860+
====
1861+
1862+
The `passing` clause allows to reuse the same JSON path but pass different values for evaluation.
1863+
1864+
[[hql-json-query-passing-example]]
1865+
====
1866+
[source, java, indent=0]
1867+
----
1868+
include::{json-example-dir-hql}/JsonQueryTest.java[tags=hql-json-query-passing-example]
1869+
----
1870+
====
1871+
1872+
The `wrapper` clause allows to specify whether results of a query should be wrapped in brackets `[]` i.e. an array.
1873+
The default behavior is to omit an array wrapper i.e. `without wrapper`.
1874+
It is an error when a `json_query` returns more than a single result and `without wrapper` is used.
1875+
How an error like this should be handled can be controlled with the `on error` clause.
1876+
1877+
WARNING: Since the default behavior of `on error` is database dependent,
1878+
some databases might return a comma separated list of values even when using `without wrapper`. This is not portable.
1879+
1880+
[[hql-json-query-wrapper-example]]
1881+
====
1882+
[source, java, indent=0]
1883+
----
1884+
include::{json-example-dir-hql}/JsonQueryTest.java[tags=hql-json-query-with-wrapper-example]
1885+
----
1886+
====
1887+
1888+
The `on error` clause defines the behavior when an error occurs while querying with the JSON path.
1889+
Conditions that classify as errors are database dependent, but usual errors which can be handled with this clause are:
1890+
1891+
* First argument is not a valid JSON document
1892+
* Second argument is not a valid JSON path
1893+
* Multiple `json_query` results when `without wrapper` is used
1894+
1895+
The default behavior of `on error` is database specific, but usually, `null` is returned on an error.
1896+
It is recommended to specify this clause when the exact error behavior is important.
1897+
1898+
[[hql-json-query-on-error-example]]
1899+
====
1900+
[source, java, indent=0]
1901+
----
1902+
include::{json-example-dir-hql}/JsonQueryTest.java[tags=hql-json-query-on-error-example]
1903+
----
1904+
====
1905+
1906+
The `on empty` clause defines the behavior when the JSON path does not match the JSON document.
1907+
By default, `null` is returned on empty.
1908+
1909+
[[hql-json-query-on-empty-example]]
1910+
====
1911+
[source, java, indent=0]
1912+
----
1913+
include::{json-example-dir-hql}/JsonQueryTest.java[tags=hql-json-query-on-empty-example]
1914+
----
1915+
====
1916+
1917+
To actually receive an error `on empty`, it is necessary to also specify `error on error`.
1918+
Depending on the database, an error might still be thrown even without that, but that is not portable.
1919+
1920+
NOTE: The H2 emulation only supports absolute JSON paths using the dot notation.
1921+
18351922
[[hql-user-defined-functions]]
18361923
==== Native and user-defined functions
18371924

documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/json_exists_bnf.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"json_exists(" expression, expression passingClause? onErrorClause? ")"
1+
"json_exists(" expression "," expression passingClause? onErrorClause? ")"
22

33
passingClause
44
: "passing" expression "as" identifier ("," expression "as" identifier)*
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"json_query(" expression "," expression passingClause? wrapperClause? onErrorClause? onEmptyClause? ")"
2+
3+
wrapperClause
4+
: "with" ("conditional"|"unconditional")? "array"? "wrapper"
5+
| "without" "array"? "wrapper"
6+
7+
passingClause
8+
: "passing" expression "as" identifier ("," expression "as" identifier)*
9+
10+
onErrorClause
11+
: ( "error" | "null" | ( "empty" ( "array" | "object" )? ) ) "on error";
12+
13+
onEmptyClause
14+
: ( "error" | "null" | ( "empty" ( "array" | "object" )? ) ) "on empty";

documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/json_value_bnf.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"json_value(" expression, expression passingClause? ("returning" castTarget)? onErrorClause? onEmptyClause? ")"
1+
"json_value(" expression "," expression passingClause? ("returning" castTarget)? onErrorClause? onEmptyClause? ")"
22

33
passingClause
44
: "passing" expression "as" identifier ("," expression "as" identifier)*

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
432432

433433
if ( getDB2Version().isSameOrAfter( 11 ) ) {
434434
functionFactory.jsonValue_no_passing();
435+
functionFactory.jsonQuery_no_passing();
435436
functionFactory.jsonExists_no_passing();
436437
functionFactory.jsonObject_db2();
437438
functionFactory.jsonArray_db2();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
404404

405405
if ( getVersion().isSameOrAfter( 2, 2, 220 ) ) {
406406
functionFactory.jsonValue_h2();
407+
functionFactory.jsonQuery_h2();
407408
functionFactory.jsonExists_h2();
408409
}
409410
}

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
@@ -654,6 +654,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
654654

655655
if ( getMySQLVersion().isSameOrAfter( 5, 7 ) ) {
656656
functionFactory.jsonValue_mysql();
657+
functionFactory.jsonQuery_mysql();
657658
functionFactory.jsonExists_mysql();
658659
functionFactory.jsonObject_mysql();
659660
functionFactory.jsonArray_mysql();

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
@@ -323,6 +323,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
323323

324324
if ( getVersion().isSameOrAfter( 12 ) ) {
325325
functionFactory.jsonValue_oracle();
326+
functionFactory.jsonQuery_oracle();
326327
functionFactory.jsonExists_oracle();
327328
functionFactory.jsonObject_oracle();
328329
functionFactory.jsonArray_oracle();

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,12 +634,14 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
634634

635635
if ( getVersion().isSameOrAfter( 17 ) ) {
636636
functionFactory.jsonValue();
637+
functionFactory.jsonQuery();
637638
functionFactory.jsonExists();
638639
functionFactory.jsonObject();
639640
functionFactory.jsonArray();
640641
}
641642
else {
642643
functionFactory.jsonValue_postgresql();
644+
functionFactory.jsonQuery_postgresql();
643645
functionFactory.jsonExists_postgresql();
644646
if ( getVersion().isSameOrAfter( 16 ) ) {
645647
functionFactory.jsonObject();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
402402
functionFactory.hypotheticalOrderedSetAggregates_windowEmulation();
403403
if ( getVersion().isSameOrAfter( 13 ) ) {
404404
functionFactory.jsonValue_sqlserver();
405+
functionFactory.jsonQuery_sqlserver();
405406
functionFactory.jsonExists_sqlserver();
406407
functionFactory.jsonObject_sqlserver();
407408
functionFactory.jsonArray_sqlserver();

0 commit comments

Comments
 (0)