MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / apply_order_by

Function apply_order_by

nodedb-sql/src/planner/select/order_by/apply.rs:27–126  ·  view source on GitHub ↗

Apply ORDER BY, detecting search-triggering sort expressions. `select_items` is the raw SELECT list from the AST. It is required so that an ORDER BY referencing an alias (`ORDER BY score DESC` where the SELECT carries `rrf_score(...) AS score`) can be resolved back to the underlying function call before the search-trigger check runs. Without this resolution the search trigger would only fire when

(
    plan: &SqlPlan,
    order_by: &ast::OrderBy,
    functions: &FunctionRegistry,
    select_items: &[ast::SelectItem],
)

Source from the content-addressed store, hash-verified

25/// function call appears in ORDER BY — a shape no SQL author would write
26/// when the same expression is also being projected.
27pub(in crate::planner::select) fn apply_order_by(
28 plan: &SqlPlan,
29 order_by: &ast::OrderBy,
30 functions: &FunctionRegistry,
31 select_items: &[ast::SelectItem],
32) -> Result<SqlPlan> {
33 let exprs = match &order_by.kind {
34 ast::OrderByKind::Expressions(exprs) => exprs,
35 ast::OrderByKind::All(_) => return Ok(plan.clone()),
36 };
37
38 if exprs.is_empty() {
39 return Ok(plan.clone());
40 }
41
42 // Two resolution rules apply before the trigger check:
43 // (a) Bare-identifier ORDER BY → look up the alias in the SELECT
44 // projection and substitute the underlying expression.
45 // (b) Literal function-call ORDER BY → also check the SELECT for the
46 // same call under an alias, and propagate that alias.
47 let first = &exprs[0];
48 let (resolved_expr, score_alias) = resolve_order_by_target(&first.expr, select_items);
49 if let Some(search_plan) =
50 try_extract_sort_search(resolved_expr, plan, functions, score_alias.as_deref())?
51 {
52 return Ok(search_plan);
53 }
54
55 // Normal sort keys.
56 let sort_keys: Vec<SortKey> = exprs
57 .iter()
58 .map(|o| {
59 Ok(SortKey {
60 expr: convert_expr(&o.expr)?,
61 ascending: o.options.asc.unwrap_or(true),
62 nulls_first: o.options.nulls_first.unwrap_or(false),
63 })
64 })
65 .collect::<Result<_>>()?;
66
67 match plan {
68 SqlPlan::Scan {
69 collection,
70 alias,
71 engine,
72 filters,
73 projection,
74 limit,
75 offset,
76 distinct,
77 window_functions,
78 temporal,
79 ..
80 } => Ok(SqlPlan::Scan {
81 collection: collection.clone(),
82 alias: alias.clone(),
83 engine: *engine,
84 filters: filters.clone(),

Callers 1

plan_queryFunction · 0.85

Calls 6

resolve_order_by_targetFunction · 0.85
try_extract_sort_searchFunction · 0.85
convert_exprFunction · 0.85
cloneMethod · 0.45
is_emptyMethod · 0.45
iterMethod · 0.45

Tested by

no test coverage detected