risingwave_expr_impl/scalar/
jsonb_path.rs1use jsonbb::ValueRef;
16use risingwave_common::types::{JsonbRef, JsonbVal};
17use risingwave_expr::{ExprError, Result, function};
18use sql_json_path::{EvalError, JsonPath, ParseError};
19use thiserror_ext::AsReport;
20
21#[function(
22 "jsonb_path_exists(jsonb, varchar) -> boolean",
23 prebuild = "JsonPath::new($1).map_err(parse_error)?"
24)]
25fn jsonb_path_exists2(target: JsonbRef<'_>, path: &JsonPath) -> Result<bool> {
26 path.exists::<ValueRef<'_>>(target.into())
27 .map_err(eval_error)
28}
29
30#[function(
31 "jsonb_path_exists(jsonb, varchar, jsonb) -> boolean",
32 prebuild = "JsonPath::new($1).map_err(parse_error)?"
33)]
34fn jsonb_path_exists3(target: JsonbRef<'_>, vars: JsonbRef<'_>, path: &JsonPath) -> Result<bool> {
35 path.exists_with_vars::<ValueRef<'_>>(target.into(), vars.into())
36 .map_err(eval_error)
37}
38
39#[function(
54 "jsonb_path_exists(jsonb, varchar, jsonb, boolean) -> boolean",
55 prebuild = "JsonPath::new($1).map_err(parse_error)?"
56)]
57fn jsonb_path_exists4(
58 target: JsonbRef<'_>,
59 vars: JsonbRef<'_>,
60 silent: bool,
61 path: &JsonPath,
62) -> Result<Option<bool>> {
63 match jsonb_path_exists3(target, vars, path) {
64 Ok(x) => Ok(Some(x)),
65 Err(_) if silent => Ok(None),
66 Err(e) => Err(e),
67 }
68}
69
70#[function(
71 "jsonb_path_match(jsonb, varchar) -> boolean",
72 prebuild = "JsonPath::new($1).map_err(parse_error)?"
73)]
74fn jsonb_path_match2(target: JsonbRef<'_>, path: &JsonPath) -> Result<Option<bool>> {
75 let matched = path
76 .query::<ValueRef<'_>>(target.into())
77 .map_err(eval_error)?;
78
79 if matched.len() != 1 || !matched[0].as_ref().is_boolean() && !matched[0].as_ref().is_null() {
80 return Err(ExprError::InvalidParam {
81 name: "jsonb_path_match",
82 reason: "single boolean result is expected".into(),
83 });
84 }
85 Ok(matched[0].as_ref().as_bool())
86}
87
88#[function(
89 "jsonb_path_match(jsonb, varchar, jsonb) -> boolean",
90 prebuild = "JsonPath::new($1).map_err(parse_error)?"
91)]
92fn jsonb_path_match3(
93 target: JsonbRef<'_>,
94 vars: JsonbRef<'_>,
95 path: &JsonPath,
96) -> Result<Option<bool>> {
97 let matched = path
98 .query_with_vars::<ValueRef<'_>>(target.into(), vars.into())
99 .map_err(eval_error)?;
100
101 if matched.len() != 1 || !matched[0].as_ref().is_boolean() && !matched[0].as_ref().is_null() {
102 return Err(ExprError::InvalidParam {
103 name: "jsonb_path_match",
104 reason: "single boolean result is expected".into(),
105 });
106 }
107 Ok(matched[0].as_ref().as_bool())
108}
109
110#[function(
124 "jsonb_path_match(jsonb, varchar, jsonb, boolean) -> boolean",
125 prebuild = "JsonPath::new($1).map_err(parse_error)?"
126)]
127fn jsonb_path_match4(
128 target: JsonbRef<'_>,
129 vars: JsonbRef<'_>,
130 silent: bool,
131 path: &JsonPath,
132) -> Result<Option<bool>> {
133 match jsonb_path_match3(target, vars, path) {
134 Ok(x) => Ok(x),
135 Err(_) if silent => Ok(None),
136 Err(e) => Err(e),
137 }
138}
139
140#[function(
141 "jsonb_path_query(jsonb, varchar) -> setof jsonb",
142 prebuild = "JsonPath::new($1).map_err(parse_error)?"
143)]
144fn jsonb_path_query2<'a>(
145 target: JsonbRef<'a>,
146 path: &JsonPath,
147) -> Result<impl Iterator<Item = JsonbVal> + 'a> {
148 let matched = path
149 .query::<ValueRef<'_>>(target.into())
150 .map_err(eval_error)?;
151 Ok(matched.into_iter().map(|json| json.into_owned().into()))
152}
153
154#[function(
155 "jsonb_path_query(jsonb, varchar, jsonb) -> setof jsonb",
156 prebuild = "JsonPath::new($1).map_err(parse_error)?"
157)]
158fn jsonb_path_query3<'a>(
159 target: JsonbRef<'a>,
160 vars: JsonbRef<'a>,
161 path: &JsonPath,
162) -> Result<impl Iterator<Item = JsonbVal> + 'a> {
163 let matched = path
164 .query_with_vars::<ValueRef<'_>>(target.into(), vars.into())
165 .map_err(eval_error)?;
166 Ok(matched.into_iter().map(|json| json.into_owned().into()))
167}
168
169#[function(
183 "jsonb_path_query(jsonb, varchar, jsonb, boolean) -> setof jsonb",
184 prebuild = "JsonPath::new($1).map_err(parse_error)?"
185)]
186fn jsonb_path_query4<'a>(
187 target: JsonbRef<'a>,
188 vars: JsonbRef<'a>,
189 silent: bool,
190 path: &JsonPath,
191) -> Result<Option<impl Iterator<Item = JsonbVal> + 'a>> {
192 match jsonb_path_query3(target, vars, path) {
193 Ok(x) => Ok(Some(x)),
194 Err(_) if silent => Ok(None),
195 Err(e) => Err(e),
196 }
197}
198
199#[function(
200 "jsonb_path_query_array(jsonb, varchar) -> jsonb",
201 prebuild = "JsonPath::new($1).map_err(parse_error)?"
202)]
203fn jsonb_path_query_array2(
204 target: JsonbRef<'_>,
205 path: &JsonPath,
206 writer: &mut jsonbb::Builder,
207) -> Result<()> {
208 let matched = path
209 .query::<ValueRef<'_>>(target.into())
210 .map_err(eval_error)?;
211 writer.begin_array();
212 for json in matched {
213 writer.add_value(json.as_ref());
214 }
215 writer.end_array();
216 Ok(())
217}
218
219#[function(
220 "jsonb_path_query_array(jsonb, varchar, jsonb) -> jsonb",
221 prebuild = "JsonPath::new($1).map_err(parse_error)?"
222)]
223fn jsonb_path_query_array3(
224 target: JsonbRef<'_>,
225 vars: JsonbRef<'_>,
226 path: &JsonPath,
227 writer: &mut jsonbb::Builder,
228) -> Result<()> {
229 let matched = path
230 .query_with_vars::<ValueRef<'_>>(target.into(), vars.into())
231 .map_err(eval_error)?;
232 writer.begin_array();
233 for json in matched {
234 writer.add_value(json.as_ref());
235 }
236 writer.end_array();
237 Ok(())
238}
239
240#[function(
252 "jsonb_path_query_array(jsonb, varchar, jsonb, boolean) -> jsonb",
253 prebuild = "JsonPath::new($1).map_err(parse_error)?"
254)]
255fn jsonb_path_query_array4(
256 target: JsonbRef<'_>,
257 vars: JsonbRef<'_>,
258 silent: bool,
259 path: &JsonPath,
260 writer: &mut jsonbb::Builder,
261) -> Result<Option<()>> {
262 match jsonb_path_query_array3(target, vars, path, writer) {
263 Ok(()) => Ok(Some(())),
264 Err(_) if silent => Ok(None),
265 Err(e) => Err(e),
266 }
267}
268
269#[function(
270 "jsonb_path_query_first(jsonb, varchar) -> jsonb",
271 prebuild = "JsonPath::new($1).map_err(parse_error)?"
272)]
273fn jsonb_path_query_first2(
274 target: JsonbRef<'_>,
275 path: &JsonPath,
276 writer: &mut jsonbb::Builder,
277) -> Result<Option<()>> {
278 let matched = path
279 .query_first::<ValueRef<'_>>(target.into())
280 .map_err(eval_error)?;
281 match matched {
282 Some(json) => {
283 writer.add_value(json.as_ref());
284 Ok(Some(()))
285 }
286 None => Ok(None),
287 }
288}
289
290#[function(
291 "jsonb_path_query_first(jsonb, varchar, jsonb) -> jsonb",
292 prebuild = "JsonPath::new($1).map_err(parse_error)?"
293)]
294fn jsonb_path_query_first3(
295 target: JsonbRef<'_>,
296 vars: JsonbRef<'_>,
297 path: &JsonPath,
298 writer: &mut jsonbb::Builder,
299) -> Result<Option<()>> {
300 let matched = path
301 .query_first_with_vars::<ValueRef<'_>>(target.into(), vars.into())
302 .map_err(eval_error)?;
303 match matched {
304 Some(json) => {
305 writer.add_value(json.as_ref());
306 Ok(Some(()))
307 }
308 None => Ok(None),
309 }
310}
311
312#[function(
325 "jsonb_path_query_first(jsonb, varchar, jsonb, boolean) -> jsonb",
326 prebuild = "JsonPath::new($1).map_err(parse_error)?"
327)]
328fn jsonb_path_query_first4(
329 target: JsonbRef<'_>,
330 vars: JsonbRef<'_>,
331 silent: bool,
332 path: &JsonPath,
333 writer: &mut jsonbb::Builder,
334) -> Result<Option<()>> {
335 match jsonb_path_query_first3(target, vars, path, writer) {
336 Ok(x) => Ok(x),
337 Err(_) if silent => Ok(None),
338 Err(e) => Err(e),
339 }
340}
341
342fn parse_error(e: ParseError) -> ExprError {
343 ExprError::Parse(e.to_report_string().into())
344}
345
346fn eval_error(e: EvalError) -> ExprError {
347 ExprError::InvalidParam {
348 name: "jsonpath",
349 reason: e.to_report_string().into(),
350 }
351}