couchdb-orm 0.1.6

couchdb-orm Copyright (C) 2020-2023 OpenToolAdd This program comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under certain conditions; type `show-license' for details. A CLI ORM to manage some Databases operations like migration, schema creation, etc.... For the moment it only handle CouchDB.
Documentation
// Copyright (C) 2020-2023  OpenToolAdd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// contact: contact@tool-add.com

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) => {
            // println!("{:?}", 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();

    // println!("{:?}", chunks);
    let uri: String = format!("{}/{}/_bulk_docs", host, db_name,);

    for (index, chunk) in chunks.iter().enumerate() {
        println!("chunk {} seeded", index);
        // deleting _rev
        // because if revision has been deleted it won't reappear
        // without revision, it restores the original document
        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>(),
        });
        // println!("{}", json_body);
        post_request(&client, &uri, &json_body).await?;
    }
    Ok(true)
}

#[cfg(test)]
mod tests {}