drasi_core/path_solver/
match_path.rs1use drasi_query_ast::ast::Expression;
16
17use super::merge_relation_match;
18
19use super::merge_node_match;
20
21use crate::evaluation::EvaluationError;
22use std::collections::HashMap;
23use std::collections::HashSet;
24use std::sync::Arc;
25
26use drasi_query_ast::ast;
27
28#[derive(Debug)]
29pub struct MatchPath {
30 pub slots: Vec<MatchPathSlot>,
31 optional_paths: HashSet<usize>,
32}
33
34impl MatchPath {
35 pub fn from_query(query_part: &ast::QueryPart) -> Result<Self, EvaluationError> {
36 let mut slots = Vec::new();
37
38 let mut alias_map = HashMap::new();
39 let mut optional_paths = HashSet::new();
40
41 for (path_index, mc) in query_part.match_clauses.iter().enumerate() {
42 if mc.optional {
43 optional_paths.insert(path_index);
44 }
45 let slot_num = merge_node_match(
46 &mc.start,
47 &mut slots,
48 &mut alias_map,
49 path_index,
50 mc.optional,
51 )?;
52 let mut prev_slot_num = slot_num;
53
54 for p in &mc.path {
55 let rel_slot_num = merge_relation_match(
56 &p.0,
57 &mut slots,
58 &mut alias_map,
59 path_index,
60 mc.optional,
61 )?;
62 let node_slot_num =
63 merge_node_match(&p.1, &mut slots, &mut alias_map, path_index, mc.optional)?;
64
65 match p.0.direction {
66 ast::Direction::Right => {
67 slots[prev_slot_num].out_slots.push(rel_slot_num);
68 slots[rel_slot_num].in_slots.push(prev_slot_num);
69
70 slots[rel_slot_num].out_slots.push(node_slot_num);
71 slots[node_slot_num].in_slots.push(rel_slot_num);
72 }
73 ast::Direction::Left => {
74 slots[prev_slot_num].in_slots.push(rel_slot_num);
75 slots[rel_slot_num].out_slots.push(prev_slot_num);
76
77 slots[rel_slot_num].in_slots.push(node_slot_num);
78 slots[node_slot_num].out_slots.push(rel_slot_num);
79 }
80 ast::Direction::Either => {
81 slots[prev_slot_num].in_slots.push(rel_slot_num);
82 slots[prev_slot_num].out_slots.push(rel_slot_num);
83 slots[rel_slot_num].in_slots.push(prev_slot_num);
84 slots[rel_slot_num].out_slots.push(prev_slot_num);
85
86 slots[node_slot_num].in_slots.push(rel_slot_num);
87 slots[node_slot_num].out_slots.push(rel_slot_num);
88 slots[rel_slot_num].in_slots.push(node_slot_num);
89 slots[rel_slot_num].out_slots.push(node_slot_num);
90 }
91 }
92
93 prev_slot_num = node_slot_num;
94 }
95 }
96
97 Ok(MatchPath {
98 slots,
99 optional_paths,
100 })
101 }
102
103 pub fn get_optional_slots_on_common_paths(
104 &self,
105 anchor_slot_num: usize,
106 empty_slots: HashSet<usize>,
107 ) -> HashSet<usize> {
108 let mut optional_slots = HashSet::new();
109 for path in &self.slots[anchor_slot_num].paths {
110 let mut has_empty_slots = false;
111 let mut path_slots = HashSet::new();
112
113 for (slot_num, slot) in self.slots.iter().enumerate() {
114 if slot.optional && slot.paths.contains(path) {
115 if empty_slots.contains(&slot_num) {
116 has_empty_slots = true;
117 break;
118 }
119
120 if slot_num != anchor_slot_num && slot.paths.len() > 1 {
121 continue;
122 }
123
124 path_slots.insert(slot_num);
125 }
126 }
127 if !has_empty_slots {
128 optional_slots.extend(path_slots);
129 }
130 }
131
132 optional_slots
133 }
134}
135
136#[derive(Debug)]
137pub struct MatchPathSlot {
138 pub spec: SlotElementSpec,
139 pub in_slots: Vec<usize>,
140 pub out_slots: Vec<usize>,
141 pub paths: HashSet<usize>,
142 pub optional: bool,
143}
144
145#[derive(Debug)]
146pub struct SlotElementSpec {
147 pub annotation: Option<Arc<str>>,
148 pub labels: Vec<Arc<str>>,
149 pub predicates: Vec<Expression>,
150}
151
152impl SlotElementSpec {
153 pub fn new(
154 annotation: Option<Arc<str>>,
155 labels: Vec<Arc<str>>,
156 predicates: Vec<Expression>,
157 ) -> SlotElementSpec {
158 SlotElementSpec {
159 annotation,
160 labels,
161 predicates,
162 }
163 }
164
165 pub fn from_node_match(node_match: &ast::NodeMatch) -> SlotElementSpec {
166 let annotation = &node_match.annotation.name;
167 let labels = node_match.labels.clone();
168 let predicates = node_match.property_predicates.clone();
169
170 SlotElementSpec::new(annotation.clone(), labels, predicates)
171 }
172
173 pub fn from_relation_match(node_match: &ast::RelationMatch) -> SlotElementSpec {
174 let annotation = &node_match.annotation.name;
175 let labels = node_match.labels.clone();
176 let predicates = node_match.property_predicates.clone();
177
178 SlotElementSpec::new(annotation.clone(), labels, predicates)
179 }
180}