use serde::de::DeserializeOwned;
use crate::error::DbCoreError;
pub fn parse_json_array_of_arrays(json: &str) -> Result<Vec<Vec<serde_json::Value>>, DbCoreError> {
let parsed: serde_json::Value =
serde_json::from_str(json).map_err(|e| DbCoreError::RowMapping(e.to_string()))?;
let outer = parsed
.as_array()
.ok_or_else(|| DbCoreError::RowMapping("expected JSON array".to_owned()))?;
let mut rows = Vec::with_capacity(outer.len());
for item in outer {
let inner = item
.as_array()
.ok_or_else(|| DbCoreError::RowMapping("expected inner array in JSON row".to_owned()))?
.clone();
rows.push(inner);
}
Ok(rows)
}
pub fn parse_json_single_array(json: &str) -> Result<Vec<serde_json::Value>, DbCoreError> {
let parsed: serde_json::Value =
serde_json::from_str(json).map_err(|e| DbCoreError::RowMapping(e.to_string()))?;
if parsed.is_null() {
return Ok(Vec::new());
}
parsed
.as_array()
.cloned()
.ok_or_else(|| DbCoreError::RowMapping("expected JSON array or null".to_owned()))
}
pub fn from_json_object_slice<T: DeserializeOwned>(
values: &[serde_json::Value],
keys: &[&str],
) -> Result<T, DbCoreError> {
if values.len() != keys.len() {
return Err(DbCoreError::RowMapping(format!(
"column count mismatch: got {} values for {} keys",
values.len(),
keys.len()
)));
}
let mut map = serde_json::Map::new();
for (k, v) in keys.iter().zip(values.iter()) {
map.insert((*k).to_owned(), v.clone());
}
serde_json::from_value(serde_json::Value::Object(map))
.map_err(|e| DbCoreError::RowMapping(e.to_string()))
}
pub struct RelationDeserializer<'a> {
values: &'a [serde_json::Value],
}
impl<'a> RelationDeserializer<'a> {
pub fn new(values: &'a [serde_json::Value]) -> Self {
Self { values }
}
pub fn get<T: DeserializeOwned>(&self, index: usize) -> Result<T, DbCoreError> {
let val = self.values.get(index).ok_or_else(|| {
DbCoreError::RowMapping(format!(
"relation column index {index} out of bounds (len {})",
self.values.len()
))
})?;
serde_json::from_value(val.clone())
.map_err(|e| DbCoreError::RowMapping(format!("column {index}: {e}")))
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
pub trait FromRelationalRow: Sized {
const SCALAR_COLUMNS: &'static [&'static str];
fn from_relational_values(values: &[serde_json::Value]) -> Result<Self, DbCoreError>;
}