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