use crate::regexes::COUCHDB_DB_RULE;
use awc::{Client, ClientRequest};
use serde::{de::DeserializeOwned, Serialize};
pub mod errors;
use crate::client::couchdb::responses::all_docs::AllDocs;
use errors::DBAllDocsError;
pub async fn get_all_docs<T: Serialize + DeserializeOwned>(
client: &Client,
db_name: &str,
host: &str,
skip: usize,
limit: usize,
) -> Result<AllDocs<T>, Box<dyn std::error::Error>> {
if !COUCHDB_DB_RULE.is_match(db_name) {
return Err(Box::new(DBAllDocsError::new(&format!(
"{} string doesn't respect the regex rule {}",
db_name,
COUCHDB_DB_RULE.as_str()
))));
}
let uri: String = format!("{}/{}/_all_docs", host, db_name,);
let queries: serde_json::Value = serde_json::from_str(
r#"{
"include_docs": "true"
}"#,
)?;
let request: ClientRequest = client.post(&uri).query(&queries)?;
let body: serde_json::Value = serde_json::from_str(&format!(
r#"{{
"skip": {},
"limit": {}
}}"#,
skip, limit
))
.unwrap();
match request.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();
Err(Box::new(DBAllDocsError::new(&format!(
"Error with the request to {}: error: \n{}",
&uri, error
))))
} else {
let bytes: Vec<u8> = response.body().await?.iter().cloned().collect();
let value: AllDocs<T> = serde_json::from_str({
let res = std::str::from_utf8(bytes.as_slice()).unwrap();
res
})
.unwrap();
Ok(value)
}
}
Err(error) => Err(Box::new(DBAllDocsError::new(&format!(
"Error with the request to {}: error: \n{}",
host, error
)))),
}
}
#[cfg(test)]
mod tests {
extern crate actix_web;
extern crate couchdb_orm_meta;
extern crate wiremock;
use super::*;
use std::error::Error;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use couchdb_orm_meta::schemas::tasks::schema_1661680133::{
Status as OldStatus, Task as OldTask,
};
use wiremock::matchers::{method, path_regex};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[actix_rt::test]
async fn get_all_docs_regex_error_test() {
let client: Client = Client::default();
let box_result: Box<dyn Error> =
get_all_docs::<serde_json::Value>(&client, "Test", "", 0, 1000)
.await
.unwrap_err();
let result: &DBAllDocsError = box_result.downcast_ref().unwrap();
assert_eq!(
format!("{}", result),
format!(
"DBAllDocsError: {} string doesn't respect the regex rule {}",
"Test",
COUCHDB_DB_RULE.as_str()
)
);
let box_result: Box<dyn Error> =
get_all_docs::<serde_json::Value>(&client, "testT", "", 0, 1000)
.await
.unwrap_err();
let result: &DBAllDocsError = box_result.downcast_ref().unwrap();
assert_eq!(
format!("{}", result),
format!(
"DBAllDocsError: {} string doesn't respect the regex rule {}",
"testT",
COUCHDB_DB_RULE.as_str()
)
)
}
#[actix_rt::test]
async fn get_all_docs_http_error_test() {
let mock_server = MockServer::start().await;
let data = r#"
{
"error": "test error"
}"#;
let response_template: ResponseTemplate =
ResponseTemplate::new(400).set_body_raw(data.as_bytes(), "application/json");
let mock = Mock::given(method("POST"))
.and(path_regex(r"^/test/\w+"))
.respond_with(response_template);
mock_server.register(mock).await;
let error: serde_json::Value = serde_json::from_str(data).unwrap();
let client: Client = Client::default();
let host: String = mock_server.uri();
let box_result: Box<dyn Error> =
get_all_docs::<serde_json::Value>(&client, "test", &host, 0, 1000)
.await
.unwrap_err();
let result: &DBAllDocsError = box_result.downcast_ref().unwrap();
assert_eq!(
format!("{}", result),
format!(
"DBAllDocsError: Error with the request to {}: error: \n{}",
format!("{}/{}/_all_docs", host, "test"),
error
)
)
}
#[actix_rt::test]
async fn get_all_docs_test() {
let mock_server = MockServer::start().await;
let this_file: PathBuf = PathBuf::from_str(file!()).unwrap();
let file = fs::read_to_string(&format!(
"{}/__fixtures__/_all_docs.200.response.json",
this_file.parent().unwrap().to_str().unwrap()
))
.unwrap();
let response_template: ResponseTemplate =
ResponseTemplate::new(200).set_body_raw(file.as_bytes(), "application/json");
let mock = Mock::given(method("POST"))
.and(path_regex(r"^/test/\w+"))
.respond_with(response_template);
mock_server.register(mock).await;
let client: Client = Client::default();
let host: String = mock_server.uri();
let response_result = get_all_docs::<OldTask>(&client, "test", &host, 0, 1000)
.await
.unwrap();
assert_eq!(response_result.total_rows, 5);
assert_eq!(response_result.offset, 0);
assert_eq!(response_result.rows.len(), 5);
assert_eq!(
response_result.rows[0].id,
"6b37e7affbb12c0ed12c961f2800074a"
);
assert_eq!(
response_result.rows[0].key,
"6b37e7affbb12c0ed12c961f2800074a"
);
assert_eq!(
response_result.rows[0].value.rev,
"1-4123ce7e20bb449419d1fcf62b18c5b3"
);
assert_eq!(response_result.rows[0].doc.name, "My task");
assert_eq!(response_result.rows[0].doc.status, OldStatus::Draft);
assert_eq!(response_result.rows[0].doc.owner, "Ciro DE CARO");
}
}