1use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15pub struct CypherQuery {
16 pub reading_clauses: Vec<ReadingClause>,
18 pub where_clause: Option<WhereClause>,
20 pub with_clause: Option<WithClause>,
22 pub post_with_reading_clauses: Vec<ReadingClause>,
24 pub post_with_where_clause: Option<WhereClause>,
26 pub return_clause: ReturnClause,
28 pub limit: Option<u64>,
30 pub order_by: Option<OrderByClause>,
32 pub skip: Option<u64>,
34}
35
36impl CypherQuery {
37 pub fn get_node_labels(&self) -> Vec<String> {
39 let mut labels = Vec::new();
40 for clause in &self.reading_clauses {
42 if let ReadingClause::Match(match_clause) = clause {
43 for pattern in &match_clause.patterns {
44 match pattern {
45 GraphPattern::Node(node) => {
46 for label in &node.labels {
47 if !labels.contains(label) {
48 labels.push(label.clone());
49 }
50 }
51 }
52 GraphPattern::Path(path) => {
53 for label in &path.start_node.labels {
54 if !labels.contains(label) {
55 labels.push(label.clone());
56 }
57 }
58 for segment in &path.segments {
59 for label in &segment.end_node.labels {
60 if !labels.contains(label) {
61 labels.push(label.clone());
62 }
63 }
64 }
65 }
66 }
67 }
68 }
69 }
70 labels
71 }
72
73 pub fn get_relationship_types(&self) -> Vec<String> {
75 let mut types = Vec::new();
76 for clause in &self.reading_clauses {
77 if let ReadingClause::Match(match_clause) = clause {
78 for pattern in &match_clause.patterns {
79 self.collect_relationship_types_from_pattern(pattern, &mut types);
80 }
81 }
82 }
83 types
84 }
85
86 fn collect_relationship_types_from_pattern(
87 &self,
88 pattern: &GraphPattern,
89 types: &mut Vec<String>,
90 ) {
91 if let GraphPattern::Path(path) = pattern {
92 for segment in &path.segments {
93 for rel_type in &segment.relationship.types {
94 if !types.contains(rel_type) {
95 types.push(rel_type.clone());
96 }
97 }
98 }
99 }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105pub enum ReadingClause {
106 Match(MatchClause),
107 Unwind(UnwindClause),
108}
109
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub struct MatchClause {
113 pub patterns: Vec<GraphPattern>,
115}
116
117#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct UnwindClause {
120 pub expression: ValueExpression,
122 pub alias: String,
124}
125
126#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub enum GraphPattern {
129 Node(NodePattern),
131 Path(PathPattern),
133}
134
135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
137pub struct NodePattern {
138 pub variable: Option<String>,
140 pub labels: Vec<String>,
142 pub properties: HashMap<String, PropertyValue>,
144}
145
146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub struct PathPattern {
149 pub start_node: NodePattern,
151 pub segments: Vec<PathSegment>,
153}
154
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157pub struct PathSegment {
158 pub relationship: RelationshipPattern,
160 pub end_node: NodePattern,
162}
163
164#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
166pub struct RelationshipPattern {
167 pub variable: Option<String>,
169 pub types: Vec<String>,
171 pub direction: RelationshipDirection,
173 pub properties: HashMap<String, PropertyValue>,
175 pub length: Option<LengthRange>,
177}
178
179#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
181pub enum RelationshipDirection {
182 Outgoing,
184 Incoming,
186 Undirected,
188}
189
190#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
192pub struct LengthRange {
193 pub min: Option<u32>,
195 pub max: Option<u32>,
197}
198
199#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub enum PropertyValue {
202 String(String),
204 Integer(i64),
206 Float(f64),
208 Boolean(bool),
210 Null,
212 Parameter(String),
214 Property(PropertyRef),
216}
217
218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
220pub struct PropertyRef {
221 pub variable: String,
223 pub property: String,
225}
226
227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
229pub struct WhereClause {
230 pub expression: BooleanExpression,
232}
233
234#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236pub enum BooleanExpression {
237 Comparison {
239 left: ValueExpression,
240 operator: ComparisonOperator,
241 right: ValueExpression,
242 },
243 And(Box<BooleanExpression>, Box<BooleanExpression>),
245 Or(Box<BooleanExpression>, Box<BooleanExpression>),
247 Not(Box<BooleanExpression>),
249 Exists(PropertyRef),
251 In {
253 expression: ValueExpression,
254 list: Vec<ValueExpression>,
255 },
256 Like {
258 expression: ValueExpression,
259 pattern: String,
260 },
261 ILike {
263 expression: ValueExpression,
264 pattern: String,
265 },
266 Contains {
268 expression: ValueExpression,
269 substring: String,
270 },
271 StartsWith {
273 expression: ValueExpression,
274 prefix: String,
275 },
276 EndsWith {
278 expression: ValueExpression,
279 suffix: String,
280 },
281 IsNull(ValueExpression),
283 IsNotNull(ValueExpression),
285}
286
287#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
289pub enum DistanceMetric {
290 L2,
292 #[default]
294 Cosine,
295 Dot,
297}
298
299#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
301pub enum ComparisonOperator {
302 Equal,
303 NotEqual,
304 LessThan,
305 LessThanOrEqual,
306 GreaterThan,
307 GreaterThanOrEqual,
308}
309
310#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
312pub enum ValueExpression {
313 Variable(String),
315 Property(PropertyRef),
317 Literal(PropertyValue),
319 ScalarFunction {
322 name: String,
323 args: Vec<ValueExpression>,
324 },
325 AggregateFunction {
328 name: String,
329 args: Vec<ValueExpression>,
330 distinct: bool,
332 },
333 Arithmetic {
335 left: Box<ValueExpression>,
336 operator: ArithmeticOperator,
337 right: Box<ValueExpression>,
338 },
339 VectorDistance {
342 left: Box<ValueExpression>,
343 right: Box<ValueExpression>,
344 metric: DistanceMetric,
345 },
346 VectorSimilarity {
349 left: Box<ValueExpression>,
350 right: Box<ValueExpression>,
351 metric: DistanceMetric,
352 },
353 Parameter(String),
355 VectorLiteral(Vec<f32>),
358}
359
360#[derive(Debug, Clone, PartialEq)]
362pub enum FunctionType {
363 Aggregate,
365 Scalar,
367 Unknown,
369}
370
371pub fn classify_function(name: &str) -> FunctionType {
373 match name.to_lowercase().as_str() {
374 "count" | "sum" | "avg" | "min" | "max" | "collect" => FunctionType::Aggregate,
375 "tolower" | "lower" | "toupper" | "upper" => FunctionType::Scalar,
376 _ => FunctionType::Unknown,
378 }
379}
380
381#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
383pub enum ArithmeticOperator {
384 Add,
385 Subtract,
386 Multiply,
387 Divide,
388 Modulo,
389}
390
391#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
396pub struct WithClause {
397 pub items: Vec<ReturnItem>,
399 pub order_by: Option<OrderByClause>,
401 pub limit: Option<u64>,
403}
404
405#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
407pub struct ReturnClause {
408 pub distinct: bool,
410 pub items: Vec<ReturnItem>,
412}
413
414#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
416pub struct ReturnItem {
417 pub expression: ValueExpression,
419 pub alias: Option<String>,
421}
422
423#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
425pub struct OrderByClause {
426 pub items: Vec<OrderByItem>,
428}
429
430#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
432pub struct OrderByItem {
433 pub expression: ValueExpression,
435 pub direction: SortDirection,
437}
438
439#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
441pub enum SortDirection {
442 Ascending,
443 Descending,
444}
445
446impl NodePattern {
447 pub fn new(variable: Option<String>) -> Self {
449 Self {
450 variable,
451 labels: Vec::new(),
452 properties: HashMap::new(),
453 }
454 }
455
456 pub fn with_label<S: Into<String>>(mut self, label: S) -> Self {
458 self.labels.push(label.into());
459 self
460 }
461
462 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
464 self.properties.insert(key.into(), value);
465 self
466 }
467}
468
469impl RelationshipPattern {
470 pub fn new(direction: RelationshipDirection) -> Self {
472 Self {
473 variable: None,
474 types: Vec::new(),
475 direction,
476 properties: HashMap::new(),
477 length: None,
478 }
479 }
480
481 pub fn with_variable<S: Into<String>>(mut self, variable: S) -> Self {
483 self.variable = Some(variable.into());
484 self
485 }
486
487 pub fn with_type<S: Into<String>>(mut self, rel_type: S) -> Self {
489 self.types.push(rel_type.into());
490 self
491 }
492
493 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
495 self.properties.insert(key.into(), value);
496 self
497 }
498}
499
500impl PropertyRef {
501 pub fn new<S: Into<String>>(variable: S, property: S) -> Self {
503 Self {
504 variable: variable.into(),
505 property: property.into(),
506 }
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use super::*;
513
514 #[test]
515 fn test_node_pattern_creation() {
516 let node = NodePattern::new(Some("n".to_string()))
517 .with_label("Person")
518 .with_property("name", PropertyValue::String("John".to_string()));
519
520 assert_eq!(node.variable, Some("n".to_string()));
521 assert_eq!(node.labels, vec!["Person"]);
522 assert_eq!(node.properties.len(), 1);
523 }
524
525 #[test]
526 fn test_relationship_pattern_creation() {
527 let rel = RelationshipPattern::new(RelationshipDirection::Outgoing)
528 .with_variable("r")
529 .with_type("KNOWS");
530
531 assert_eq!(rel.variable, Some("r".to_string()));
532 assert_eq!(rel.types, vec!["KNOWS"]);
533 assert_eq!(rel.direction, RelationshipDirection::Outgoing);
534 }
535
536 #[test]
537 fn test_property_ref() {
538 let prop_ref = PropertyRef::new("n", "name");
539 assert_eq!(prop_ref.variable, "n");
540 assert_eq!(prop_ref.property, "name");
541 }
542}