common_function/scalars/json/
json_is.rs1use std::fmt::{self, Display};
16use std::sync::Arc;
17
18use datafusion_common::arrow::array::{Array, AsArray, BooleanBuilder};
19use datafusion_common::arrow::compute;
20use datafusion_common::arrow::datatypes::DataType;
21use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, Signature, Volatility};
22
23use crate::function::{Function, extract_args};
24
25macro_rules! json_is {
27 ($name:ident, $json_type:ident, $doc:expr) => {
28 paste::paste! {
29 json_is!($name, $doc, jsonb::RawJsonb::[<is_ $json_type>]);
30 }
31 };
32 ($name:ident, $doc:expr, $check:path) => {
33 paste::paste! {
34 #[derive(Clone, Debug)]
35 pub(crate) struct $name {
36 signature: Signature,
37 }
38
39 impl Default for $name {
40 fn default() -> Self {
41 Self {
42 signature: Signature::uniform(
44 1,
45 vec![DataType::Binary, DataType::BinaryView],
46 Volatility::Immutable,
47 ),
48 }
49 }
50 }
51
52 impl Function for $name {
53 fn name(&self) -> &str {
54 stringify!([<$name:snake>])
55 }
56
57 fn return_type(&self, _: &[DataType]) -> datafusion_common::Result<DataType> {
58 Ok(DataType::Boolean)
59 }
60
61 fn signature(&self) -> &Signature {
62 &self.signature
63 }
64
65 fn invoke_with_args(
66 &self,
67 args: ScalarFunctionArgs,
68 ) -> datafusion_common::Result<ColumnarValue> {
69 let [arg0] = extract_args(self.name(), &args)?;
70
71 let arg0 = compute::cast(&arg0, &DataType::BinaryView)?;
72 let jsons = arg0.as_binary_view();
73 let size = jsons.len();
74 let mut builder = BooleanBuilder::with_capacity(size);
75
76 for i in 0..size {
77 let json = jsons.is_valid(i).then(|| jsons.value(i));
78 let result = match json {
79 Some(json) => {
80 Some($check(&jsonb::RawJsonb::new(json)).map_err(|e| datafusion_common::DataFusionError::Execution(e.to_string()))?)
81 }
82 _ => None,
83 };
84 builder.append_option(result);
85 }
86
87 Ok(ColumnarValue::Array(Arc::new(builder.finish())))
88 }
89 }
90
91 impl Display for $name {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 write!(f, "{}", stringify!([<$name:snake>]).to_ascii_uppercase())
94 }
95 }
96 }
97 };
98}
99
100fn is_jsonb_integer(value: &jsonb::RawJsonb<'_>) -> Result<bool, jsonb::Error> {
103 Ok(match value.as_number()? {
104 Some(jsonb::Number::Int64(_)) => true,
105 Some(jsonb::Number::UInt64(value)) => i64::try_from(value).is_ok(),
106 _ => false,
107 })
108}
109
110json_is!(JsonIsNull, null, "Checks if the input JSONB is null");
111json_is!(
112 JsonIsBool,
113 boolean,
114 "Checks if the input JSONB is a boolean type JSON value"
115);
116json_is!(
117 JsonIsInt,
118 "Checks if the input JSONB is an integer type JSON value",
119 is_jsonb_integer
120);
121json_is!(
122 JsonIsFloat,
123 number,
124 "Checks if the input JSONB is a JSON float"
125);
126json_is!(
127 JsonIsString,
128 string,
129 "Checks if the input JSONB is a JSON string"
130);
131json_is!(
132 JsonIsArray,
133 array,
134 "Checks if the input JSONB is a JSON array"
135);
136json_is!(
137 JsonIsObject,
138 object,
139 "Checks if the input JSONB is a JSON object"
140);
141
142#[cfg(test)]
143mod tests {
144 use std::sync::Arc;
145
146 use arrow_schema::Field;
147 use datafusion_common::arrow::array::{AsArray, BinaryArray};
148
149 use super::*;
150
151 #[test]
152 fn test_json_is_functions() {
153 let json_is_functions: [&dyn Function; 6] = [
154 &JsonIsBool::default(),
155 &JsonIsInt::default(),
156 &JsonIsFloat::default(),
157 &JsonIsString::default(),
158 &JsonIsArray::default(),
159 &JsonIsObject::default(),
160 ];
161 let expected_names = [
162 "json_is_bool",
163 "json_is_int",
164 "json_is_float",
165 "json_is_string",
166 "json_is_array",
167 "json_is_object",
168 ];
169 for (func, expected_name) in json_is_functions.iter().zip(expected_names.iter()) {
170 assert_eq!(func.name(), *expected_name);
171 assert_eq!(
172 func.return_type(&[DataType::Binary]).unwrap(),
173 DataType::Boolean
174 );
175 }
176
177 let json_strings = [
178 r#"true"#,
179 r#"1"#,
180 r#"1.0"#,
181 r#""The pig fly through a castle, and has been attracted by the princess.""#,
182 r#"[1, 2]"#,
183 r#"{"a": 1}"#,
184 ];
185 let expected_results = [
186 [true, false, false, false, false, false],
187 [false, true, false, false, false, false],
188 [false, true, true, false, false, false],
190 [false, false, false, true, false, false],
191 [false, false, false, false, true, false],
192 [false, false, false, false, false, true],
193 ];
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 let args = ScalarFunctionArgs {
203 args: vec![ColumnarValue::Array(Arc::new(
204 BinaryArray::from_iter_values(jsonbs),
205 ))],
206 arg_fields: vec![],
207 number_rows: 6,
208 return_field: Arc::new(Field::new("", DataType::Boolean, false)),
209 config_options: Arc::new(Default::default()),
210 };
211
212 for (func, expected_result) in json_is_functions.iter().zip(expected_results.iter()) {
213 let result = func
214 .invoke_with_args(args.clone())
215 .and_then(|x| x.to_array(6))
216 .unwrap();
217 let vector = result.as_boolean();
218 assert_eq!(vector.len(), json_strings.len());
219
220 for (i, expected) in expected_result.iter().enumerate() {
221 let result = vector.value(i);
222 assert_eq!(result, *expected);
223 }
224 }
225 }
226}