Skip to main content

linkrs_query/parser/parsing/traversal_parser/
find_path.rs

1use crate::parser::ast::stmt::*;
2use crate::parser::core::error::ParseError;
3use crate::parser::parsing::clause_parser::ClauseParser;
4use crate::parser::parsing::parse_context::ParseContext;
5use crate::parser::TokenKind;
6use linkrs_core::types::graph_schema::EdgeDirection;
7
8use super::TraversalParser;
9
10impl TraversalParser {
11    /// Analysis of the FIND PATH statement
12    pub fn parse_find_path_statement(
13        &mut self,
14        ctx: &mut ParseContext,
15    ) -> Result<Stmt, ParseError> {
16        let start_span = ctx.current_span();
17        ctx.expect_token(TokenKind::Find)?;
18
19        let shortest = if ctx.match_token(TokenKind::Shortest) {
20            true
21        } else {
22            !ctx.match_token(TokenKind::All)
23        };
24
25        ctx.expect_token(TokenKind::Path)?;
26
27        let mut with_loop = false;
28        let mut with_trail = false;
29        let mut with_walk = false;
30        while ctx.match_token(TokenKind::With) {
31            if ctx.match_token(TokenKind::Loop) {
32                with_loop = true;
33            } else if ctx.match_token(TokenKind::Trail) {
34                with_trail = true;
35            } else if ctx.match_token(TokenKind::Walk) {
36                with_walk = true;
37            }
38        }
39
40        ctx.expect_token(TokenKind::From)?;
41        let from_span = ctx.current_span();
42        let from_clause = ctx.recover_clause(
43            |c| {
44                Ok(FromClause {
45                    span: c.current_span(),
46                    vertices: Vec::new(),
47                })
48            },
49            |c| {
50                let vertices = self.parse_expression_list(c)?;
51                Ok(FromClause {
52                    span: from_span,
53                    vertices,
54                })
55            },
56        )?;
57
58        ctx.expect_token(TokenKind::To)?;
59        let to_vertex =
60            ctx.recover_clause(Self::create_true_expression, |c| self.parse_expression(c))?;
61
62        // OVER is optional: inspect whether the token is present without
63        // recording a parse error when it is absent, then consume it only in
64        // that case.
65        let over_present = ctx.check_token(TokenKind::Over);
66        let over = if over_present {
67            ctx.expect_token(TokenKind::Over)?;
68            ctx.recover_clause(
69                |c| {
70                    Ok(OverClause {
71                        span: c.current_span(),
72                        edge_types: Vec::new(),
73                        direction: EdgeDirection::Out,
74                    })
75                },
76                |c| ClauseParser::new().parse_over_clause(c),
77            )?
78        } else {
79            OverClause {
80                span: ctx.current_span(),
81                edge_types: Vec::new(),
82                direction: EdgeDirection::Out,
83            }
84        };
85
86        let mut max_steps = None;
87        if ctx.match_token(TokenKind::Upto) {
88            let steps = ctx.recover_clause(
89                |_| Ok(None),
90                |c| c.expect_integer_literal().map(|n| n as usize).map(Some),
91            )?;
92            if let Some(n) = steps {
93                max_steps = Some(n);
94                ctx.expect_token(TokenKind::Step)?;
95            }
96        }
97
98        let weight_expression = if ctx.match_token(TokenKind::Weight) {
99            ctx.recover_clause(|_| Ok(None), |c| c.expect_identifier().map(Some))?
100        } else {
101            None
102        };
103
104        let where_clause = if ctx.match_token(TokenKind::Where) {
105            Some(ctx.recover_clause(Self::create_true_expression, |c| self.parse_expression(c))?)
106        } else {
107            Some(Self::create_true_expression(ctx)?)
108        };
109
110        let yield_clause = if ctx.match_token(TokenKind::Yield) {
111            ctx.recover_clause(
112                |_| Ok(None),
113                |c| ClauseParser::new().parse_yield_clause(c).map(Some),
114            )?
115        } else {
116            None
117        };
118
119        let span = ctx.span_since(start_span.start);
120
121        Ok(Stmt::FindPath(FindPathStmt {
122            span,
123            from: from_clause,
124            to: to_vertex,
125            over: Some(over),
126            where_clause,
127            shortest,
128            max_steps,
129            limit: None,
130            skip: None,
131            yield_clause,
132            weight_expression,
133            heuristic_expression: None,
134            with_loop,
135            with_trail,
136            with_walk,
137        }))
138    }
139}