1use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15pub struct CypherQuery {
16 pub match_clauses: Vec<MatchClause>,
18 pub where_clause: Option<WhereClause>,
20 pub return_clause: ReturnClause,
22 pub limit: Option<u64>,
24 pub order_by: Option<OrderByClause>,
26 pub skip: Option<u64>,
28}
29
30impl CypherQuery {
31 pub fn get_node_labels(&self) -> Vec<String> {
33 let mut labels = Vec::new();
34 for match_clause in &self.match_clauses {
35 for pattern in &match_clause.patterns {
36 match pattern {
37 GraphPattern::Node(node) => {
38 for label in &node.labels {
39 if !labels.contains(label) {
40 labels.push(label.clone());
41 }
42 }
43 }
44 GraphPattern::Path(path) => {
45 for label in &path.start_node.labels {
46 if !labels.contains(label) {
47 labels.push(label.clone());
48 }
49 }
50 for segment in &path.segments {
51 for label in &segment.end_node.labels {
52 if !labels.contains(label) {
53 labels.push(label.clone());
54 }
55 }
56 }
57 }
58 }
59 }
60 }
61 labels
62 }
63
64 pub fn get_relationship_types(&self) -> Vec<String> {
66 let mut types = Vec::new();
67 for match_clause in &self.match_clauses {
68 for pattern in &match_clause.patterns {
69 if let GraphPattern::Path(path) = pattern {
70 for segment in &path.segments {
71 for rel_type in &segment.relationship.types {
72 if !types.contains(rel_type) {
73 types.push(rel_type.clone());
74 }
75 }
76 }
77 }
78 }
79 }
80 types
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct MatchClause {
87 pub patterns: Vec<GraphPattern>,
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub enum GraphPattern {
94 Node(NodePattern),
96 Path(PathPattern),
98}
99
100#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102pub struct NodePattern {
103 pub variable: Option<String>,
105 pub labels: Vec<String>,
107 pub properties: HashMap<String, PropertyValue>,
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
113pub struct PathPattern {
114 pub start_node: NodePattern,
116 pub segments: Vec<PathSegment>,
118}
119
120#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122pub struct PathSegment {
123 pub relationship: RelationshipPattern,
125 pub end_node: NodePattern,
127}
128
129#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131pub struct RelationshipPattern {
132 pub variable: Option<String>,
134 pub types: Vec<String>,
136 pub direction: RelationshipDirection,
138 pub properties: HashMap<String, PropertyValue>,
140 pub length: Option<LengthRange>,
142}
143
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub enum RelationshipDirection {
147 Outgoing,
149 Incoming,
151 Undirected,
153}
154
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157pub struct LengthRange {
158 pub min: Option<u32>,
160 pub max: Option<u32>,
162}
163
164#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
166pub enum PropertyValue {
167 String(String),
169 Integer(i64),
171 Float(f64),
173 Boolean(bool),
175 Null,
177 Parameter(String),
179 Property(PropertyRef),
181}
182
183#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub struct PropertyRef {
186 pub variable: String,
188 pub property: String,
190}
191
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
194pub struct WhereClause {
195 pub expression: BooleanExpression,
197}
198
199#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub enum BooleanExpression {
202 Comparison {
204 left: ValueExpression,
205 operator: ComparisonOperator,
206 right: ValueExpression,
207 },
208 And(Box<BooleanExpression>, Box<BooleanExpression>),
210 Or(Box<BooleanExpression>, Box<BooleanExpression>),
212 Not(Box<BooleanExpression>),
214 Exists(PropertyRef),
216 In {
218 expression: ValueExpression,
219 list: Vec<ValueExpression>,
220 },
221 Like {
223 expression: ValueExpression,
224 pattern: String,
225 },
226 IsNull(ValueExpression),
228 IsNotNull(ValueExpression),
230}
231
232#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234pub enum ComparisonOperator {
235 Equal,
236 NotEqual,
237 LessThan,
238 LessThanOrEqual,
239 GreaterThan,
240 GreaterThanOrEqual,
241}
242
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
245pub enum ValueExpression {
246 Variable(String),
248 Property(PropertyRef),
250 Literal(PropertyValue),
252 Function {
254 name: String,
255 args: Vec<ValueExpression>,
256 },
257 Arithmetic {
259 left: Box<ValueExpression>,
260 operator: ArithmeticOperator,
261 right: Box<ValueExpression>,
262 },
263}
264
265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
267pub enum ArithmeticOperator {
268 Add,
269 Subtract,
270 Multiply,
271 Divide,
272 Modulo,
273}
274
275#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
277pub struct ReturnClause {
278 pub distinct: bool,
280 pub items: Vec<ReturnItem>,
282}
283
284#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
286pub struct ReturnItem {
287 pub expression: ValueExpression,
289 pub alias: Option<String>,
291}
292
293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
295pub struct OrderByClause {
296 pub items: Vec<OrderByItem>,
298}
299
300#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
302pub struct OrderByItem {
303 pub expression: ValueExpression,
305 pub direction: SortDirection,
307}
308
309#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
311pub enum SortDirection {
312 Ascending,
313 Descending,
314}
315
316impl NodePattern {
317 pub fn new(variable: Option<String>) -> Self {
319 Self {
320 variable,
321 labels: Vec::new(),
322 properties: HashMap::new(),
323 }
324 }
325
326 pub fn with_label<S: Into<String>>(mut self, label: S) -> Self {
328 self.labels.push(label.into());
329 self
330 }
331
332 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
334 self.properties.insert(key.into(), value);
335 self
336 }
337}
338
339impl RelationshipPattern {
340 pub fn new(direction: RelationshipDirection) -> Self {
342 Self {
343 variable: None,
344 types: Vec::new(),
345 direction,
346 properties: HashMap::new(),
347 length: None,
348 }
349 }
350
351 pub fn with_variable<S: Into<String>>(mut self, variable: S) -> Self {
353 self.variable = Some(variable.into());
354 self
355 }
356
357 pub fn with_type<S: Into<String>>(mut self, rel_type: S) -> Self {
359 self.types.push(rel_type.into());
360 self
361 }
362
363 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
365 self.properties.insert(key.into(), value);
366 self
367 }
368}
369
370impl PropertyRef {
371 pub fn new<S: Into<String>>(variable: S, property: S) -> Self {
373 Self {
374 variable: variable.into(),
375 property: property.into(),
376 }
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[test]
385 fn test_node_pattern_creation() {
386 let node = NodePattern::new(Some("n".to_string()))
387 .with_label("Person")
388 .with_property("name", PropertyValue::String("John".to_string()));
389
390 assert_eq!(node.variable, Some("n".to_string()));
391 assert_eq!(node.labels, vec!["Person"]);
392 assert_eq!(node.properties.len(), 1);
393 }
394
395 #[test]
396 fn test_relationship_pattern_creation() {
397 let rel = RelationshipPattern::new(RelationshipDirection::Outgoing)
398 .with_variable("r")
399 .with_type("KNOWS");
400
401 assert_eq!(rel.variable, Some("r".to_string()));
402 assert_eq!(rel.types, vec!["KNOWS"]);
403 assert_eq!(rel.direction, RelationshipDirection::Outgoing);
404 }
405
406 #[test]
407 fn test_property_ref() {
408 let prop_ref = PropertyRef::new("n", "name");
409 assert_eq!(prop_ref.variable, "n");
410 assert_eq!(prop_ref.property, "name");
411 }
412}