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());
41 let mut combined_bv: Option<BitVec> = None;
42
43 for col in args.iter() {
44 let (data, bitvec) = col.data().unwrap_option();
45 if let Some(bv) = bitvec {
46 combined_bv = Some(match combined_bv {
47 Some(existing) => existing.and(bv),
48 None => bv.clone(),
49 });
50 }
51 unwrapped.push(data);
52 }
53
54 if !unwrapped.len().is_multiple_of(2) {
55 return Err(RoutineError::FunctionExecutionFailed {
56 function: ctx.fragment.clone(),
57 reason: "json::object requires an even number of arguments (key-value pairs)"
58 .to_string(),
59 });
60 }
61
62 for i in (0..unwrapped.len()).step_by(2) {
63 let col_data = unwrapped[i];
64 match col_data {
65 ColumnBuffer::Utf8 {
66 ..
67 } => {}
68 other => {
69 return Err(RoutineError::FunctionInvalidArgumentType {
70 function: ctx.fragment.clone(),
71 argument_index: i,
72 expected: vec![Type::Utf8],
73 actual: other.get_type(),
74 });
75 }
76 }
77 }
78
79 let row_count = if unwrapped.is_empty() {
80 1
81 } else {
82 unwrapped[0].len()
83 };
84 let num_pairs = unwrapped.len() / 2;
85 let mut results: Vec<Box<Value>> = Vec::with_capacity(row_count);
86
87 for row in 0..row_count {
88 let mut fields = Vec::with_capacity(num_pairs);
89 for pair in 0..num_pairs {
90 let key_data = unwrapped[pair * 2];
91 let val_data = unwrapped[pair * 2 + 1];
92
93 let key: String = key_data.get_as::<String>(row).unwrap_or_default();
94 let value = val_data.get_value(row);
95
96 fields.push((key, value));
97 }
98 results.push(Box::new(Value::Record(fields)));
99 }
100
101 let result_data = ColumnBuffer::any(results);
102 let final_data = match combined_bv {
103 Some(bv) => ColumnBuffer::Option {
104 inner: Box::new(result_data),
105 bitvec: bv,
106 },
107 None => result_data,
108 };
109
110 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), final_data)]))
111 }
112}
113
114impl Function for JsonObject {
115 fn kinds(&self) -> &[FunctionKind] {
116 &[FunctionKind::Scalar]
117 }
118}