use crate::regexes::COUCHDB_DB_RULE;
use awc::Client;
use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
pub mod errors;
use errors::DBSeedError;
async fn post_request(
client: &awc::Client,
uri: &str,
body: &serde_json::Value,
) -> Result<bool, Box<dyn std::error::Error>> {
match client.post(uri).send_json(body).await {
Ok(mut response) => {
if response.status().as_u16() >= 400 {
let bytes: Vec<u8> = response.body().await?.iter().cloned().collect();
let error: serde_json::Value =
serde_json::from_str(std::str::from_utf8(bytes.as_slice()).unwrap()).unwrap();
return Err(Box::new(DBSeedError::new(&format!(
"Error with the request to {}: error: \n{}",
&uri, error
))));
} else {
return Ok(true);
}
}
Err(error) => {
return Err(Box::new(DBSeedError::new(&format!(
"Error with the request to {}: error: \n{}",
uri, error
))))
}
}
}
pub async fn seed_db<T: Clone + Serialize + DeserializeOwned + Debug>(
client: &Client,
db_name: &str,
data: Vec<T>,
host: &str,
) -> Result<bool, Box<dyn std::error::Error>> {
if !COUCHDB_DB_RULE.is_match(db_name) {
return Err(Box::new(DBSeedError::new(&format!(
"{} string doesn't respect the regex rule {}",
db_name,
COUCHDB_DB_RULE.as_str()
))));
}
let chunks: Vec<Vec<T>> = data.as_slice().chunks(100).map(|m| m.to_vec()).collect();
let uri: String = format!("{}/{}/_bulk_docs", host, db_name,);
for (index, chunk) in chunks.iter().enumerate() {
println!("chunk {} seeded", index);
let json_body: serde_json::Value = serde_json::json!({
"docs": chunk.iter().map(|o| {
let mut value = serde_json::to_value(o).unwrap();
let value = value.as_object_mut().unwrap();
value.remove("_rev");
serde_json::to_value(value).unwrap()
}).collect::<serde_json::Value>(),
});
post_request(&client, &uri, &json_body).await?;
}
Ok(true)
}
#[cfg(test)]
mod tests {}