common_function/scalars/json/
json_path_exists.rs1use std::fmt::{self, Display};
16
17use common_query::error::{InvalidFuncArgsSnafu, Result, UnsupportedInputDataTypeSnafu};
18use common_query::prelude::{Signature, TypeSignature};
19use datafusion::logical_expr::Volatility;
20use datatypes::data_type::ConcreteDataType;
21use datatypes::prelude::VectorRef;
22use datatypes::scalars::ScalarVectorBuilder;
23use datatypes::vectors::{BooleanVectorBuilder, MutableVector};
24use snafu::ensure;
25
26use crate::function::{Function, FunctionContext};
27
28#[derive(Clone, Debug, Default)]
30pub struct JsonPathExistsFunction;
31
32const NAME: &str = "json_path_exists";
33
34impl Function for JsonPathExistsFunction {
35 fn name(&self) -> &str {
36 NAME
37 }
38
39 fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result<ConcreteDataType> {
40 Ok(ConcreteDataType::boolean_datatype())
41 }
42
43 fn signature(&self) -> Signature {
44 Signature::one_of(
45 vec![
46 TypeSignature::Exact(vec![
47 ConcreteDataType::json_datatype(),
48 ConcreteDataType::string_datatype(),
49 ]),
50 TypeSignature::Exact(vec![
51 ConcreteDataType::null_datatype(),
52 ConcreteDataType::string_datatype(),
53 ]),
54 TypeSignature::Exact(vec![
55 ConcreteDataType::json_datatype(),
56 ConcreteDataType::null_datatype(),
57 ]),
58 TypeSignature::Exact(vec![
59 ConcreteDataType::null_datatype(),
60 ConcreteDataType::null_datatype(),
61 ]),
62 ],
63 Volatility::Immutable,
64 )
65 }
66
67 fn eval(&self, _func_ctx: &FunctionContext, columns: &[VectorRef]) -> Result<VectorRef> {
68 ensure!(
69 columns.len() == 2,
70 InvalidFuncArgsSnafu {
71 err_msg: format!(
72 "The length of the args is not correct, expect exactly two, have: {}",
73 columns.len()
74 ),
75 }
76 );
77 let jsons = &columns[0];
78 let paths = &columns[1];
79
80 let size = jsons.len();
81 let mut results = BooleanVectorBuilder::with_capacity(size);
82
83 match (jsons.data_type(), paths.data_type()) {
84 (ConcreteDataType::Binary(_), ConcreteDataType::String(_)) => {
85 for i in 0..size {
86 let result = match (jsons.get_ref(i).as_binary(), paths.get_ref(i).as_string())
87 {
88 (Ok(Some(json)), Ok(Some(path))) => {
89 let json_path = match jsonb::jsonpath::parse_json_path(path.as_bytes())
91 {
92 Ok(json_path) => json_path,
93 Err(_) => {
94 return InvalidFuncArgsSnafu {
95 err_msg: format!("Illegal json path: {:?}", path),
96 }
97 .fail();
98 }
99 };
100 jsonb::path_exists(json, json_path).ok()
101 }
102 _ => None,
103 };
104
105 results.push(result);
106 }
107 }
108
109 (ConcreteDataType::Null(_), ConcreteDataType::String(_)) => results.push_nulls(size),
111 (ConcreteDataType::Binary(_), ConcreteDataType::Null(_)) => results.push_nulls(size),
112 (ConcreteDataType::Null(_), ConcreteDataType::Null(_)) => results.push_nulls(size),
113
114 _ => {
115 return UnsupportedInputDataTypeSnafu {
116 function: NAME,
117 datatypes: columns.iter().map(|c| c.data_type()).collect::<Vec<_>>(),
118 }
119 .fail();
120 }
121 }
122
123 Ok(results.to_vector())
124 }
125}
126
127impl Display for JsonPathExistsFunction {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 write!(f, "JSON_PATH_EXISTS")
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use std::sync::Arc;
136
137 use common_query::prelude::TypeSignature;
138 use datatypes::prelude::ScalarVector;
139 use datatypes::vectors::{BinaryVector, NullVector, StringVector};
140
141 use super::*;
142
143 #[test]
144 fn test_json_path_exists_function() {
145 let json_path_exists = JsonPathExistsFunction;
146
147 assert_eq!("json_path_exists", json_path_exists.name());
148 assert_eq!(
149 ConcreteDataType::boolean_datatype(),
150 json_path_exists
151 .return_type(&[ConcreteDataType::json_datatype()])
152 .unwrap()
153 );
154
155 assert!(matches!(json_path_exists.signature(),
156 Signature {
157 type_signature: TypeSignature::OneOf(valid_types),
158 volatility: Volatility::Immutable
159 } if valid_types ==
160 vec![
161 TypeSignature::Exact(vec![
162 ConcreteDataType::json_datatype(),
163 ConcreteDataType::string_datatype(),
164 ]),
165 TypeSignature::Exact(vec![
166 ConcreteDataType::null_datatype(),
167 ConcreteDataType::string_datatype(),
168 ]),
169 TypeSignature::Exact(vec![
170 ConcreteDataType::json_datatype(),
171 ConcreteDataType::null_datatype(),
172 ]),
173 TypeSignature::Exact(vec![
174 ConcreteDataType::null_datatype(),
175 ConcreteDataType::null_datatype(),
176 ]),
177 ],
178 ));
179
180 let json_strings = [
181 r#"{"a": {"b": 2}, "b": 2, "c": 3}"#,
182 r#"{"a": 4, "b": {"c": 6}, "c": 6}"#,
183 r#"{"a": 7, "b": 8, "c": {"a": 7}}"#,
184 r#"{"a": 7, "b": 8, "c": {"a": 7}}"#,
185 r#"[1, 2, 3]"#,
186 r#"null"#,
187 r#"{"a": 7, "b": 8, "c": {"a": 7}}"#,
188 r#"null"#,
189 ];
190 let paths = vec![
191 "$.a.b.c", "$.b", "$.c.a", ".d", "$[0]", "$.a", "null", "null",
192 ];
193 let expected = [false, true, true, false, true, false, false, false];
194
195 let jsonbs = json_strings
196 .iter()
197 .map(|s| {
198 let value = jsonb::parse_value(s.as_bytes()).unwrap();
199 value.to_vec()
200 })
201 .collect::<Vec<_>>();
202
203 let json_vector = BinaryVector::from_vec(jsonbs);
204 let path_vector = StringVector::from_vec(paths);
205 let args: Vec<VectorRef> = vec![Arc::new(json_vector), Arc::new(path_vector)];
206 let vector = json_path_exists
207 .eval(&FunctionContext::default(), &args)
208 .unwrap();
209
210 assert_eq!(8, vector.len());
212 for (i, real) in expected.iter().enumerate() {
213 let result = vector.get_ref(i);
214 assert!(!result.is_null());
215 let val = result.as_boolean().unwrap().unwrap();
216 assert_eq!(val, *real);
217 }
218
219 let json_bytes = jsonb::parse_value("{}".as_bytes()).unwrap().to_vec();
221 let json = BinaryVector::from_vec(vec![json_bytes]);
222 let illegal_path = StringVector::from_vec(vec!["$..a"]);
223
224 let args: Vec<VectorRef> = vec![Arc::new(json), Arc::new(illegal_path)];
225 let err = json_path_exists.eval(&FunctionContext::default(), &args);
226 assert!(err.is_err());
227
228 let json_bytes = jsonb::parse_value("{}".as_bytes()).unwrap().to_vec();
230 let json = BinaryVector::from_vec(vec![json_bytes]);
231 let null_json = NullVector::new(1);
232
233 let path = StringVector::from_vec(vec!["$.a"]);
234 let null_path = NullVector::new(1);
235
236 let args: Vec<VectorRef> = vec![Arc::new(null_json), Arc::new(path)];
237 let result1 = json_path_exists
238 .eval(&FunctionContext::default(), &args)
239 .unwrap();
240 let args: Vec<VectorRef> = vec![Arc::new(json), Arc::new(null_path)];
241 let result2 = json_path_exists
242 .eval(&FunctionContext::default(), &args)
243 .unwrap();
244
245 assert_eq!(result1.len(), 1);
246 assert!(result1.get_ref(0).is_null());
247 assert_eq!(result2.len(), 1);
248 assert!(result2.get_ref(0).is_null());
249 }
250}