linkrs-query 0.1.0

Query engine, parser, and executor for Linkrs
Documentation
use crate::parser::ast::pattern::Pattern;
use crate::parser::ast::types::{LimitClause, SampleClause, SkipClause};
use linkrs_core::types::expr::contextual::ContextualExpression;
use linkrs_core::types::{EdgeDirection, OrderDirection, Span};

use super::Stmt;

#[derive(Debug, Clone)]
pub struct QueryStmt {
    pub span: Span,
    pub statements: Vec<Stmt>,
}

impl QueryStmt {
    pub fn new(statements: Vec<Stmt>, span: Span) -> Self {
        Self { span, statements }
    }
}

impl PartialEq for QueryStmt {
    fn eq(&self, other: &Self) -> bool {
        self.span == other.span && self.statements.len() == other.statements.len()
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct MatchStmt {
    pub span: Span,
    pub patterns: Vec<Pattern>,
    pub join_hint: Option<super::super::hint::JoinHintAst>,
    pub where_clause: Option<ContextualExpression>,
    pub return_clause: Option<ReturnClause>,
    pub order_by: Option<OrderByClause>,
    pub limit: Option<LimitClause>,
    pub skip: Option<SkipClause>,
    pub optional: bool,
    pub delete_clause: Option<MatchDeleteClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MatchDeleteClause {
    pub span: Span,
    pub target: MatchDeleteTarget,
    pub with_edge: bool,
}

#[derive(Debug, Clone, PartialEq)]
pub enum MatchDeleteTarget {
    Vertices(Vec<ContextualExpression>),
    Edges(Vec<ContextualExpression>),
    EdgeRefs(
        Vec<(
            ContextualExpression,
            ContextualExpression,
            Option<ContextualExpression>,
        )>,
    ),
}

#[derive(Debug, Clone, PartialEq)]
pub struct ReturnClause {
    pub span: Span,
    pub items: Vec<ReturnItem>,
    pub distinct: bool,
    pub order_by: Option<OrderByClause>,
    pub limit: Option<LimitClause>,
    pub skip: Option<SkipClause>,
    pub sample: Option<SampleClause>,
    pub having_clause: Option<ContextualExpression>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum ReturnItem {
    Expression {
        expression: ContextualExpression,
        alias: Option<String>,
    },
}

#[derive(Debug, Clone, PartialEq)]
pub struct OrderByClause {
    pub span: Span,
    pub items: Vec<OrderByItem>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct OrderByItem {
    pub expression: ContextualExpression,
    pub direction: OrderDirection,
}

#[derive(Debug, Clone, PartialEq)]
pub struct GoStmt {
    pub span: Span,
    pub steps: Steps,
    pub from: FromClause,
    pub over: Option<OverClause>,
    pub where_clause: Option<ContextualExpression>,
    pub yield_clause: Option<YieldClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Steps {
    Fixed(usize),
    Range { min: usize, max: usize },
    Variable(String),
}

#[derive(Debug, Clone, PartialEq)]
pub struct StepClause {
    pub span: Span,
    pub steps: Steps,
}

#[derive(Debug, Clone, PartialEq)]
pub struct WhereClause {
    pub span: Span,
    pub condition: ContextualExpression,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FromClause {
    pub span: Span,
    pub vertices: Vec<ContextualExpression>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct OverClause {
    pub span: Span,
    pub edge_types: Vec<String>,
    pub direction: EdgeDirection,
}

#[derive(Debug, Clone, PartialEq)]
pub struct YieldClause {
    pub span: Span,
    /// `YIELD DISTINCT`: collapse duplicate projected rows.
    pub distinct: bool,
    pub items: Vec<YieldItem>,
    pub where_clause: Option<ContextualExpression>,
    pub order_by: Option<OrderByClause>,
    pub limit: Option<LimitClause>,
    pub skip: Option<SkipClause>,
    pub sample: Option<SampleClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct YieldItem {
    pub expression: ContextualExpression,
    pub alias: Option<String>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FetchStmt {
    pub span: Span,
    pub target: FetchTarget,
    pub yield_clause: Option<YieldClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum FetchTarget {
    Vertices {
        tag_name: Option<String>,
        ids: Vec<ContextualExpression>,
        properties: Option<Vec<String>>,
    },
    Edges {
        src: ContextualExpression,
        dst: ContextualExpression,
        edge_type: String,
        rank: Option<ContextualExpression>,
        properties: Option<Vec<String>>,
    },
}

#[derive(Debug, Clone, PartialEq)]
pub struct LookupStmt {
    pub span: Span,
    pub target: LookupTarget,
    pub where_clause: Option<ContextualExpression>,
    pub yield_clause: Option<YieldClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum LookupTarget {
    Tag(String),
    Edge(String),
    Unspecified(String),
}

#[derive(Debug, Clone, PartialEq)]
pub struct SubgraphStmt {
    pub span: Span,
    pub steps: Steps,
    pub from: FromClause,
    pub over: Option<OverClause>,
    pub where_clause: Option<ContextualExpression>,
    pub yield_clause: Option<YieldClause>,
    pub with_prop: bool,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FindPathStmt {
    pub span: Span,
    pub from: FromClause,
    pub to: ContextualExpression,
    pub over: Option<OverClause>,
    pub where_clause: Option<ContextualExpression>,
    pub shortest: bool,
    pub max_steps: Option<usize>,
    pub limit: Option<LimitClause>,
    pub skip: Option<SkipClause>,
    pub yield_clause: Option<YieldClause>,
    pub weight_expression: Option<String>,
    pub heuristic_expression: Option<String>,
    /// `WITH LOOP`: self-loop edges may be taken as terminal extensions.
    pub with_loop: bool,
    /// `WITH TRAIL`: path edges may not repeat; vertices may.
    pub with_trail: bool,
    /// `WITH WALK`: path vertices may repeat.
    pub with_walk: bool,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ReturnStmt {
    pub span: Span,
    pub items: Vec<ReturnItem>,
    pub distinct: bool,
    pub order_by: Option<OrderByClause>,
    pub skip: Option<SkipClause>,
    pub limit: Option<LimitClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct YieldStmt {
    pub span: Span,
    pub items: Vec<YieldItem>,
    pub where_clause: Option<ContextualExpression>,
    pub distinct: bool,
    pub order_by: Option<OrderByClause>,
    pub skip: Option<SkipClause>,
    pub limit: Option<LimitClause>,
    pub sample: Option<SampleClause>,
}

/// `LOAD FROM <source> [OPTIONS (...)] [RETURN ...]` reading clause.
#[derive(Debug, Clone, PartialEq)]
pub struct LoadFromStmt {
    pub span: Span,
    pub headers: Vec<LoadHeaderColumn>,
    pub source: ScanSource,
    pub options: Vec<LoadOption>,
    pub return_clause: Option<ReturnClause>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct LoadHeaderColumn {
    pub name: String,
    pub data_type: Option<String>,
}

#[derive(Debug, Clone)]
pub enum ScanSource {
    File(String),
    Glob(String),
    TableFunc {
        name: String,
        args: Vec<ContextualExpression>,
    },
    Query(Box<Stmt>),
}

impl PartialEq for ScanSource {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (ScanSource::File(a), ScanSource::File(b)) => a == b,
            (ScanSource::Glob(a), ScanSource::Glob(b)) => a == b,
            (
                ScanSource::TableFunc { name: a, args: aa },
                ScanSource::TableFunc { name: b, args: ab },
            ) => a == b && aa == ab,
            (ScanSource::Query(a), ScanSource::Query(b)) => format!("{a:?}") == format!("{b:?}"),
            _ => false,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct LoadOption {
    pub key: String,
    pub value: String,
}

/// `CALL <func>(<args>) [YIELD <cols>]` in-query function call.
#[derive(Debug, Clone, PartialEq)]
pub struct InQueryCallStmt {
    pub span: Span,
    pub func_name: String,
    pub args: Vec<ContextualExpression>,
    pub yield_clause: Option<YieldClause>,
}