use super::function_trait::{Function, FunctionContext, FunctionError, FunctionResult};
use crate::storage::Value;
#[derive(Debug)]
pub struct CountFunction;
impl CountFunction {
pub fn new() -> Self {
Self
}
}
impl Function for CountFunction {
fn name(&self) -> &str {
"COUNT"
}
fn description(&self) -> &str {
"Counts the number of non-null values in a column or all rows if no column specified"
}
fn argument_count(&self) -> usize {
0 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
if context.argument_count() == 0 {
return Ok(Value::Number(context.rows.len() as f64));
}
let column_name = context.get_argument(0)?.as_string().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: "COUNT argument must be a string column name".to_string(),
}
})?;
if column_name == "*" {
return Ok(Value::Number(context.rows.len() as f64));
}
let mut count = 0;
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
if !value.is_null() {
count += 1;
}
}
}
Ok(Value::Number(count as f64))
}
fn return_type(&self) -> &str {
"Number"
}
}
#[derive(Debug)]
pub struct AverageFunction;
impl AverageFunction {
pub fn new() -> Self {
Self
}
}
impl Function for AverageFunction {
fn name(&self) -> &str {
"AVERAGE"
}
fn description(&self) -> &str {
"Calculates the arithmetic mean of numeric values in a column"
}
fn argument_count(&self) -> usize {
1 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
context.validate_argument_count(1)?;
let arg = context.get_argument(0)?;
match arg {
Value::String(column_name) => {
let mut sum = 0.0;
let mut count = 0;
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
if !value.is_null() {
let number = value.as_number().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: format!(
"Cannot convert {} to number for AVERAGE",
value.type_name()
),
}
})?;
sum += number;
count += 1;
}
}
}
if count == 0 {
log::debug!(
"DEBUG: AverageFunction::execute - returning NULL (no values found)"
);
Ok(Value::Null)
} else {
let avg = sum / count as f64;
log::debug!("DEBUG: AverageFunction::execute - returning Number({}) from sum={}, count={}", avg, sum, count);
Ok(Value::Number(avg))
}
}
Value::Number(num) => {
Ok(Value::Number(*num))
}
_ => Err(FunctionError::InvalidArgumentType {
message: "AVERAGE argument must be a string column name or numeric value"
.to_string(),
}),
}
}
fn return_type(&self) -> &str {
"Number"
}
}
#[derive(Debug)]
pub struct SumFunction;
impl SumFunction {
pub fn new() -> Self {
Self
}
}
impl Function for SumFunction {
fn name(&self) -> &str {
"SUM"
}
fn description(&self) -> &str {
"Calculates the sum of numeric values in a column"
}
fn argument_count(&self) -> usize {
1 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
let column_name = context.get_argument(0)?.as_string().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: "SUM argument must be a string column name".to_string(),
}
})?;
let mut sum = 0.0;
let mut has_values = false;
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
if !value.is_null() {
if let Some(num) = value.as_number() {
sum += num;
has_values = true;
}
}
}
}
if !has_values {
return Ok(Value::Null);
}
Ok(Value::Number(sum))
}
fn return_type(&self) -> &str {
"Number"
}
}
#[derive(Debug)]
pub struct MinFunction;
impl MinFunction {
pub fn new() -> Self {
Self
}
}
impl Function for MinFunction {
fn name(&self) -> &str {
"MIN"
}
fn description(&self) -> &str {
"Finds the minimum numeric value in a column"
}
fn argument_count(&self) -> usize {
1 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
let column_name = context.get_argument(0)?.as_string().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: "MIN argument must be a string column name".to_string(),
}
})?;
let mut min_value: Option<f64> = None;
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
if !value.is_null() {
if let Some(num) = value.as_number() {
match min_value {
None => min_value = Some(num),
Some(current_min) => {
if num < current_min {
min_value = Some(num);
}
}
}
}
}
}
}
match min_value {
Some(min) => Ok(Value::Number(min)),
None => Ok(Value::Null),
}
}
fn return_type(&self) -> &str {
"Number"
}
}
#[derive(Debug)]
pub struct MaxFunction;
impl MaxFunction {
pub fn new() -> Self {
Self
}
}
impl Function for MaxFunction {
fn name(&self) -> &str {
"MAX"
}
fn description(&self) -> &str {
"Finds the maximum numeric value in a column"
}
fn argument_count(&self) -> usize {
1 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
let column_name = context.get_argument(0)?.as_string().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: "MAX argument must be a string column name".to_string(),
}
})?;
let mut max_value: Option<f64> = None;
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
if !value.is_null() {
if let Some(num) = value.as_number() {
match max_value {
None => max_value = Some(num),
Some(current_max) => {
if num > current_max {
max_value = Some(num);
}
}
}
}
}
}
}
match max_value {
Some(max) => Ok(Value::Number(max)),
None => Ok(Value::Null),
}
}
fn return_type(&self) -> &str {
"Number"
}
}
#[derive(Debug)]
pub struct CollectFunction;
impl CollectFunction {
pub fn new() -> Self {
Self
}
}
impl Function for CollectFunction {
fn name(&self) -> &str {
"COLLECT"
}
fn description(&self) -> &str {
"Collects values from a column into a list/array"
}
fn argument_count(&self) -> usize {
1 }
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value> {
let column_name = context.get_argument(0)?.as_string().ok_or_else(|| {
FunctionError::InvalidArgumentType {
message: "COLLECT argument must be a string column name".to_string(),
}
})?;
let mut collected_values = Vec::new();
for row in &context.rows {
if let Some(value) = row.values.get(column_name) {
collected_values.push(value.clone());
}
}
Ok(Value::List(collected_values))
}
fn return_type(&self) -> &str {
"List"
}
}