couchdb_orm/client/couchdb/actions/db/backup/
mod.rs1use crate::client::couchdb::actions::db::all_docs::get_all_docs;
18use crate::regexes::COUCHDB_DB_RULE;
19use awc::Client;
20use chrono::Utc;
21use serde::{de::DeserializeOwned, Serialize};
22use std::fmt::Debug;
23use std::path::PathBuf;
24
25pub mod errors;
26
27use errors::DBBackupError;
28
29pub async fn backup_db<T: Clone + Serialize + DeserializeOwned + Debug>(
30 client: &Client,
31 db_name: &str,
32 seed_name: &str,
33 host: &str,
34) -> Result<bool, Box<dyn std::error::Error>> {
35 if !COUCHDB_DB_RULE.is_match(db_name) {
36 return Err(Box::new(DBBackupError::new(&format!(
37 "{} string doesn't respect the regex rule {}",
38 db_name,
39 COUCHDB_DB_RULE.as_str()
40 ))));
41 }
42
43 let mut skip: usize = 0;
44 let mut max_rows: usize = 1000;
45 let limit: usize = 100;
46 let exe_path: PathBuf = std::env::current_exe().unwrap();
49 let backup_path: PathBuf = exe_path
50 .parent()
51 .unwrap()
52 .to_path_buf()
53 .parent()
54 .unwrap()
55 .to_path_buf()
56 .parent()
57 .unwrap()
58 .to_path_buf()
59 .join("backups");
60
61 let timestamp: i64 = Utc::now().timestamp();
62 let folder_path = backup_path.join(format!("{}/{}/{}", db_name, seed_name, timestamp));
63
64 std::fs::create_dir_all(&backup_path)?;
66 std::fs::create_dir_all(&folder_path)?;
68
69 while skip < max_rows {
70 let index = skip / 100;
71 println!("chunk {} backuped", index);
72 let all_docs = get_all_docs::<T>(client, db_name, host, skip, limit).await?;
76 max_rows = all_docs.total_rows;
77 let all_docs: Vec<T> = all_docs.rows.iter().map(|o| o.doc.clone()).collect();
78
79 let file_path = folder_path.join(format!("{}.json", index));
80 std::fs::write(
81 &file_path,
82 format!("{}", serde_json::to_string_pretty(&all_docs).unwrap()),
83 )?;
84 skip += limit;
87 }
88 println!("backup saved in: {}", folder_path.display());
89
90 Ok(true)
91}
92
93#[cfg(test)]
94mod tests {}