nodedb_query/msgpack_scan/
aggregate_helpers.rs1use nodedb_types::Value;
12
13use crate::expr::{EvalError, SqlExpr};
14use crate::msgpack_scan::field::extract_field;
15use crate::msgpack_scan::reader::{read_f64, read_numeric, read_str, read_value};
16use crate::value_ops;
17
18#[inline]
32fn eval_expr(doc: &[u8], expr: &SqlExpr) -> Result<Option<Value>, EvalError> {
33 let Ok(doc_val) = nodedb_types::json_msgpack::value_from_msgpack(doc) else {
34 return Ok(None);
35 };
36 Ok(Some(expr.eval(&doc_val)?))
37}
38
39#[inline]
45pub fn extract_f64(
46 doc: &[u8],
47 field: &str,
48 expr: Option<&SqlExpr>,
49) -> Result<Option<f64>, EvalError> {
50 if let Some(expr) = expr {
51 return Ok(eval_expr(doc, expr)?.and_then(|v| value_ops::value_to_f64(&v, false)));
52 }
53 let Some((start, _end)) = extract_field(doc, 0, field) else {
54 return Ok(None);
55 };
56 Ok(read_f64(doc, start))
57}
58
59#[inline]
68pub fn extract_sum_value(
69 doc: &[u8],
70 field: &str,
71 expr: Option<&SqlExpr>,
72) -> Result<Option<Value>, EvalError> {
73 if let Some(expr) = expr {
74 return Ok(eval_expr(doc, expr)?.and_then(|v| crate::numeric_sum::sum_input(&v)));
75 }
76 let Some((start, _end)) = extract_field(doc, 0, field) else {
77 return Ok(None);
78 };
79 Ok(match read_numeric(doc, start) {
80 Some(n) => Some(crate::numeric_sum::numeric_to_value(n)),
81 None => read_str(doc, start).and_then(crate::numeric_sum::numeric_text),
82 })
83}
84
85pub fn extract_str(
88 doc: &[u8],
89 field: &str,
90 expr: Option<&SqlExpr>,
91) -> Result<Option<String>, EvalError> {
92 if let Some(expr) = expr {
93 return Ok(eval_expr(doc, expr)?.map(|v| value_ops::value_to_display_string(&v)));
94 }
95 let Some((start, _end)) = extract_field(doc, 0, field) else {
96 return Ok(None);
97 };
98 Ok(read_str(doc, start).map(|s| s.to_string()))
99}
100
101pub fn extract_value(
104 doc: &[u8],
105 field: &str,
106 expr: Option<&SqlExpr>,
107) -> Result<Option<Value>, EvalError> {
108 if let Some(expr) = expr {
109 return eval_expr(doc, expr);
110 }
111 let Some((start, end)) = extract_field(doc, 0, field) else {
112 return Ok(None);
113 };
114 if let Some(v) = read_value(doc, start) {
115 return Ok(Some(v));
116 }
117 let field_bytes = &doc[start..end];
118 Ok(nodedb_types::json_msgpack::value_from_msgpack(field_bytes).ok())
119}
120
121pub fn extract_bytes(
124 doc: &[u8],
125 field: &str,
126 expr: Option<&SqlExpr>,
127) -> Result<Option<Vec<u8>>, EvalError> {
128 if let Some(expr) = expr {
129 let Some(val) = eval_expr(doc, expr)? else {
130 return Ok(None);
131 };
132 return Ok(nodedb_types::json_msgpack::value_to_msgpack(&val).ok());
133 }
134 let Some((start, end)) = extract_field(doc, 0, field) else {
135 return Ok(None);
136 };
137 Ok(Some(doc[start..end].to_vec()))
138}
139
140#[inline]
143pub fn extract_non_null(
144 doc: &[u8],
145 field: &str,
146 expr: Option<&SqlExpr>,
147) -> Result<Option<()>, EvalError> {
148 let Some(v) = extract_value(doc, field, expr)? else {
149 return Ok(None);
150 };
151 Ok(if v.is_null() { None } else { Some(()) })
152}