rusdb-core 0.1.2

Database driver for `rusdb`, which uses gRPC to communicate.
Documentation
use bson::{doc, Document};
use serde::{de::DeserializeOwned, Serialize};
use std::marker::PhantomData;
use tonic::Status;
use uuid::Uuid;

use crate::RusDbConnection;

#[derive(Clone)]
pub struct RusDocument<T>
where
    T: Serialize + DeserializeOwned + Clone + std::fmt::Debug,
{
    _id: Uuid,
    collection: RusCollection<T>,
    pub document: T,
}

impl<T> std::fmt::Debug for RusDocument<T>
where
    T: Serialize + DeserializeOwned + Clone + std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", self.document)
    }
}

impl<T> RusDocument<T>
where
    T: Serialize + DeserializeOwned + Clone + std::fmt::Debug,
{
    pub fn create(_id: Uuid, collection: RusCollection<T>, document: T) -> Self {
        Self {
            _id,
            collection,
            document,
        }
    }
    pub fn from_slice(slice: &[u8], collection: RusCollection<T>) -> Result<Self, bson::de::Error> {
        let doc = bson::from_slice::<Document>(slice)?;
        Self::from_document(doc, collection)
    }
    pub fn from_document(
        doc: Document,
        collection: RusCollection<T>,
    ) -> Result<Self, bson::de::Error> {
        let _id: Uuid = bson::from_bson(doc.get("_id").expect("no id").clone())?;
        let document: T = bson::from_document(doc)?;
        Ok(Self {
            _id,
            document,
            collection,
        })
    }
    pub fn id(&self) -> Uuid {
        self._id.clone()
    }
    pub fn to_document(&self) -> Result<Document, bson::ser::Error> {
        let mut doc = bson::to_document(&self.document)?;
        doc.insert("_id", bson::to_bson(&self._id)?);
        Ok(doc)
    }
    fn id_doc(&self) -> Result<Document, bson::ser::Error> {
        Ok(doc!("_id": bson::to_bson(&self._id)?))
    }
    pub fn to_vec(&self) -> Result<Vec<u8>, bson::ser::Error> {
        bson::to_vec(&self.to_document()?)
    }
    pub async fn sync(&mut self) -> Result<(), Status> {
        let doc = self.to_document().unwrap();
        self.collection
            .update(self.id_doc().unwrap(), doc, Some(1))
            .await?;
        Ok(())
    }
    pub async fn delete(mut self) -> Result<(), Status> {
        if self
            .collection
            .remove(self.id_doc().unwrap(), Some(1))
            .await?
            == 1
        {
            drop(self);
            Ok(())
        } else {
            Err(Status::aborted("no document was removed."))
        }
    }
}

#[derive(Clone)]
pub struct RusCollection<T>
where
    T: Serialize + DeserializeOwned + Clone + std::fmt::Debug,
{
    collection: String,
    conn: RusDbConnection,
    document_type: PhantomData<T>,
}

impl<T> RusCollection<T>
where
    T: Serialize + DeserializeOwned + Clone + std::fmt::Debug,
{
    pub fn create(collection: String, conn: RusDbConnection) -> Self {
        Self {
            collection,
            conn,
            document_type: PhantomData::default(),
        }
    }
    fn create_document_vec(&self, data: &[u8]) -> Result<RusDocument<T>, bson::de::Error> {
        RusDocument::from_slice(data, self.clone())
    }
    pub async fn insert(&mut self, doc: T) -> Result<RusDocument<T>, Status> {
        let res = self
            .conn
            .insert(&self.collection, bson::to_document(&doc).unwrap(), true)
            .await?;
        let res = res.get_ref();
        if res.count == 0 {
            Err(Status::aborted("no documents inserted."))
        } else {
            let docs: Vec<RusDocument<T>> = res
                .inserts
                .iter()
                .map(|v| {
                    let data = v.document.as_ref().expect("document data missing");
                    self.create_document_vec(data).unwrap()
                })
                .collect();
            for d in docs {
                return Ok(d);
            }
            Err(Status::aborted("no document returned"))
        }
    }
    pub async fn insert_many(&mut self, docs: Vec<T>) -> Result<Vec<RusDocument<T>>, Status> {
        let res = self
            .conn
            .insert_many(
                &self.collection,
                docs.into_iter()
                    .map(|v| bson::to_document(&v).unwrap())
                    .collect(),
                true,
            )
            .await?;
        let res = res.get_ref();
        if res.count == 0 {
            Err(Status::aborted("no documents inserted."))
        } else {
            Ok(res
                .inserts
                .iter()
                .map(|v| {
                    let data = v.document.as_ref().expect("document data missing");
                    self.create_document_vec(data).unwrap()
                })
                .collect())
        }
    }
    pub async fn update(
        &mut self,
        filter: Document,
        updates: Document,
        limit: Option<u32>,
    ) -> Result<Vec<RusDocument<T>>, Status> {
        let res = self
            .conn
            .update(&self.collection, filter, updates, limit)
            .await?;
        let res = res.get_ref();
        Ok(res
            .updated
            .iter()
            .map(|v| self.create_document_vec(v).unwrap())
            .collect())
    }
    pub async fn remove(&mut self, filter: Document, limit: Option<u32>) -> Result<u32, Status> {
        let res = self.conn.remove(&self.collection, filter, limit).await?;
        let res = res.get_ref();
        Ok(res.count)
    }
    pub async fn find(
        &mut self,
        filter: Document,
        limit: Option<u32>,
    ) -> Result<Vec<RusDocument<T>>, Status> {
        let res = self
            .conn
            .find(&self.collection, Some(filter), limit)
            .await?;
        let res = res.get_ref();
        Ok(res
            .documents
            .iter()
            .map(|v| self.create_document_vec(v).unwrap())
            .collect())
    }
    pub async fn find_all(&mut self, limit: Option<u32>) -> Result<Vec<RusDocument<T>>, Status> {
        let res = self.conn.find(&self.collection, None, limit).await?;
        let res = res.get_ref();
        Ok(res
            .documents
            .iter()
            .map(|v| self.create_document_vec(v).unwrap())
            .collect())
    }
    pub async fn get(&mut self, id: Uuid) -> Result<Option<RusDocument<T>>, Status> {
        let id = id.to_string();
        let res = self.conn.get(&self.collection, &id).await?;
        let res = res.get_ref();
        if let Some(doc) = &res.document {
            Ok(Some(self.create_document_vec(doc).unwrap()))
        } else {
            Ok(None)
        }
    }
    pub async fn truncate(&mut self) -> Result<u32, Status> {
        let res = self.conn.remove(&self.collection, doc!(), None).await?;
        let res = res.get_ref();
        Ok(res.count)
    }
}