Skip to main content

shape_ast/parser/queries/
helpers.rs

1//! Helper functions for query parsing
2
3use crate::error::{Result, ShapeError};
4use crate::parser::pair_location;
5use pest::iterators::Pair;
6
7use crate::ast::{Expr, OrderByClause, QueryModifiers, SortDirection};
8use crate::parser::{Rule, expressions};
9
10/// Parse query modifiers (LIMIT, ORDER BY)
11pub fn parse_query_modifiers(pair: Pair<Rule>, modifiers: &mut QueryModifiers) -> Result<()> {
12    match pair.as_rule() {
13        Rule::limit_clause => {
14            let inner = pair
15                .into_inner()
16                .next()
17                .ok_or_else(|| ShapeError::ParseError {
18                    message: "expected integer after 'limit'".to_string(),
19                    location: None,
20                })?;
21            let limit_str = inner.as_str();
22            let limit_val = limit_str
23                .parse::<usize>()
24                .map_err(|_| ShapeError::ParseError {
25                    message: format!(
26                        "invalid limit value: '{}' - must be a positive integer",
27                        limit_str
28                    ),
29                    location: Some(pair_location(&inner)),
30                })?;
31            modifiers.limit = Some(limit_val);
32        }
33        Rule::order_by_clause => {
34            let mut columns = Vec::new();
35            for inner in pair.into_inner() {
36                if inner.as_rule() == Rule::order_by_list {
37                    for item in inner.into_inner() {
38                        if item.as_rule() == Rule::order_by_item {
39                            let (expr, direction) = parse_order_by_item(item)?;
40                            columns.push((expr, direction));
41                        }
42                    }
43                }
44            }
45            modifiers.order_by = Some(OrderByClause { columns });
46        }
47        _ => {}
48    }
49    Ok(())
50}
51
52/// Parse a single ORDER BY item (expression + optional direction)
53fn parse_order_by_item(pair: Pair<Rule>) -> Result<(Expr, SortDirection)> {
54    let mut inner = pair.into_inner();
55
56    // Parse the expression
57    let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
58        message: "expected expression in ORDER BY clause".to_string(),
59        location: None,
60    })?;
61    let expr = expressions::parse_expression(expr_pair)?;
62
63    // Parse optional sort direction (defaults to ascending)
64    let direction = if let Some(dir_pair) = inner.next() {
65        match dir_pair.as_str().to_lowercase().as_str() {
66            "asc" => SortDirection::Ascending,
67            "desc" => SortDirection::Descending,
68            _ => SortDirection::Ascending,
69        }
70    } else {
71        SortDirection::Ascending
72    };
73
74    Ok((expr, direction))
75}