pub mod export;
pub mod import;
use serde::{Serialize, de::DeserializeOwned};
use serde_json::Value;
pub trait NahpuExport {
fn to_json_array(&self) -> Result<Vec<Value>, String>;
}
pub trait NahpuImport: Sized {
fn from_json_array(data: &[Value]) -> Result<Vec<Self>, String>;
}
impl<T> NahpuExport for [T]
where
T: Serialize,
{
fn to_json_array(&self) -> Result<Vec<Value>, String> {
let json_value = serde_json::to_value(self).map_err(|e| e.to_string())?;
match json_value {
Value::Array(arr) => Ok(arr),
_ => Err("Expected array format".to_string()),
}
}
}
impl<T> NahpuExport for Vec<T>
where
T: Serialize,
{
fn to_json_array(&self) -> Result<Vec<Value>, String> {
self.as_slice().to_json_array()
}
}
impl<T> NahpuImport for T
where
T: DeserializeOwned,
{
fn from_json_array(data: &[Value]) -> Result<Vec<Self>, String> {
let json_value = Value::Array(data.to_vec());
serde_json::from_value(json_value).map_err(|e| e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::nahpu_sqlite::Site;
use std::fs;
use std::path::PathBuf;
fn get_dummy_sites() -> Vec<Site> {
vec![
Site {
id: 1,
site_id: Some("S1".to_string()),
project_uuid: Some("uuid-1".to_string()),
lead_staff_id: None,
site_type: Some("Forest".to_string()),
country: Some("USA".to_string()),
state_province: Some("California".to_string()),
county: None,
municipality: None,
media_id: None,
locality: Some("Yosemite".to_string()),
remark: None,
habitat_type: None,
habitat_condition: None,
habitat_description: None,
},
Site {
id: 2,
site_id: Some("S2".to_string()),
project_uuid: Some("uuid-2".to_string()),
lead_staff_id: None,
site_type: Some("Desert".to_string()),
country: Some("USA".to_string()),
state_province: Some("Nevada".to_string()),
county: None,
municipality: None,
media_id: None,
locality: Some("Mojave".to_string()),
remark: None,
habitat_type: None,
habitat_condition: None,
habitat_description: None,
},
]
}
#[test]
fn test_csv_export_import() {
let sites = get_dummy_sites();
let data = sites.to_json_array().unwrap();
let cols: Vec<String> = data[0].as_object().unwrap().keys().cloned().collect();
let path = PathBuf::from("test_export.csv");
let exporter = super::export::RecordExporter::new(&data, &cols);
exporter.export_csv(&path).unwrap();
let imported_data = super::import::import_csv(&path).unwrap();
let imported_sites: Vec<Site> = Site::from_json_array(&imported_data).unwrap();
assert_eq!(imported_sites.len(), 2);
assert_eq!(imported_sites[0].site_id.as_deref(), Some("S1"));
assert_eq!(imported_sites[1].site_id.as_deref(), Some("S2"));
let _ = fs::remove_file(path);
}
#[test]
fn test_excel_export_import() {
let sites = get_dummy_sites();
let data = sites.to_json_array().unwrap();
let cols: Vec<String> = data[0].as_object().unwrap().keys().cloned().collect();
let path = PathBuf::from("test_export.xlsx");
let exporter = super::export::RecordExporter::new(&data, &cols);
exporter.export_excel(&path).unwrap();
let imported_data = super::import::import_excel(&path, "Sheet1").unwrap();
let imported_sites: Vec<Site> = Site::from_json_array(&imported_data).unwrap();
assert_eq!(imported_sites.len(), 2);
assert_eq!(imported_sites[0].site_id.as_deref(), Some("S1"));
assert_eq!(imported_sites[1].site_id.as_deref(), Some("S2"));
let _ = fs::remove_file(path);
}
}