couchdb_orm/client/couchdb/actions/db/seed/
mod.rs

1// Copyright (C) 2020-2023  OpenToolAdd
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program.  If not, see <http://www.gnu.org/licenses/>.
15// contact: contact@tool-add.com
16
17use crate::regexes::COUCHDB_DB_RULE;
18use awc::Client;
19use serde::{de::DeserializeOwned, Serialize};
20use std::fmt::Debug;
21
22pub mod errors;
23
24use errors::DBSeedError;
25
26async fn post_request(
27    client: &awc::Client,
28    uri: &str,
29    body: &serde_json::Value,
30) -> Result<bool, Box<dyn std::error::Error>> {
31    match client.post(uri).send_json(body).await {
32        Ok(mut response) => {
33            // println!("{:?}", response);
34            if response.status().as_u16() >= 400 {
35                let bytes: Vec<u8> = response.body().await?.iter().cloned().collect();
36                let error: serde_json::Value =
37                    serde_json::from_str(std::str::from_utf8(bytes.as_slice()).unwrap()).unwrap();
38                return Err(Box::new(DBSeedError::new(&format!(
39                    "Error with the request to {}: error: \n{}",
40                    &uri, error
41                ))));
42            } else {
43                return Ok(true);
44            }
45        }
46        Err(error) => {
47            return Err(Box::new(DBSeedError::new(&format!(
48                "Error with the request to {}: error: \n{}",
49                uri, error
50            ))))
51        }
52    }
53}
54
55pub async fn seed_db<T: Clone + Serialize + DeserializeOwned + Debug>(
56    client: &Client,
57    db_name: &str,
58    data: Vec<T>,
59    host: &str,
60) -> Result<bool, Box<dyn std::error::Error>> {
61    if !COUCHDB_DB_RULE.is_match(db_name) {
62        return Err(Box::new(DBSeedError::new(&format!(
63            "{} string doesn't respect the regex rule {}",
64            db_name,
65            COUCHDB_DB_RULE.as_str()
66        ))));
67    }
68
69    let chunks: Vec<Vec<T>> = data.as_slice().chunks(100).map(|m| m.to_vec()).collect();
70
71    // println!("{:?}", chunks);
72    let uri: String = format!("{}/{}/_bulk_docs", host, db_name,);
73
74    for (index, chunk) in chunks.iter().enumerate() {
75        println!("chunk {} seeded", index);
76        // deleting _rev
77        // because if revision has been deleted it won't reappear
78        // without revision, it restores the original document
79        let json_body: serde_json::Value = serde_json::json!({
80            "docs": chunk.iter().map(|o| {
81               let mut value = serde_json::to_value(o).unwrap();
82               let value = value.as_object_mut().unwrap();
83               value.remove("_rev");
84               serde_json::to_value(value).unwrap()
85            }).collect::<serde_json::Value>(),
86        });
87        // println!("{}", json_body);
88        post_request(&client, &uri, &json_body).await?;
89    }
90    Ok(true)
91}
92
93#[cfg(test)]
94mod tests {}