risingwave_expr_impl/scalar/
jsonb_concat.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use jsonbb::{Value, ValueRef};
16use risingwave_common::types::{JsonbRef, JsonbVal};
17use risingwave_expr::function;
18
19/// Concatenates the two jsonbs.
20///
21/// Examples:
22///
23/// ```slt
24/// # concat
25/// query T
26/// SELECT '[1,2]'::jsonb || '[3,4]'::jsonb;
27/// ----
28/// [1, 2, 3, 4]
29///
30/// query T
31/// SELECT '{"a": 1}'::jsonb || '{"b": 2}'::jsonb;
32/// ----
33/// {"a": 1, "b": 2}
34///
35/// query T
36/// SELECT '[1,2]'::jsonb || '{"a": 1}'::jsonb;
37/// ----
38/// [1, 2, {"a": 1}]
39///
40/// query T
41/// SELECT '1'::jsonb || '2'::jsonb;
42/// ----
43/// [1, 2]
44///
45/// query T
46/// SELECT '[1,2]'::jsonb || 'null'::jsonb;
47/// ----
48/// [1, 2, null]
49///
50/// query T
51/// SELECT 'null'::jsonb || '[1,2]'::jsonb;
52/// ----
53/// [null, 1, 2]
54///
55/// query T
56/// SELECT 'null'::jsonb || '1'::jsonb;
57/// ----
58/// [null, 1]
59/// ```
60#[function("jsonb_concat(jsonb, jsonb) -> jsonb")]
61pub fn jsonb_concat(left: JsonbRef<'_>, right: JsonbRef<'_>) -> JsonbVal {
62    match (left.into(), right.into()) {
63        // left and right are object based.
64        // This would have left:{'a':1}, right:{'b':2} -> {'a':1,'b':2}
65        (ValueRef::Object(left), ValueRef::Object(right)) => {
66            JsonbVal::from(Value::object(left.iter().chain(right.iter())))
67        }
68
69        // left and right are array-based.
70        // This would merge both arrays into one array.
71        // This would have left:[1,2], right:[3,4] -> [1,2,3,4]
72        (ValueRef::Array(left), ValueRef::Array(right)) => {
73            JsonbVal::from(Value::array(left.iter().chain(right.iter())))
74        }
75
76        // One operand is an array, and the other is a single element.
77        // This would insert the non-array value as another element into the array
78        // Eg left:[1,2] right: {'a':1} -> [1,2,{'a':1}]
79        (ValueRef::Array(left), value) => JsonbVal::from(Value::array(left.iter().chain([value]))),
80
81        // One operand is an array, and the other is a single element.
82        // This would insert the non-array value as another element into the array
83        // Eg left:{'a':1} right:[1,2] -> [{'a':1},1,2]
84        (value, ValueRef::Array(right)) => {
85            JsonbVal::from(Value::array([value].into_iter().chain(right.iter())))
86        }
87
88        // Both are non-array inputs.
89        // Both elements would be placed together in an array
90        // Eg left:1 right: 2 -> [1,2]
91        (left, right) => JsonbVal::from(Value::array([left, right])),
92    }
93}