couchdb_orm/client/couchdb/
mod.rs1use awc::Client;
18use awc::ClientBuilder;
19use dotenv;
20use std::env;
21use std::path::PathBuf;
22
23use cmd_lib::run_cmd;
24use dialoguer::Confirm;
25
26pub mod actions;
27pub mod models;
28pub mod responses;
29
30use responses::all_docs::AllDocs;
31
32use actions::db::{
33 all_docs::get_all_docs,
34 create::create_db,
35 db_status::get_db_status,
36 delete::{delete_all, delete_db},
37};
38
39use responses::db_status::DbStatus;
40
41pub struct CouchDBClient {
42 host: String,
43 pub client: Client,
44}
45
46impl CouchDBClient {
47 pub fn new(host: Option<String>) -> Self {
48 dotenv::dotenv().ok();
49 let client: Client = ClientBuilder::new()
50 .header("User-Agent", "CouchDB-ORM")
51 .header("Content-Type", "application/json")
52 .basic_auth(
53 env::var("COUCHDB_ORM_NAME").expect("COUCHDB_ORM_NAME variable needed"),
54 Some(
55 &env::var("COUCHDB_ORM_PASSWORD")
56 .expect("COUCHDB_ORM_PASSWORD variable needed"),
57 ),
58 )
59 .finish();
60 let host: String = host.unwrap_or(CouchDBClient::env_host());
61 CouchDBClient { client, host }
62 }
63
64 pub fn host(&self) -> &str {
65 &self.host
66 }
67
68 pub async fn get_db_status(
69 &self,
70 db_name: &str,
71 ) -> Result<DbStatus, Box<dyn std::error::Error>> {
72 get_db_status(&self.client, db_name, &self.host).await
73 }
74
75 pub async fn create_db(&self, db_name: &str) -> Result<bool, Box<dyn std::error::Error>> {
76 create_db(&self.client, db_name, &self.host).await
77 }
78
79 pub async fn delete_db(&self, db_name: &str) -> Result<bool, Box<dyn std::error::Error>> {
80 delete_db(&self.client, db_name, &self.host).await
81 }
82
83 pub async fn get_all_docs(
84 &self,
85 db_name: &str,
86 ) -> Result<AllDocs<serde_json::Value>, Box<dyn std::error::Error>> {
87 let mut skip: usize = 0;
88 let mut max_rows: usize = 1000;
89 let limit: usize = 100;
90 let mut response: AllDocs<serde_json::Value> = AllDocs {
91 rows: vec![],
92 total_rows: 0,
93 offset: 0,
94 };
95 let mut want_continue = true;
96 while skip < max_rows && want_continue {
98 response =
103 get_all_docs::<serde_json::Value>(&self.client, db_name, &self.host, skip, limit)
104 .await?;
105 max_rows = response.total_rows;
106 println!("{:#?}", response.rows);
107
108 if skip < max_rows {
109 if Confirm::new()
110 .with_prompt("Do you want to continue?")
111 .interact()?
112 {
113 skip += limit;
114 want_continue = true;
115 } else {
116 println!("aborting");
117 want_continue = false;
118 }
119 }
120 }
121 Ok(response)
122 }
123
124 pub async fn delete_all_docs(&self, db_name: &str) -> Result<bool, Box<dyn std::error::Error>> {
125 delete_all::<serde_json::Value>(&self.client, db_name, &self.host).await
126 }
127
128 pub async fn seed_db(
129 &self,
130 db_name: &str,
131 rootdir: &PathBuf,
132 ) -> Result<bool, Box<dyn std::error::Error>> {
133 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
134 match run_cmd! {
135 cd $path;
136 cargo run seed $db_name;
137 } {
138 Ok(()) => Ok(true),
139 Err(e) => Err(Box::new(e)),
140 }
141 }
142
143 pub async fn migrate_db(
144 &self,
145 db_name: &str,
146 rootdir: &PathBuf,
147 ) -> Result<bool, Box<dyn std::error::Error>> {
148 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
149 match run_cmd! {
150 cd $path;
151 cargo run migrate $db_name;
152 } {
153 Ok(()) => Ok(true),
154 Err(e) => Err(Box::new(e)),
155 }
156 }
157
158 pub async fn secure_db(
159 &self,
160 db_name: &str,
161 file: Option<String>,
162 rootdir: &PathBuf,
163 ) -> Result<bool, Box<dyn std::error::Error>> {
164 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
165 match file {
166 Some(f) => {
167 match run_cmd! {
168 cd $path;
169 cargo run secure $db_name $f;
170 } {
171 Ok(()) => Ok(true),
172 Err(e) => Err(Box::new(e)),
173 }
174 }
175 None => {
176 match run_cmd! {
177 cd $path;
178 cargo run secure $db_name;
179 } {
180 Ok(()) => Ok(true),
181 Err(e) => Err(Box::new(e)),
182 }
183 }
184 }
185 }
186
187 pub async fn backup_db(
188 &self,
189 db_name: &str,
190 rootdir: &PathBuf,
191 ) -> Result<bool, Box<dyn std::error::Error>> {
192 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
193 match run_cmd! {
194 cd $path;
195 cargo run backup $db_name;
196 } {
197 Ok(()) => Ok(true),
198 Err(e) => Err(Box::new(e)),
199 }
200 }
201
202 pub async fn restore_db(
203 &self,
204 db_name: &str,
205 rootdir: &PathBuf,
206 ) -> Result<bool, Box<dyn std::error::Error>> {
207 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
208 match run_cmd! {
209 cd $path;
210 cargo run restore $db_name;
211 } {
212 Ok(()) => Ok(true),
213 Err(e) => Err(Box::new(e)),
214 }
215 }
216
217 pub async fn create_design_doc(
218 &self,
219 db_name: &str,
220 rootdir: &PathBuf,
221 ) -> Result<bool, Box<dyn std::error::Error>> {
222 let path: String = format!("{}/_meta", rootdir.to_str().unwrap());
223 match run_cmd! {
224 cd $path;
225 cargo run design_doc_create $db_name;
226 } {
227 Ok(()) => Ok(true),
228 Err(e) => Err(Box::new(e)),
229 }
230 }
231
232 fn env_host() -> String {
233 format!(
234 "{}://{}:{}",
235 env::var("COUCHDB_PROTOCOL").expect("COUCHDB_PROTOCOL variable needed"),
236 env::var("COUCHDB_HOST").expect("COUCHDB_HOST variable needed"),
237 env::var("COUCHDB_PORT").expect("COUCHDB_PORT variable needed")
238 )
239 }
240}