basiliq 0.1.2

REST API server exposing a Postgres database using JSON:API
use super::*;
use ciboulette::*;
use ciboulette2pg::*;
use std::convert::TryFrom;

pub mod create;
pub mod delete;
pub mod read;
pub mod update;

async fn finish_tx<'a, 'response>(
    state: &Arc<BasiliqServerState>,
    response: &CibouletteResponse<'response, &serde_json::value::RawValue>,
    tx: sqlx::Transaction<'a, sqlx::Postgres>,
) -> Result<(), BasiliqServerError> {
    match state.config().demo_mode() {
        false => match response.status().is_success() {
            true => Ok(tx.commit().await?),
            false => Ok(tx.rollback().await?),
        },
        true => Ok(tx.rollback().await?),
    }
}

async fn exec_query<'request>(
    state: &Arc<BasiliqServerState>,
    inbound_request: &'request dyn CibouletteRequestCommons<'request>,
    query: String,
    params: Ciboulette2PgArguments<'request>,
) -> Result<Response<Body>, BasiliqServerError> {
    let mut transaction = state.db_pool().begin().await?;

    let raw_rows: Vec<sqlx::postgres::PgRow> = sqlx::query_with(&query, params)
        .fetch_all(&mut *transaction)
        .await
        .unwrap();
    let rows = Ciboulette2PgRow::from_raw(&raw_rows)?;
    let rows_nb = rows.len();
    let response_elements = Ciboulette2PgRow::build_response_elements(
        rows,
        state.store().ciboulette(),
        inbound_request.anchor_type(),
        Some(rows_nb),
    )?;
    let accumulator = CibouletteResponseDataBuilder::new(inbound_request, response_elements);
    let response: CibouletteResponse<&serde_json::value::RawValue> = accumulator.build()?;
    let res = Body::from(bytes::Bytes::from(serde_json::to_string(&response)?));
    finish_tx(&state, &response, transaction).await?;
    Ok(Response::builder()
        .header(
            hyper::header::CONTENT_TYPE,
            super::server::JSON_API_CONTENT_TYPE,
        )
        .status(super::status_code::convert_status_code(response.status()))
        .body(res)?)
}

pub async fn handle_request(
    state: &Arc<BasiliqServerState>,
    req: CibouletteRequest<'_>,
) -> Result<Response<Body>, BasiliqServerError> {
    match *req.intention() {
        CibouletteIntention::Create => {
            let create_req = ciboulette::CibouletteCreateRequest::try_from(req)?;
            let (query, params) = create::handle_request(&state, &create_req)?;
            exec_query(state, &create_req, query, params).await
        }
        CibouletteIntention::Read => {
            let read_req = ciboulette::CibouletteReadRequest::try_from(req)?;
            let (query, params) = read::handle_request(&state, &read_req)?;
            exec_query(state, &read_req, query, params).await
        }
        CibouletteIntention::Update => {
            println!("HERE");
            let update_req = ciboulette::CibouletteUpdateRequest::try_from(req)?;
            let (query, params) = update::handle_request(&state, &update_req)?;
            exec_query(state, &update_req, query, params).await
        }
        CibouletteIntention::Delete => {
            let delete_req = ciboulette::CibouletteDeleteRequest::try_from(req)?;
            let (query, params) = delete::handle_request(&state, &delete_req)?;
            exec_query(state, &delete_req, query, params).await
        }
    }
}