use crate::{
db::{
executor::KernelRow,
query::{
builder::aggregate::AggregateExpr,
plan::expr::{Expr, ProjectionField, ProjectionSpec},
},
},
model::EntityModel,
value::Value,
};
fn projection_label_from_aggregate(aggregate: &AggregateExpr) -> String {
let kind = aggregate.kind().sql_label();
let distinct = if aggregate.is_distinct() {
"DISTINCT "
} else {
""
};
if let Some(field) = aggregate.target_field() {
return format!("{kind}({distinct}{field})");
}
format!("{kind}({distinct}*)")
}
fn projection_label_from_expr(expr: &Expr, ordinal: usize) -> String {
match expr {
Expr::Field(field) => field.as_str().to_string(),
Expr::Aggregate(aggregate) => projection_label_from_aggregate(aggregate),
Expr::Alias { name, .. } => name.as_str().to_string(),
Expr::Literal(_) | Expr::Unary { .. } | Expr::Binary { .. } => {
format!("expr_{ordinal}")
}
}
}
pub(in crate::db::session::sql) fn projection_labels_from_projection_spec(
projection: &ProjectionSpec,
) -> Vec<String> {
let mut labels = Vec::with_capacity(projection.len());
for (ordinal, field) in projection.fields().enumerate() {
match field {
ProjectionField::Scalar {
expr: _,
alias: Some(alias),
} => labels.push(alias.as_str().to_string()),
ProjectionField::Scalar { expr, alias: None } => {
labels.push(projection_label_from_expr(expr, ordinal));
}
}
}
labels
}
pub(in crate::db::session::sql) fn projection_labels_from_entity_model(
model: &'static EntityModel,
) -> Vec<String> {
model
.fields
.iter()
.map(|field| field.name.to_string())
.collect()
}
pub(in crate::db::session::sql) fn sql_projection_rows_from_kernel_rows(
rows: Vec<KernelRow>,
) -> Vec<Vec<Value>> {
rows.into_iter()
.map(|row| {
row.into_slots()
.into_iter()
.map(|value| value.unwrap_or(Value::Null))
.collect()
})
.collect()
}