reifydb_routine/function/json/
object.rs1use reifydb_core::value::column::{Column, columns::Columns, data::ColumnData};
5use reifydb_type::{
6 util::bitvec::BitVec,
7 value::{Value, r#type::Type},
8};
9
10use crate::function::{Function, FunctionCapability, FunctionContext, FunctionInfo, error::FunctionError};
11
12pub struct JsonObject {
13 info: FunctionInfo,
14}
15
16impl Default for JsonObject {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22impl JsonObject {
23 pub fn new() -> Self {
24 Self {
25 info: FunctionInfo::new("json::object"),
26 }
27 }
28}
29
30impl Function for JsonObject {
31 fn info(&self) -> &FunctionInfo {
32 &self.info
33 }
34
35 fn capabilities(&self) -> &[FunctionCapability] {
36 &[FunctionCapability::Scalar]
37 }
38
39 fn return_type(&self, _input_types: &[Type]) -> Type {
40 Type::Any
41 }
42
43 fn execute(&self, ctx: &FunctionContext, args: &Columns) -> Result<Columns, FunctionError> {
44 let mut unwrapped: Vec<_> = Vec::with_capacity(args.len());
46 let mut combined_bv: Option<BitVec> = None;
47
48 for col in args.iter() {
49 let (data, bitvec) = col.data().unwrap_option();
50 if let Some(bv) = bitvec {
51 combined_bv = Some(match combined_bv {
52 Some(existing) => existing.and(bv),
53 None => bv.clone(),
54 });
55 }
56 unwrapped.push(data);
57 }
58
59 if !unwrapped.len().is_multiple_of(2) {
60 return Err(FunctionError::ExecutionFailed {
61 function: ctx.fragment.clone(),
62 reason: "json::object requires an even number of arguments (key-value pairs)"
63 .to_string(),
64 });
65 }
66
67 for i in (0..unwrapped.len()).step_by(2) {
69 let col_data = unwrapped[i];
70 match col_data {
71 ColumnData::Utf8 {
72 ..
73 } => {}
74 other => {
75 return Err(FunctionError::InvalidArgumentType {
76 function: ctx.fragment.clone(),
77 argument_index: i,
78 expected: vec![Type::Utf8],
79 actual: other.get_type(),
80 });
81 }
82 }
83 }
84
85 let row_count = if unwrapped.is_empty() {
86 1
87 } else {
88 unwrapped[0].len()
89 };
90 let num_pairs = unwrapped.len() / 2;
91 let mut results: Vec<Box<Value>> = Vec::with_capacity(row_count);
92
93 for row in 0..row_count {
94 let mut fields = Vec::with_capacity(num_pairs);
95 for pair in 0..num_pairs {
96 let key_data = unwrapped[pair * 2];
97 let val_data = unwrapped[pair * 2 + 1];
98
99 let key: String = key_data.get_as::<String>(row).unwrap_or_default();
100 let value = val_data.get_value(row);
101
102 fields.push((key, value));
103 }
104 results.push(Box::new(Value::Record(fields)));
105 }
106
107 let result_data = ColumnData::any(results);
108 let final_data = match combined_bv {
109 Some(bv) => ColumnData::Option {
110 inner: Box::new(result_data),
111 bitvec: bv,
112 },
113 None => result_data,
114 };
115
116 Ok(Columns::new(vec![Column::new(ctx.fragment.clone(), final_data)]))
117 }
118}