tinychain 0.1.7

A next-gen database + application server
Documentation
use log::debug;
use safecast::TryCastFrom;

use tc_error::*;
use tc_transact::Transaction;
use tcgeneric::{PathSegment, TCPath};

use crate::chain::{Chain, ChainInstance};
use crate::scalar::Scalar;

use super::{GetHandler, Handler, PostHandler, Public, PutHandler, Route};

impl Route for Chain {
    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a> + 'a>> {
        debug!("Chain::route {}", TCPath::from(path));

        if path.is_empty() {
            Some(Box::new(SubjectHandler::new(self, path)))
        } else if path[0].as_str() == "chain" {
            Some(Box::new(ChainHandler::from(self)))
        } else {
            None
        }
    }
}

struct SubjectHandler<'a> {
    chain: &'a Chain,
    path: &'a [PathSegment],
}

impl<'a> SubjectHandler<'a> {
    fn new(chain: &'a Chain, path: &'a [PathSegment]) -> Self {
        debug!("SubjectHandler {}", TCPath::from(path));
        Self { chain, path }
    }
}

impl<'a> Handler<'a> for SubjectHandler<'a> {
    fn get(self: Box<Self>) -> Option<GetHandler<'a>> {
        Some(Box::new(|txn, key| {
            Box::pin(async move {
                debug!("Subject::get {} {}", TCPath::from(self.path), key);
                let subject = self.chain.subject().at(txn.id()).await?;
                debug!("Subject is {}", subject);
                subject.get(&txn, self.path, key).await
            })
        }))
    }

    fn put(self: Box<Self>) -> Option<PutHandler<'a>> {
        Some(Box::new(|txn, key, value| {
            Box::pin(async move {
                let subject = self.chain.subject();

                let scalar_value = Scalar::try_cast_from(value.clone(), |v| {
                    TCError::not_implemented(format!("update Chain with value {}", v))
                })?;

                debug!("Subject::put {} <- {}", key, value);
                self.chain
                    .append(
                        *txn.id(),
                        self.path.to_vec().into(),
                        key.clone(),
                        scalar_value,
                    )
                    .await?;

                if self.path.is_empty() {
                    subject
                        .put(*txn.id(), self.path.to_vec().into(), key, value)
                        .await
                } else {
                    let subject = self.chain.subject().at(txn.id()).await?;
                    subject.put(&txn, self.path, key, value).await
                }
            })
        }))
    }

    fn post(self: Box<Self>) -> Option<PostHandler<'a>> {
        Some(Box::new(|txn, params| {
            Box::pin(async move {
                debug!("Subject::post {}", params);
                let subject = self.chain.subject().at(txn.id()).await?;
                subject.post(&txn, self.path, params).await
            })
        }))
    }
}

struct ChainHandler<'a> {
    chain: &'a Chain,
}

impl<'a> From<&'a Chain> for ChainHandler<'a> {
    fn from(chain: &'a Chain) -> Self {
        Self { chain }
    }
}

impl<'a> Handler<'a> for ChainHandler<'a> {
    fn get(self: Box<Self>) -> Option<GetHandler<'a>> {
        Some(Box::new(|_txn, key| {
            Box::pin(async move {
                if key.is_none() {
                    Ok(self.chain.clone().into())
                } else {
                    Err(TCError::bad_request("invalid key for Chain", key))
                }
            })
        }))
    }
}