use nodedb_types::Value;
use crate::expr::{EvalError, SqlExpr};
use crate::msgpack_scan::field::extract_field;
use crate::msgpack_scan::reader::{read_f64, read_numeric, read_str, read_value};
use crate::value_ops;
#[inline]
fn eval_expr(doc: &[u8], expr: &SqlExpr) -> Result<Option<Value>, EvalError> {
let Ok(doc_val) = nodedb_types::json_msgpack::value_from_msgpack(doc) else {
return Ok(None);
};
Ok(Some(expr.eval(&doc_val)?))
}
#[inline]
pub fn extract_f64(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<f64>, EvalError> {
if let Some(expr) = expr {
return Ok(eval_expr(doc, expr)?.and_then(|v| value_ops::value_to_f64(&v, false)));
}
let Some((start, _end)) = extract_field(doc, 0, field) else {
return Ok(None);
};
Ok(read_f64(doc, start))
}
#[inline]
pub fn extract_sum_value(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<Value>, EvalError> {
if let Some(expr) = expr {
return Ok(eval_expr(doc, expr)?.and_then(|v| crate::numeric_sum::sum_input(&v)));
}
let Some((start, _end)) = extract_field(doc, 0, field) else {
return Ok(None);
};
Ok(match read_numeric(doc, start) {
Some(n) => Some(crate::numeric_sum::numeric_to_value(n)),
None => read_str(doc, start).and_then(crate::numeric_sum::numeric_text),
})
}
pub fn extract_str(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<String>, EvalError> {
if let Some(expr) = expr {
return Ok(eval_expr(doc, expr)?.map(|v| value_ops::value_to_display_string(&v)));
}
let Some((start, _end)) = extract_field(doc, 0, field) else {
return Ok(None);
};
Ok(read_str(doc, start).map(|s| s.to_string()))
}
pub fn extract_value(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<Value>, EvalError> {
if let Some(expr) = expr {
return eval_expr(doc, expr);
}
let Some((start, end)) = extract_field(doc, 0, field) else {
return Ok(None);
};
if let Some(v) = read_value(doc, start) {
return Ok(Some(v));
}
let field_bytes = &doc[start..end];
Ok(nodedb_types::json_msgpack::value_from_msgpack(field_bytes).ok())
}
pub fn extract_bytes(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<Vec<u8>>, EvalError> {
if let Some(expr) = expr {
let Some(val) = eval_expr(doc, expr)? else {
return Ok(None);
};
return Ok(nodedb_types::json_msgpack::value_to_msgpack(&val).ok());
}
let Some((start, end)) = extract_field(doc, 0, field) else {
return Ok(None);
};
Ok(Some(doc[start..end].to_vec()))
}
#[inline]
pub fn extract_non_null(
doc: &[u8],
field: &str,
expr: Option<&SqlExpr>,
) -> Result<Option<()>, EvalError> {
let Some(v) = extract_value(doc, field, expr)? else {
return Ok(None);
};
Ok(if v.is_null() { None } else { Some(()) })
}