use std::collections::HashMap;
use nodedb_physical::physical_plan::UpdateValue;
use nodedb_types::value::Value;
use crate::error::LiteError;
use crate::query::assignments::resolve_updates_with_excluded;
pub(crate) fn apply_patch(
row: &mut HashMap<String, Value>,
patch: &[(String, UpdateValue)],
excluded: &HashMap<String, Value>,
) -> Result<(), LiteError> {
if patch.is_empty() {
return Ok(());
}
let resolved = resolve_updates_with_excluded(
patch,
&Value::Object(row.clone()),
&Value::Object(excluded.clone()),
)?;
row.extend(resolved);
Ok(())
}
#[cfg(test)]
mod tests {
use nodedb_query::expr::SqlExpr as QExpr;
use super::*;
#[test]
fn literal_assignment_overwrites_field() {
let mut row = HashMap::from([("n".to_string(), Value::Integer(1))]);
let excluded = HashMap::from([("n".to_string(), Value::Integer(9))]);
let bytes = zerompk::to_msgpack_vec(&Value::Integer(5)).expect("encode literal");
let patch = vec![("n".to_string(), UpdateValue::Literal(bytes))];
apply_patch(&mut row, &patch, &excluded).expect("apply literal");
assert_eq!(row.get("n"), Some(&Value::Integer(5)));
}
#[test]
fn expr_assignment_evaluates_against_stored_and_excluded() {
let mut row = HashMap::from([("n".to_string(), Value::Integer(1))]);
let excluded = HashMap::from([("n".to_string(), Value::Integer(9))]);
let expr = QExpr::BinaryOp {
left: Box::new(QExpr::Column("n".to_string())),
op: nodedb_query::expr::types::BinaryOp::Add,
right: Box::new(QExpr::Literal(Value::Integer(1))),
};
let patch = vec![("n".to_string(), UpdateValue::Expr(expr))];
apply_patch(&mut row, &patch, &excluded).expect("apply expr");
assert_eq!(row.get("n"), Some(&Value::Integer(2)));
}
#[test]
fn excluded_column_resolves_to_incoming_row() {
let mut row = HashMap::from([("n".to_string(), Value::Integer(1))]);
let excluded = HashMap::from([("n".to_string(), Value::Integer(9))]);
let expr = QExpr::ExcludedColumn("n".to_string());
let patch = vec![("n".to_string(), UpdateValue::Expr(expr))];
apply_patch(&mut row, &patch, &excluded).expect("apply excluded ref");
assert_eq!(row.get("n"), Some(&Value::Integer(9)));
}
}