use super::{deserialize::deserialize, schema::Table};
use crate::storage::Error;
use futures_util::TryStreamExt;
use pbbson::Model;
use sqlx::{Pool, Postgres};

pub(super) async fn perform(pool: &Pool<Postgres>, table: &Table, id: &str) -> Result<Model, Error> {
    // Prepare query
    let sql = {
        let table_name = &table.name;
        let maybe_id_field = table.fields_by_name.get("id");
        let param = match maybe_id_field {
            None => "$1".to_string(),
            Some(field) => format!("$1::{}", field.data_type),
        };
        format!("SELECT * FROM {table_name} WHERE id = {param}")
    };
    log::debug!(sql; "Finding one");

    // Perform query
    let mut rows = sqlx::query(&sql).bind(id).fetch(pool);

    // Find row
    let row = match rows.try_next().await.map_err(|e| Error::internal(e.to_string()))? {
        None => return Err(Error::not_found("No such record")),
        Some(row) => row,
    };

    // Translate into model
    let model = deserialize(row, table)?;
    Ok(model)
}
