use super::{
    create::{bind, find_field},
    schema::Table,
};
use crate::storage::Error;
use pbbson::Model;
use sqlx::{Execute, Pool, Postgres, QueryBuilder};

pub(super) async fn perform(pool: &Pool<Postgres>, table: &Table, model: Model) -> Result<(), Error> {
    // UPDATE <table>
    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new("UPDATE ");
    qb.push(&table.name);

    // SET field = ?, ...
    qb.push(" SET ");
    let mut field_num = 0;
    for (k, v) in model.iter() {
        let field = match find_field(table, k) {
            Some(field) => field,
            None => {
                log::error!(field = k; "No db column found for field");
                continue;
            }
        };

        field_num += 1;
        if field_num > 1 {
            qb.push(", ");
        }

        qb.push(&field.column_name);
        qb.push("=");
        bind(&field, v, &mut qb)?;
    }
    qb.push(" WHERE id = ");
    qb.push_bind(model.id()?);

    // Perform query
    let query = qb.build();
    let sql = query.sql();
    log::debug!(sql; "Updating");
    let res = query.execute(pool).await.map_err(|e| Error::internal(e.to_string()))?;
    if res.rows_affected() == 0 {
        return Err(Error::NotFound("No such record".to_string()));
    }
    Ok(())
}
