use std::collections::BTreeSet;
use selene_core::{DbString, Record, Value};
use smallvec::SmallVec;
use crate::{
SourceSpan, ValueExpr,
runtime::{Binding, BindingTableSchema, DataExceptionSubclass, EvalCtx, ExecutorError},
};
use super::{binary_ops::data_exception_with, evaluate};
pub(super) fn eval_record_literal(
fields: &[(DbString, ValueExpr)],
span: SourceSpan,
binding: &Binding,
schema: &BindingTableSchema,
ctx: &EvalCtx<'_, '_, '_, '_>,
) -> Result<Value, ExecutorError> {
let mut seen = BTreeSet::new();
let mut values = SmallVec::<[(DbString, Value); 4]>::new();
for (key, expr) in fields {
if !seen.insert(key.clone()) {
return data_exception_with(
DataExceptionSubclass::RecordDataFieldUnassignable,
format!("duplicate record field: {}", key.as_str()),
span,
);
}
values.push((key.clone(), evaluate(expr, binding, schema, ctx)?));
}
Ok(Value::Record(Box::new(Record::Open(values))))
}
pub(super) fn record_field(record: &Record, key: DbString) -> Value {
match record {
Record::Open(fields) => fields
.iter()
.find(|(name, _)| *name == key)
.map(|(_, value)| value.clone())
.unwrap_or(Value::Null),
_ => Value::Null,
}
}