monsta-server 0.0.1

Monsta server
Documentation
use monsta_proto::{
    monsta_server::{Monsta, MonstaServer},
    *,
};
use tonic::{Request as TonicRequest, Response as TonicResponse};

use crate::{database::Database, universe::Universe, Error, Result};

type TonicResult<T> = std::result::Result<T, tonic::Status>;

pub struct Server {
    uv: Universe,
}

#[tonic::async_trait]
impl Monsta for Server {
    async fn call(&self, request: TonicRequest<Request>) -> TonicResult<TonicResponse<Response>> {
        let req = request.into_inner();
        if let Some(req) = req.database {
            let res = self.handle_database(req).await?;
            Ok(TonicResponse::new(Response {
                database: Some(res),
                ..Default::default()
            }))
        } else if let Some(req) = req.collection {
            let res = self.handle_collection(req).await?;
            Ok(TonicResponse::new(Response {
                collection: Some(res),
                ..Default::default()
            }))
        } else if let Some(req) = req.transaction {
            let res = self.handle_transaction(req).await?;
            Ok(TonicResponse::new(Response {
                transaction: Some(res),
                ..Default::default()
            }))
        } else {
            Err(Error::InvalidArgument("missing request".to_owned()).into())
        }
    }
}

impl Server {
    pub fn new() -> MonstaServer<Server> {
        let server = Server {
            uv: Universe::new(),
        };
        MonstaServer::new(server)
    }
}

impl Server {
    async fn handle_database(&self, req: DatabaseRequest) -> Result<DatabaseResponse> {
        if let Some(req) = req.create_database {
            let res = self.handle_create_database(req).await?;
            Ok(DatabaseResponse {
                create_database: Some(res),
                ..Default::default()
            })
        } else if let Some(req) = req.describe_database {
            let res = self.handle_describe_database(req).await?;
            Ok(DatabaseResponse {
                describe_database: Some(res),
                ..Default::default()
            })
        } else {
            Err(Error::InvalidArgument(
                "unknown database request".to_owned(),
            ))
        }
    }

    async fn handle_create_database(
        &self,
        req: CreateDatabaseRequest,
    ) -> Result<CreateDatabaseResponse> {
        let spec = req
            .spec
            .ok_or_else(|| Error::InvalidArgument("missing database specification".to_owned()))?;
        let db = self.uv.create_database(spec).await?;
        let desc = db.desc().await;
        Ok(CreateDatabaseResponse { desc: Some(desc) })
    }

    async fn handle_describe_database(
        &self,
        req: DescribeDatabaseRequest,
    ) -> Result<DescribeDatabaseResponse> {
        if req.id > 0 {
            let db = self
                .uv
                .database(req.id)
                .await
                .ok_or_else(|| Error::NotFound(format!("database id {}", req.id)))?;
            let desc = db.desc().await;
            Ok(DescribeDatabaseResponse { desc: Some(desc) })
        } else if !req.name.is_empty() {
            let db = self
                .uv
                .lookup_database(&req.name)
                .await
                .ok_or_else(|| Error::NotFound(format!("database name {}", req.name)))?;
            let desc = db.desc().await;
            Ok(DescribeDatabaseResponse { desc: Some(desc) })
        } else {
            Err(Error::InvalidArgument(
                "missing database id or name".to_owned(),
            ))
        }
    }

    async fn handle_collection(&self, req: CollectionRequest) -> Result<CollectionResponse> {
        let db = self
            .uv
            .database(req.database_id)
            .await
            .ok_or_else(|| Error::NotFound(format!("database id {}", req.database_id)))?;
        if let Some(req) = req.create_collection {
            let res = self.handle_create_collection(db, req).await?;
            Ok(CollectionResponse {
                create_collection: Some(res),
                ..Default::default()
            })
        } else if let Some(req) = req.describe_collection {
            let res = self.handle_describe_collection(db, req).await?;
            Ok(CollectionResponse {
                describe_collection: Some(res),
                ..Default::default()
            })
        } else {
            Err(Error::InvalidArgument(
                "unknown collection request".to_owned(),
            ))
        }
    }

    async fn handle_create_collection(
        &self,
        db: Database,
        req: CreateCollectionRequest,
    ) -> Result<CreateCollectionResponse> {
        let spec = req
            .spec
            .ok_or_else(|| Error::InvalidArgument("missing collection specification".to_owned()))?;
        let co = db.create_collection(spec).await?;
        let desc = co.desc().await;
        Ok(CreateCollectionResponse { desc: Some(desc) })
    }

    async fn handle_describe_collection(
        &self,
        db: Database,
        req: DescribeCollectionRequest,
    ) -> Result<DescribeCollectionResponse> {
        if req.id > 0 {
            let co = db
                .collection(req.id)
                .await
                .ok_or_else(|| Error::NotFound(format!("collection id {}", req.id)))?;
            let desc = co.desc().await;
            Ok(DescribeCollectionResponse { desc: Some(desc) })
        } else if !req.name.is_empty() {
            let co = db
                .lookup_collection(&req.name)
                .await
                .ok_or_else(|| Error::NotFound(format!("collection name {}", req.name)))?;
            let desc = co.desc().await;
            Ok(DescribeCollectionResponse { desc: Some(desc) })
        } else {
            Err(Error::InvalidArgument(
                "missing collection id or name".to_owned(),
            ))
        }
    }

    async fn handle_transaction(&self, req: DatabaseTxnRequest) -> Result<DatabaseTxnResponse> {
        let db = self
            .uv
            .database(req.database_id)
            .await
            .ok_or_else(|| Error::NotFound(format!("database id {}", req.database_id)))?;
        db.execute_transaction(req).await
    }
}