mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-21 02:28:07 +02:00
Merge pull request #6 from ModernRelay/claude/omnigraph-aggregates-a53rG
Implement aggregate functions with GROUP BY support
This commit is contained in:
commit
c5a88cacb5
6 changed files with 868 additions and 152 deletions
|
|
@ -189,6 +189,29 @@ fn typecheck_read_query(catalog: &Catalog, query: &QueryDecl) -> Result<TypeCont
|
|||
));
|
||||
}
|
||||
|
||||
// T9: If any return expression is an aggregate, non-aggregate expressions
|
||||
// must be valid group-by keys (PropAccess or Variable).
|
||||
let has_agg = query
|
||||
.return_clause
|
||||
.iter()
|
||||
.any(|p| matches!(p.expr, Expr::Aggregate { .. }));
|
||||
if has_agg {
|
||||
for proj in &query.return_clause {
|
||||
if !matches!(proj.expr, Expr::Aggregate { .. }) {
|
||||
match &proj.expr {
|
||||
Expr::PropAccess { .. } | Expr::Variable(_) => {}
|
||||
_ => {
|
||||
return Err(NanoError::Type(
|
||||
"T9: non-aggregate expressions in an aggregate query must be \
|
||||
property accesses or variables"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -1298,9 +1321,9 @@ fn resolve_expr_type(
|
|||
Expr::Aggregate { func, arg } => {
|
||||
let arg_type = resolve_expr_type(catalog, arg, ctx, params)?;
|
||||
|
||||
// T8: sum/avg/min/max require numeric
|
||||
// T8: sum/avg require numeric; min/max require numeric or string
|
||||
match func {
|
||||
AggFunc::Sum | AggFunc::Avg | AggFunc::Min | AggFunc::Max => {
|
||||
AggFunc::Sum | AggFunc::Avg => {
|
||||
if let ResolvedType::Scalar(s) = &arg_type
|
||||
&& (s.list || !s.scalar.is_numeric())
|
||||
{
|
||||
|
|
@ -1311,6 +1334,17 @@ fn resolve_expr_type(
|
|||
)));
|
||||
}
|
||||
}
|
||||
AggFunc::Min | AggFunc::Max => {
|
||||
if let ResolvedType::Scalar(s) = &arg_type
|
||||
&& (s.list || (!s.scalar.is_numeric() && s.scalar != ScalarType::String))
|
||||
{
|
||||
return Err(NanoError::Type(format!(
|
||||
"T8: {} requires numeric or string type, got {}",
|
||||
func,
|
||||
s.display_name()
|
||||
)));
|
||||
}
|
||||
}
|
||||
_ => {} // count works on any type
|
||||
}
|
||||
|
||||
|
|
@ -1340,8 +1374,8 @@ fn infer_projection_field(
|
|||
Expr::Aggregate { func, arg } => {
|
||||
let (data_type, nullable) = match func {
|
||||
AggFunc::Count => (DataType::Int64, true),
|
||||
AggFunc::Avg => (DataType::Float64, true),
|
||||
_ => {
|
||||
AggFunc::Avg | AggFunc::Sum => (DataType::Float64, true),
|
||||
AggFunc::Min | AggFunc::Max => {
|
||||
let resolved = resolve_expr_type(catalog, arg, ctx, params)?;
|
||||
let (data_type, _) = resolved_type_to_field_shape(catalog, &resolved)?;
|
||||
(data_type, true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue