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::ValueRef;
16use risingwave_common::types::JsonbRef;
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<'_>, writer: &mut jsonbb::Builder) {
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            writer.begin_object();
67            for (k, v) in left.iter().chain(right.iter()) {
68                writer.add_string(k);
69                writer.add_value(v);
70            }
71            writer.end_object();
72        }
73
74        // left and right are array-based.
75        // This would merge both arrays into one array.
76        // This would have left:[1,2], right:[3,4] -> [1,2,3,4]
77        (ValueRef::Array(left), ValueRef::Array(right)) => {
78            writer.begin_array();
79            for v in left.iter().chain(right.iter()) {
80                writer.add_value(v);
81            }
82            writer.end_array();
83        }
84
85        // One operand is an array, and the other is a single element.
86        // This would insert the non-array value as another element into the array
87        // Eg left:[1,2] right: {'a':1} -> [1,2,{'a':1}]
88        (ValueRef::Array(left), value) => {
89            writer.begin_array();
90            for v in left.iter() {
91                writer.add_value(v);
92            }
93            writer.add_value(value);
94            writer.end_array();
95        }
96
97        // One operand is an array, and the other is a single element.
98        // This would insert the non-array value as another element into the array
99        // Eg left:{'a':1} right:[1,2] -> [{'a':1},1,2]
100        (value, ValueRef::Array(right)) => {
101            writer.begin_array();
102            writer.add_value(value);
103            for v in right.iter() {
104                writer.add_value(v);
105            }
106            writer.end_array();
107        }
108
109        // Both are non-array inputs.
110        // Both elements would be placed together in an array
111        // Eg left:1 right: 2 -> [1,2]
112        (left, right) => {
113            writer.begin_array();
114            writer.add_value(left);
115            writer.add_value(right);
116            writer.end_array();
117        }
118    }
119}