linkrs-query 0.1.0

Query engine, parser, and executor for Linkrs
Documentation
use crate::parser::ast::stmt::*;
use crate::parser::core::error::ParseError;
use crate::parser::parsing::clause_parser::ClauseParser;
use crate::parser::parsing::parse_context::ParseContext;
use crate::parser::TokenKind;
use linkrs_core::types::graph_schema::EdgeDirection;

use super::TraversalParser;

impl TraversalParser {
    /// Analysis of the FIND PATH statement
    pub fn parse_find_path_statement(
        &mut self,
        ctx: &mut ParseContext,
    ) -> Result<Stmt, ParseError> {
        let start_span = ctx.current_span();
        ctx.expect_token(TokenKind::Find)?;

        let shortest = if ctx.match_token(TokenKind::Shortest) {
            true
        } else {
            !ctx.match_token(TokenKind::All)
        };

        ctx.expect_token(TokenKind::Path)?;

        let mut with_loop = false;
        let mut with_trail = false;
        let mut with_walk = false;
        while ctx.match_token(TokenKind::With) {
            if ctx.match_token(TokenKind::Loop) {
                with_loop = true;
            } else if ctx.match_token(TokenKind::Trail) {
                with_trail = true;
            } else if ctx.match_token(TokenKind::Walk) {
                with_walk = true;
            }
        }

        ctx.expect_token(TokenKind::From)?;
        let from_span = ctx.current_span();
        let from_clause = ctx.recover_clause(
            |c| {
                Ok(FromClause {
                    span: c.current_span(),
                    vertices: Vec::new(),
                })
            },
            |c| {
                let vertices = self.parse_expression_list(c)?;
                Ok(FromClause {
                    span: from_span,
                    vertices,
                })
            },
        )?;

        ctx.expect_token(TokenKind::To)?;
        let to_vertex =
            ctx.recover_clause(Self::create_true_expression, |c| self.parse_expression(c))?;

        // OVER is optional: inspect whether the token is present without
        // recording a parse error when it is absent, then consume it only in
        // that case.
        let over_present = ctx.check_token(TokenKind::Over);
        let over = if over_present {
            ctx.expect_token(TokenKind::Over)?;
            ctx.recover_clause(
                |c| {
                    Ok(OverClause {
                        span: c.current_span(),
                        edge_types: Vec::new(),
                        direction: EdgeDirection::Out,
                    })
                },
                |c| ClauseParser::new().parse_over_clause(c),
            )?
        } else {
            OverClause {
                span: ctx.current_span(),
                edge_types: Vec::new(),
                direction: EdgeDirection::Out,
            }
        };

        let mut max_steps = None;
        if ctx.match_token(TokenKind::Upto) {
            let steps = ctx.recover_clause(
                |_| Ok(None),
                |c| c.expect_integer_literal().map(|n| n as usize).map(Some),
            )?;
            if let Some(n) = steps {
                max_steps = Some(n);
                ctx.expect_token(TokenKind::Step)?;
            }
        }

        let weight_expression = if ctx.match_token(TokenKind::Weight) {
            ctx.recover_clause(|_| Ok(None), |c| c.expect_identifier().map(Some))?
        } else {
            None
        };

        let where_clause = if ctx.match_token(TokenKind::Where) {
            Some(ctx.recover_clause(Self::create_true_expression, |c| self.parse_expression(c))?)
        } else {
            Some(Self::create_true_expression(ctx)?)
        };

        let yield_clause = if ctx.match_token(TokenKind::Yield) {
            ctx.recover_clause(
                |_| Ok(None),
                |c| ClauseParser::new().parse_yield_clause(c).map(Some),
            )?
        } else {
            None
        };

        let span = ctx.span_since(start_span.start);

        Ok(Stmt::FindPath(FindPathStmt {
            span,
            from: from_clause,
            to: to_vertex,
            over: Some(over),
            where_clause,
            shortest,
            max_steps,
            limit: None,
            skip: None,
            yield_clause,
            weight_expression,
            heuristic_expression: None,
            with_loop,
            with_trail,
            with_walk,
        }))
    }
}