drasi_core/path_solver/
match_path.rs

1// Copyright 2024 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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::sync::Arc;
24
25use drasi_query_ast::ast;
26
27#[derive(Debug)]
28pub struct MatchPath {
29    pub slots: Vec<MatchPathSlot>,
30}
31
32impl MatchPath {
33    pub fn from_query(query_part: &ast::QueryPart) -> Result<Self, EvaluationError> {
34        let mut slots = Vec::new();
35
36        let mut alias_map = HashMap::new();
37
38        for mc in &query_part.match_clauses {
39            let slot_num = merge_node_match(&mc.start, &mut slots, &mut alias_map)?;
40            let mut prev_slot_num = slot_num;
41
42            for p in &mc.path {
43                let rel_slot_num = merge_relation_match(&p.0, &mut slots, &mut alias_map)?;
44                let node_slot_num = merge_node_match(&p.1, &mut slots, &mut alias_map)?;
45
46                match p.0.direction {
47                    ast::Direction::Right => {
48                        slots[prev_slot_num].out_slots.push(rel_slot_num);
49                        slots[rel_slot_num].in_slots.push(prev_slot_num);
50
51                        slots[rel_slot_num].out_slots.push(node_slot_num);
52                        slots[node_slot_num].in_slots.push(rel_slot_num);
53                    }
54                    ast::Direction::Left => {
55                        slots[prev_slot_num].in_slots.push(rel_slot_num);
56                        slots[rel_slot_num].out_slots.push(prev_slot_num);
57
58                        slots[rel_slot_num].in_slots.push(node_slot_num);
59                        slots[node_slot_num].out_slots.push(rel_slot_num);
60                    }
61                    ast::Direction::Either => {
62                        slots[prev_slot_num].in_slots.push(rel_slot_num);
63                        slots[prev_slot_num].out_slots.push(rel_slot_num);
64                        slots[rel_slot_num].in_slots.push(prev_slot_num);
65                        slots[rel_slot_num].out_slots.push(prev_slot_num);
66
67                        slots[node_slot_num].in_slots.push(rel_slot_num);
68                        slots[node_slot_num].out_slots.push(rel_slot_num);
69                        slots[rel_slot_num].in_slots.push(node_slot_num);
70                        slots[rel_slot_num].out_slots.push(node_slot_num);
71                    }
72                }
73
74                prev_slot_num = node_slot_num;
75            }
76        }
77
78        Ok(MatchPath { slots })
79    }
80}
81
82#[derive(Debug)]
83pub struct MatchPathSlot {
84    pub spec: SlotElementSpec,
85    pub in_slots: Vec<usize>,
86    pub out_slots: Vec<usize>,
87}
88
89#[derive(Debug)]
90pub struct SlotElementSpec {
91    pub annotation: Option<Arc<str>>,
92    pub labels: Vec<Arc<str>>,
93    pub predicates: Vec<Expression>,
94}
95
96impl SlotElementSpec {
97    pub fn new(
98        annotation: Option<Arc<str>>,
99        labels: Vec<Arc<str>>,
100        predicates: Vec<Expression>,
101    ) -> SlotElementSpec {
102        SlotElementSpec {
103            annotation,
104            labels,
105            predicates,
106        }
107    }
108
109    pub fn from_node_match(node_match: &ast::NodeMatch) -> SlotElementSpec {
110        let annotation = &node_match.annotation.name;
111        let labels = node_match.labels.clone();
112        let predicates = node_match.property_predicates.clone();
113
114        SlotElementSpec::new(annotation.clone(), labels, predicates)
115    }
116
117    pub fn from_relation_match(node_match: &ast::RelationMatch) -> SlotElementSpec {
118        let annotation = &node_match.annotation.name;
119        let labels = node_match.labels.clone();
120        let predicates = node_match.property_predicates.clone();
121
122        SlotElementSpec::new(annotation.clone(), labels, predicates)
123    }
124}