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
}
}