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 ILike {
228 expression: ValueExpression,
229 pattern: String,
230 },
231 Contains {
233 expression: ValueExpression,
234 substring: String,
235 },
236 StartsWith {
238 expression: ValueExpression,
239 prefix: String,
240 },
241 EndsWith {
243 expression: ValueExpression,
244 suffix: String,
245 },
246 IsNull(ValueExpression),
248 IsNotNull(ValueExpression),
250}
251
252#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
254pub enum DistanceMetric {
255 L2,
257 #[default]
259 Cosine,
260 Dot,
262}
263
264#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
266pub enum ComparisonOperator {
267 Equal,
268 NotEqual,
269 LessThan,
270 LessThanOrEqual,
271 GreaterThan,
272 GreaterThanOrEqual,
273}
274
275#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
277pub enum ValueExpression {
278 Variable(String),
280 Property(PropertyRef),
282 Literal(PropertyValue),
284 Function {
286 name: String,
287 args: Vec<ValueExpression>,
288 },
289 Arithmetic {
291 left: Box<ValueExpression>,
292 operator: ArithmeticOperator,
293 right: Box<ValueExpression>,
294 },
295 VectorDistance {
298 left: Box<ValueExpression>,
299 right: Box<ValueExpression>,
300 metric: DistanceMetric,
301 },
302 VectorSimilarity {
305 left: Box<ValueExpression>,
306 right: Box<ValueExpression>,
307 metric: DistanceMetric,
308 },
309 Parameter(String),
311 VectorLiteral(Vec<f32>),
314}
315
316#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
318pub enum ArithmeticOperator {
319 Add,
320 Subtract,
321 Multiply,
322 Divide,
323 Modulo,
324}
325
326#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
328pub struct ReturnClause {
329 pub distinct: bool,
331 pub items: Vec<ReturnItem>,
333}
334
335#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337pub struct ReturnItem {
338 pub expression: ValueExpression,
340 pub alias: Option<String>,
342}
343
344#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
346pub struct OrderByClause {
347 pub items: Vec<OrderByItem>,
349}
350
351#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
353pub struct OrderByItem {
354 pub expression: ValueExpression,
356 pub direction: SortDirection,
358}
359
360#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
362pub enum SortDirection {
363 Ascending,
364 Descending,
365}
366
367impl NodePattern {
368 pub fn new(variable: Option<String>) -> Self {
370 Self {
371 variable,
372 labels: Vec::new(),
373 properties: HashMap::new(),
374 }
375 }
376
377 pub fn with_label<S: Into<String>>(mut self, label: S) -> Self {
379 self.labels.push(label.into());
380 self
381 }
382
383 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
385 self.properties.insert(key.into(), value);
386 self
387 }
388}
389
390impl RelationshipPattern {
391 pub fn new(direction: RelationshipDirection) -> Self {
393 Self {
394 variable: None,
395 types: Vec::new(),
396 direction,
397 properties: HashMap::new(),
398 length: None,
399 }
400 }
401
402 pub fn with_variable<S: Into<String>>(mut self, variable: S) -> Self {
404 self.variable = Some(variable.into());
405 self
406 }
407
408 pub fn with_type<S: Into<String>>(mut self, rel_type: S) -> Self {
410 self.types.push(rel_type.into());
411 self
412 }
413
414 pub fn with_property<S: Into<String>>(mut self, key: S, value: PropertyValue) -> Self {
416 self.properties.insert(key.into(), value);
417 self
418 }
419}
420
421impl PropertyRef {
422 pub fn new<S: Into<String>>(variable: S, property: S) -> Self {
424 Self {
425 variable: variable.into(),
426 property: property.into(),
427 }
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 fn test_node_pattern_creation() {
437 let node = NodePattern::new(Some("n".to_string()))
438 .with_label("Person")
439 .with_property("name", PropertyValue::String("John".to_string()));
440
441 assert_eq!(node.variable, Some("n".to_string()));
442 assert_eq!(node.labels, vec!["Person"]);
443 assert_eq!(node.properties.len(), 1);
444 }
445
446 #[test]
447 fn test_relationship_pattern_creation() {
448 let rel = RelationshipPattern::new(RelationshipDirection::Outgoing)
449 .with_variable("r")
450 .with_type("KNOWS");
451
452 assert_eq!(rel.variable, Some("r".to_string()));
453 assert_eq!(rel.types, vec!["KNOWS"]);
454 assert_eq!(rel.direction, RelationshipDirection::Outgoing);
455 }
456
457 #[test]
458 fn test_property_ref() {
459 let prop_ref = PropertyRef::new("n", "name");
460 assert_eq!(prop_ref.variable, "n");
461 assert_eq!(prop_ref.property, "name");
462 }
463}