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}