micromegas_datafusion_extensions/jsonb/
keys.rs1use crate::jsonb::list_udfs::{binary_accessor_or_err, binary_dict, dict_fast_path};
2use datafusion::arrow::array::{ArrayRef, ListBuilder, StringBuilder};
3use datafusion::arrow::datatypes::{DataType, Field};
4use datafusion::common::{Result, exec_err};
5use datafusion::error::DataFusionError;
6use datafusion::logical_expr::{
7 ColumnarValue, ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Signature, Volatility,
8};
9use jsonb::RawJsonb;
10use std::sync::Arc;
11
12#[derive(Debug, PartialEq, Eq, Hash)]
21pub struct JsonbObjectKeys {
22 signature: Signature,
23}
24
25impl JsonbObjectKeys {
26 pub fn new() -> Self {
27 Self {
28 signature: Signature::any(1, Volatility::Immutable),
29 }
30 }
31}
32
33impl Default for JsonbObjectKeys {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39fn extract_keys_from_jsonb(jsonb_bytes: &[u8]) -> Result<Option<Vec<String>>> {
40 let jsonb = RawJsonb::new(jsonb_bytes);
41 match jsonb.object_keys() {
42 Ok(Some(keys_jsonb)) => {
43 let keys_raw = keys_jsonb.as_raw();
45 match keys_raw.array_values() {
46 Ok(Some(values)) => {
47 let mut keys = Vec::with_capacity(values.len());
48 for value in values {
49 let raw = value.as_raw();
50 match raw.as_str() {
51 Ok(Some(s)) => keys.push(s.to_string()),
52 Ok(None) => {
53 return Ok(None);
55 }
56 Err(e) => return Err(DataFusionError::External(e.into())),
57 }
58 }
59 Ok(Some(keys))
60 }
61 Ok(None) => Ok(Some(Vec::new())), Err(e) => Err(DataFusionError::External(e.into())),
63 }
64 }
65 Ok(None) => Ok(None), Err(e) => Err(DataFusionError::External(e.into())),
67 }
68}
69
70impl ScalarUDFImpl for JsonbObjectKeys {
71 fn name(&self) -> &str {
72 "jsonb_object_keys"
73 }
74
75 fn signature(&self) -> &Signature {
76 &self.signature
77 }
78
79 fn return_type(&self, _args: &[DataType]) -> Result<DataType> {
80 Ok(DataType::List(Arc::new(Field::new_list_field(
81 DataType::Utf8,
82 true,
83 ))))
84 }
85
86 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
87 let args = ColumnarValue::values_to_arrays(&args.args)?;
88 if args.len() != 1 {
89 return exec_err!("wrong number of arguments to jsonb_object_keys()");
90 }
91
92 Ok(ColumnarValue::Array(build_keys_list(&args[0])?))
93 }
94}
95
96fn append_keys_slot(list_builder: &mut ListBuilder<StringBuilder>, keys: Option<Vec<String>>) {
97 match keys {
98 Some(keys) => {
99 for key in keys {
100 list_builder.values().append_value(key);
101 }
102 list_builder.append(true);
103 }
104 None => list_builder.append(false),
105 }
106}
107
108fn build_keys_list(array: &ArrayRef) -> Result<ArrayRef> {
111 if let Some(dict_array) = binary_dict(array) {
112 let list_builder = ListBuilder::new(StringBuilder::new());
113 return dict_fast_path(dict_array, list_builder, |builder, bytes| {
114 append_keys_slot(builder, extract_keys_from_jsonb(bytes)?);
115 Ok(())
116 });
117 }
118
119 let accessor = binary_accessor_or_err(array, "jsonb_object_keys")?;
120 let mut list_builder = ListBuilder::new(StringBuilder::new());
121 for i in 0..accessor.len() {
122 if accessor.is_null(i) {
123 list_builder.append(false);
124 } else {
125 append_keys_slot(
126 &mut list_builder,
127 extract_keys_from_jsonb(accessor.value(i))?,
128 );
129 }
130 }
131 Ok(Arc::new(list_builder.finish()))
132}
133
134pub fn make_jsonb_object_keys_udf() -> ScalarUDF {
136 ScalarUDF::new_from_impl(JsonbObjectKeys::new())
137}