use sqlparser::ast;
use super::aliases::resolve_order_by_target;
use super::triggers::try_extract_sort_search;
use crate::error::Result;
use crate::functions::registry::FunctionRegistry;
use crate::resolver::expr::convert_expr;
use crate::types::*;
pub(in crate::planner::select) fn apply_order_by(
plan: &SqlPlan,
order_by: &ast::OrderBy,
functions: &FunctionRegistry,
select_items: &[ast::SelectItem],
) -> Result<SqlPlan> {
let exprs = match &order_by.kind {
ast::OrderByKind::Expressions(exprs) => exprs,
ast::OrderByKind::All(_) => return Ok(plan.clone()),
};
if exprs.is_empty() {
return Ok(plan.clone());
}
let first = &exprs[0];
let (resolved_expr, score_alias) = resolve_order_by_target(&first.expr, select_items);
if let Some(search_plan) =
try_extract_sort_search(resolved_expr, plan, functions, score_alias.as_deref())?
{
return Ok(search_plan);
}
let sort_keys: Vec<SortKey> = exprs
.iter()
.map(|o| {
Ok(SortKey {
expr: convert_expr(&o.expr)?,
ascending: o.options.asc.unwrap_or(true),
nulls_first: o.options.nulls_first.unwrap_or(false),
})
})
.collect::<Result<_>>()?;
match plan {
SqlPlan::Scan {
collection,
alias,
engine,
filters,
projection,
limit,
offset,
distinct,
window_functions,
temporal,
..
} => Ok(SqlPlan::Scan {
collection: collection.clone(),
alias: alias.clone(),
engine: *engine,
filters: filters.clone(),
projection: projection.clone(),
sort_keys,
limit: *limit,
offset: *offset,
distinct: *distinct,
window_functions: window_functions.clone(),
temporal: *temporal,
}),
SqlPlan::Aggregate {
input,
group_by,
aggregates,
having,
limit,
grouping_sets,
..
} => Ok(SqlPlan::Aggregate {
input: input.clone(),
group_by: group_by.clone(),
aggregates: aggregates.clone(),
having: having.clone(),
limit: *limit,
grouping_sets: grouping_sets.clone(),
sort_keys,
}),
SqlPlan::Cte { definitions, outer } => Ok(SqlPlan::Cte {
definitions: definitions.clone(),
outer: Box::new(apply_order_by(outer, order_by, functions, select_items)?),
}),
_ => Ok(plan.clone()),
}
}