Skip to main content

velesdb_core/velesql/
graph_pattern.rs

1//! Graph pattern AST types for MATCH clause (Graph Pattern Matching).
2//!
3//! This module contains AST types for Cypher-like graph queries in VelesQL.
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8use super::ast::{Condition, Value};
9
10/// A MATCH clause for graph pattern matching.
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct MatchClause {
13    /// Graph patterns to match.
14    pub patterns: Vec<GraphPattern>,
15    /// Optional WHERE clause.
16    pub where_clause: Option<Condition>,
17    /// RETURN clause.
18    pub return_clause: ReturnClause,
19}
20
21/// A graph pattern (path or named path).
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct GraphPattern {
24    /// Optional path name (for `p = (a)-[*]->(b)`).
25    pub name: Option<String>,
26    /// Nodes in the pattern.
27    pub nodes: Vec<NodePattern>,
28    /// Relationships between nodes.
29    pub relationships: Vec<RelationshipPattern>,
30}
31
32/// A node pattern in a graph query.
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34pub struct NodePattern {
35    /// Optional alias (e.g., `n` in `(n:Person)`).
36    pub alias: Option<String>,
37    /// Node labels (e.g., `["Person", "Author"]`).
38    pub labels: Vec<String>,
39    /// Node properties for filtering.
40    pub properties: HashMap<String, Value>,
41    /// Optional source collection override for cross-collection MATCH.
42    ///
43    /// When set, this node's data is resolved from the named collection
44    /// instead of the MATCH query's default collection. Enables patterns like:
45    /// `MATCH (p:Product@products)-[:STORED_IN]->(inv:Inventory@inventory)`
46    ///
47    /// When `None`, the node is resolved from the default collection.
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub collection: Option<String>,
50}
51
52impl NodePattern {
53    /// Creates a new empty node pattern.
54    #[must_use]
55    pub fn new() -> Self {
56        Self {
57            alias: None,
58            labels: Vec::new(),
59            properties: HashMap::new(),
60            collection: None,
61        }
62    }
63
64    /// Sets the alias.
65    #[must_use]
66    pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
67        self.alias = Some(alias.into());
68        self
69    }
70
71    /// Adds a label.
72    #[must_use]
73    pub fn with_label(mut self, label: impl Into<String>) -> Self {
74        self.labels.push(label.into());
75        self
76    }
77
78    /// Sets the source collection for cross-collection MATCH.
79    #[must_use]
80    pub fn with_collection(mut self, collection: impl Into<String>) -> Self {
81        self.collection = Some(collection.into());
82        self
83    }
84}
85
86impl Default for NodePattern {
87    fn default() -> Self {
88        Self::new()
89    }
90}
91
92/// A relationship pattern in a graph query.
93#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
94pub struct RelationshipPattern {
95    /// Optional alias (e.g., `r` in `-[r:WROTE]->`).
96    pub alias: Option<String>,
97    /// Relationship types (e.g., `["WROTE", "CREATED"]` for `[:WROTE|CREATED]`).
98    pub types: Vec<String>,
99    /// Direction of the relationship.
100    pub direction: Direction,
101    /// Variable length range (e.g., `(1, 3)` for `*1..3`).
102    pub range: Option<(u32, u32)>,
103    /// Relationship properties for filtering.
104    pub properties: HashMap<String, Value>,
105}
106
107impl RelationshipPattern {
108    /// Creates a new relationship pattern with direction.
109    #[must_use]
110    pub fn new(direction: Direction) -> Self {
111        Self {
112            alias: None,
113            types: Vec::new(),
114            direction,
115            range: None,
116            properties: HashMap::new(),
117        }
118    }
119}
120
121/// Direction of a relationship.
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
123#[non_exhaustive]
124pub enum Direction {
125    /// Outgoing: `-->`
126    Outgoing,
127    /// Incoming: `<--`
128    Incoming,
129    /// Both/undirected: `--`
130    Both,
131}
132
133/// RETURN clause for specifying output.
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
135pub struct ReturnClause {
136    /// Items to return.
137    pub items: Vec<ReturnItem>,
138    /// Optional ORDER BY.
139    pub order_by: Option<Vec<OrderByItem>>,
140    /// Optional LIMIT.
141    pub limit: Option<u64>,
142}
143
144/// A single item in the RETURN clause.
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct ReturnItem {
147    /// Expression to return (e.g., `n.name`).
148    pub expression: String,
149    /// Optional alias (e.g., `AS name`).
150    pub alias: Option<String>,
151}
152
153/// ORDER BY item.
154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
155pub struct OrderByItem {
156    /// Structured expression to order by. Carrying the structured
157    /// [`OrderByExpr`](crate::velesql::OrderByExpr) (rather than a stringified
158    /// form) lets the executor evaluate arithmetic and `similarity(field, $v)`,
159    /// not just string-match property paths.
160    pub expr: crate::velesql::OrderByExpr,
161    /// Sort order.
162    pub descending: bool,
163}