mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-25 12:04:21 +01:00
#708 This PR adds basic support for the following API for defining Aggregates, and changes the existing API for scalars. ```rust register_extension! { scalars: { Double }, aggregates: { MedianState }, } #[derive(ScalarDerive)] struct Double; impl Scalar for Double { fn name(&self) -> &'static str { "double" } fn call(&self, args: &[Value]) -> Value { if let Some(arg) = args.first() { match arg.value_type() { ValueType::Float => { let val = arg.to_float().unwrap(); Value::from_float(val * 2.0) } ValueType::Integer => { let val = arg.to_integer().unwrap(); Value::from_integer(val * 2) } _ => { println!("arg: {:?}", arg); Value::null() } } } else { Value::null() } } } #[derive(AggregateDerive)] struct MedianState; impl AggFunc for MedianState { type State = Vec<f64>; fn name(&self) -> &'static str { "median" } fn args(&self) -> i32 { 1 } fn step(state: &mut Self::State, args: &[Value]) { if let Some(val) = args.first().and_then(Value::to_float) { state.push(val); } } fn finalize(state: Self::State) -> Value { if state.is_empty() { return Value::null(); } let mut sorted = state; sorted.sort_by(|a, b| a.partial_cmp(b).unwrap()); let len = sorted.len(); if len % 2 == 1 { Value::from_float(sorted[len / 2]) } else { let mid1 = sorted[len / 2 - 1]; let mid2 = sorted[len / 2]; Value::from_float((mid1 + mid2) / 2.0) } } } ``` I know it's a bit more verbose than the previous version, but I think in the long run this will be more robust, and it matches the aggregate API of implementing a trait on a struct that you derive the relevant trait on. Also this allows for better registration of functions, I think passing in the struct identifiers just feels much better than the `"func_name" => function_ptr` Closes #721