1use sqlitegraph::{
2 backend::BackendDirection,
3 pattern::{PatternLeg, PatternQuery},
4};
5
6#[derive(Debug, Clone)]
8pub enum DslResult {
9 Pattern(PatternQuery),
10 Error(String),
11}
12
13pub fn parse_dsl(input: &str) -> DslResult {
14 let trimmed = input.trim();
15 if trimmed.is_empty() {
16 return DslResult::Error("empty DSL string".into());
17 }
18 if trimmed.starts_with("pattern ") {
19 return parse_pattern_pipeline(trimmed);
20 }
21 if trimmed.contains("->") || trimmed.contains('*') {
22 return DslResult::Pattern(parse_repetitive_pattern(trimmed));
23 }
24 DslResult::Error(format!("unsupported DSL form: {trimmed}"))
25}
26
27fn parse_pattern_pipeline(input: &str) -> DslResult {
28 let rest = input.trim_start_matches("pattern").trim();
29 let mut segments = rest.splitn(2, "filter");
30 let pattern_part = segments.next().unwrap_or("").trim();
31 if pattern_part.is_empty() {
32 return DslResult::Error("missing pattern segment".into());
33 }
34 let _query = parse_repetitive_pattern(pattern_part);
35 DslResult::Pattern(_query)
37}
38
39fn parse_repetitive_pattern(segment: &str) -> PatternQuery {
40 let mut legs = Vec::new();
41 for token in segment.split("->") {
42 let trimmed = token.trim();
43 if trimmed.is_empty() {
44 continue;
45 }
46 let (ty, count) = if let Some((name, times)) = trimmed.split_once('*') {
47 let repeats = times.trim().parse::<usize>().unwrap_or(1);
48 (name.trim(), repeats)
49 } else {
50 (trimmed, 1)
51 };
52 for _ in 0..count {
53 legs.push(PatternLeg {
54 direction: BackendDirection::Outgoing,
55 edge_type: Some(ty.to_string()),
56 constraint: None,
57 });
58 }
59 }
60 PatternQuery { root: None, legs }
61}
62
63