use crate::error::TushareError;
use crate::types::TushareResponse;
use crate::traits::FromTushareData;
use serde_json::Value;
pub fn response_to_vec<T: FromTushareData>(response: TushareResponse) -> Result<Vec<T>, TushareError> {
let mut results = Vec::new();
if response.data.is_none() {
return Ok(results);
}
let Some(data) = response.data else {
return Ok(results);
};
for item in data.items {
let converted = T::from_row(&data.fields, &item)?;
results.push(converted);
}
Ok(results)
}
pub fn get_field_value<'a>(fields: &[String], values: &'a [Value], field_name: &str) -> Result<&'a Value, TushareError> {
let index = fields.iter()
.position(|f| f == field_name)
.ok_or_else(|| TushareError::ParseError(format!("Missing field: {}", field_name)))?;
values.get(index)
.ok_or_else(|| TushareError::ParseError(format!("Value not found for field: {}", field_name)))
}
pub fn get_string_field(fields: &[String], values: &[Value], field_name: &str) -> Result<String, TushareError> {
let value = get_field_value(fields, values, field_name)?;
value.as_str()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a string", field_name)))
.map(|s| s.to_string())
}
pub fn get_optional_string_field(fields: &[String], values: &[Value], field_name: &str) -> Result<Option<String>, TushareError> {
match get_field_value(fields, values, field_name) {
Ok(value) => {
if value.is_null() {
Ok(None)
} else {
value.as_str()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a string", field_name)))
.map(|s| Some(s.to_string()))
}
}
Err(_) => Ok(None), }
}
pub fn get_float_field(fields: &[String], values: &[Value], field_name: &str) -> Result<f64, TushareError> {
let value = get_field_value(fields, values, field_name)?;
value.as_f64()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a number", field_name)))
}
pub fn get_optional_float_field(fields: &[String], values: &[Value], field_name: &str) -> Result<Option<f64>, TushareError> {
match get_field_value(fields, values, field_name) {
Ok(value) => {
if value.is_null() {
Ok(None)
} else {
value.as_f64()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a number", field_name)))
.map(Some)
}
}
Err(_) => Ok(None), }
}
pub fn get_int_field(fields: &[String], values: &[Value], field_name: &str) -> Result<i64, TushareError> {
let value = get_field_value(fields, values, field_name)?;
value.as_i64()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not an integer", field_name)))
}
pub fn get_optional_int_field(fields: &[String], values: &[Value], field_name: &str) -> Result<Option<i64>, TushareError> {
match get_field_value(fields, values, field_name) {
Ok(value) => {
if value.is_null() {
Ok(None)
} else {
value.as_i64()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not an integer", field_name)))
.map(Some)
}
}
Err(_) => Ok(None), }
}
pub fn get_bool_field(fields: &[String], values: &[Value], field_name: &str) -> Result<bool, TushareError> {
let value = get_field_value(fields, values, field_name)?;
value.as_bool()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a boolean", field_name)))
}
pub fn get_optional_bool_field(fields: &[String], values: &[Value], field_name: &str) -> Result<Option<bool>, TushareError> {
match get_field_value(fields, values, field_name) {
Ok(value) => {
if value.is_null() {
Ok(None)
} else {
value.as_bool()
.ok_or_else(|| TushareError::ParseError(format!("Field {} is not a boolean", field_name)))
.map(Some)
}
}
Err(_) => Ok(None), }
}