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(target: JsonbRef<'_>, path: &JsonPath) -> Result<JsonbVal> {
204 let matched = path
205 .query::<ValueRef<'_>>(target.into())
206 .map_err(eval_error)?;
207 let array = jsonbb::Value::array(matched.iter().map(|json| json.as_ref()));
208 Ok(array.into())
209}
210
211#[function(
212 "jsonb_path_query_array(jsonb, varchar, jsonb) -> jsonb",
213 prebuild = "JsonPath::new($1).map_err(parse_error)?"
214)]
215fn jsonb_path_query_array3(
216 target: JsonbRef<'_>,
217 vars: JsonbRef<'_>,
218 path: &JsonPath,
219) -> Result<JsonbVal> {
220 let matched = path
221 .query_with_vars::<ValueRef<'_>>(target.into(), vars.into())
222 .map_err(eval_error)?;
223 let array = jsonbb::Value::array(matched.iter().map(|json| json.as_ref()));
224 Ok(array.into())
225}
226
227#[function(
239 "jsonb_path_query_array(jsonb, varchar, jsonb, boolean) -> jsonb",
240 prebuild = "JsonPath::new($1).map_err(parse_error)?"
241)]
242fn jsonb_path_query_array4(
243 target: JsonbRef<'_>,
244 vars: JsonbRef<'_>,
245 silent: bool,
246 path: &JsonPath,
247) -> Result<Option<JsonbVal>> {
248 match jsonb_path_query_array3(target, vars, path) {
249 Ok(x) => Ok(Some(x)),
250 Err(_) if silent => Ok(None),
251 Err(e) => Err(e),
252 }
253}
254
255#[function(
256 "jsonb_path_query_first(jsonb, varchar) -> jsonb",
257 prebuild = "JsonPath::new($1).map_err(parse_error)?"
258)]
259fn jsonb_path_query_first2(target: JsonbRef<'_>, path: &JsonPath) -> Result<Option<JsonbVal>> {
260 let matched = path
261 .query_first::<ValueRef<'_>>(target.into())
262 .map_err(eval_error)?;
263 Ok(matched
264 .into_iter()
265 .next()
266 .map(|json| json.into_owned().into()))
267}
268
269#[function(
270 "jsonb_path_query_first(jsonb, varchar, jsonb) -> jsonb",
271 prebuild = "JsonPath::new($1).map_err(parse_error)?"
272)]
273fn jsonb_path_query_first3(
274 target: JsonbRef<'_>,
275 vars: JsonbRef<'_>,
276 path: &JsonPath,
277) -> Result<Option<JsonbVal>> {
278 let matched = path
279 .query_first_with_vars::<ValueRef<'_>>(target.into(), vars.into())
280 .map_err(eval_error)?;
281 Ok(matched
282 .into_iter()
283 .next()
284 .map(|json| json.into_owned().into()))
285}
286
287#[function(
300 "jsonb_path_query_first(jsonb, varchar, jsonb, boolean) -> jsonb",
301 prebuild = "JsonPath::new($1).map_err(parse_error)?"
302)]
303fn jsonb_path_query_first4(
304 target: JsonbRef<'_>,
305 vars: JsonbRef<'_>,
306 silent: bool,
307 path: &JsonPath,
308) -> Result<Option<JsonbVal>> {
309 match jsonb_path_query_first3(target, vars, path) {
310 Ok(x) => Ok(x),
311 Err(_) if silent => Ok(None),
312 Err(e) => Err(e),
313 }
314}
315
316fn parse_error(e: ParseError) -> ExprError {
317 ExprError::Parse(e.to_report_string().into())
318}
319
320fn eval_error(e: EvalError) -> ExprError {
321 ExprError::InvalidParam {
322 name: "jsonpath",
323 reason: e.to_report_string().into(),
324 }
325}