// src/utils/data_converter.rs use common::proto::komp_ac::table_structure::TableStructureResponse; use prost_types::{value::Kind, NullValue, Value}; use std::collections::HashMap; pub fn convert_and_validate_data( data: &HashMap, schema: &TableStructureResponse, ) -> Result, String> { let type_map: HashMap<_, _> = schema .columns .iter() .map(|col| (col.name.as_str(), col.data_type.as_str())) .collect(); data.iter() .map(|(key, str_value)| { let expected_type = type_map.get(key.as_str()).unwrap_or(&"TEXT"); let kind = if str_value.is_empty() { // TODO: Use the correct enum variant Kind::NullValue(NullValue::NullValue.into()) } else { // Attempt to parse the string based on the expected type match *expected_type { "BOOL" => match str_value.to_lowercase().parse::() { Ok(v) => Kind::BoolValue(v), Err(_) => return Err(format!("Invalid boolean for '{}': must be 'true' or 'false'", key)), }, "INT8" | "INT4" | "INT2" | "SERIAL" | "BIGSERIAL" => { match str_value.parse::() { Ok(v) => Kind::NumberValue(v), Err(_) => return Err(format!("Invalid number for '{}': must be a whole number", key)), } } "NUMERIC" | "FLOAT4" | "FLOAT8" => match str_value.parse::() { Ok(v) => Kind::NumberValue(v), Err(_) => return Err(format!("Invalid decimal for '{}': must be a number", key)), }, "TIMESTAMPTZ" | "DATE" | "TIME" | "TEXT" | "VARCHAR" | "UUID" => { Kind::StringValue(str_value.clone()) } _ => Kind::StringValue(str_value.clone()), } }; Ok((key.clone(), Value { kind: Some(kind) })) }) .collect() }