querydown/schema/
links.rs

1use std::ops::{BitAnd, Not};
2
3use crate::syntax_tree::ConditionSet;
4
5use super::schema::{ColumnId, Schema, TableId};
6use JoinQuantity::*;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct ForwardLinkToOne {
10    pub base: Reference,
11    pub target: Reference,
12}
13
14impl From<ForeignKey> for ForwardLinkToOne {
15    fn from(foreign_key: ForeignKey) -> Self {
16        Self {
17            base: foreign_key.base,
18            target: foreign_key.target,
19        }
20    }
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct ReverseLinkToOne {
25    pub base: Reference,
26    pub target: Reference,
27}
28
29impl From<ForeignKey> for ReverseLinkToOne {
30    fn from(foreign_key: ForeignKey) -> Self {
31        Self {
32            base: foreign_key.base,
33            target: foreign_key.target,
34        }
35    }
36}
37
38#[derive(Debug, Clone, Copy)]
39pub struct ReverseLinkToMany {
40    pub base: Reference,
41    pub target: Reference,
42}
43
44impl From<ForeignKey> for ReverseLinkToMany {
45    fn from(foreign_key: ForeignKey) -> Self {
46        Self {
47            base: foreign_key.base,
48            target: foreign_key.target,
49        }
50    }
51}
52
53pub trait Link {
54    fn get_start(&self) -> Reference;
55    fn get_end(&self) -> Reference;
56    fn get_base(&self) -> Reference;
57    fn get_target(&self) -> Reference;
58    fn get_direction(&self) -> LinkDirection;
59    fn get_join_quantity(&self) -> JoinQuantity;
60}
61
62impl Link for ForwardLinkToOne {
63    fn get_direction(&self) -> LinkDirection {
64        LinkDirection::Forward
65    }
66
67    fn get_join_quantity(&self) -> JoinQuantity {
68        One
69    }
70
71    fn get_start(&self) -> Reference {
72        self.base
73    }
74
75    fn get_end(&self) -> Reference {
76        self.target
77    }
78
79    fn get_base(&self) -> Reference {
80        self.base
81    }
82
83    fn get_target(&self) -> Reference {
84        self.target
85    }
86}
87
88impl Link for ReverseLinkToOne {
89    fn get_direction(&self) -> LinkDirection {
90        LinkDirection::Reverse
91    }
92
93    fn get_join_quantity(&self) -> JoinQuantity {
94        One
95    }
96
97    fn get_start(&self) -> Reference {
98        self.target
99    }
100
101    fn get_end(&self) -> Reference {
102        self.base
103    }
104
105    fn get_base(&self) -> Reference {
106        self.base
107    }
108
109    fn get_target(&self) -> Reference {
110        self.target
111    }
112}
113
114impl Link for ReverseLinkToMany {
115    fn get_direction(&self) -> LinkDirection {
116        LinkDirection::Reverse
117    }
118
119    fn get_join_quantity(&self) -> JoinQuantity {
120        Many
121    }
122
123    fn get_start(&self) -> Reference {
124        self.target
125    }
126
127    fn get_end(&self) -> Reference {
128        self.base
129    }
130
131    fn get_base(&self) -> Reference {
132        self.base
133    }
134
135    fn get_target(&self) -> Reference {
136        self.target
137    }
138}
139
140#[derive(Debug, PartialEq, Clone, Copy)]
141pub enum JoinQuantity {
142    One,
143    Many,
144}
145
146impl BitAnd for JoinQuantity {
147    type Output = Self;
148
149    fn bitand(self, rhs: Self) -> Self::Output {
150        match (self, rhs) {
151            (One, One) => One,
152            (One, Many) => Many,
153            (Many, One) => Many,
154            (Many, Many) => Many,
155        }
156    }
157}
158
159#[derive(Debug, Clone, Copy)]
160pub enum LinkDirection {
161    Forward,
162    Reverse,
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166pub struct Reference {
167    pub table_id: TableId,
168    pub column_id: ColumnId,
169}
170
171impl Reference {
172    pub fn new(table_id: TableId, column_id: ColumnId) -> Self {
173        Self {
174            table_id,
175            column_id,
176        }
177    }
178}
179
180#[derive(Debug, Clone, Copy)]
181pub struct ForeignKey {
182    pub base: Reference,
183    pub target: Reference,
184    pub unique: bool,
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188pub enum LinkToOne {
189    ForwardLinkToOne(ForwardLinkToOne),
190    ReverseLinkToOne(ReverseLinkToOne),
191}
192
193impl Link for LinkToOne {
194    fn get_direction(&self) -> LinkDirection {
195        match self {
196            LinkToOne::ForwardLinkToOne(link) => link.get_direction(),
197            LinkToOne::ReverseLinkToOne(link) => link.get_direction(),
198        }
199    }
200
201    fn get_join_quantity(&self) -> JoinQuantity {
202        match self {
203            LinkToOne::ForwardLinkToOne(link) => link.get_join_quantity(),
204            LinkToOne::ReverseLinkToOne(link) => link.get_join_quantity(),
205        }
206    }
207
208    fn get_start(&self) -> Reference {
209        match self {
210            LinkToOne::ForwardLinkToOne(link) => link.get_start(),
211            LinkToOne::ReverseLinkToOne(link) => link.get_start(),
212        }
213    }
214
215    fn get_end(&self) -> Reference {
216        match self {
217            LinkToOne::ForwardLinkToOne(link) => link.get_end(),
218            LinkToOne::ReverseLinkToOne(link) => link.get_end(),
219        }
220    }
221
222    fn get_base(&self) -> Reference {
223        match self {
224            LinkToOne::ForwardLinkToOne(link) => link.get_base(),
225            LinkToOne::ReverseLinkToOne(link) => link.get_base(),
226        }
227    }
228
229    fn get_target(&self) -> Reference {
230        match self {
231            LinkToOne::ForwardLinkToOne(link) => link.get_target(),
232            LinkToOne::ReverseLinkToOne(link) => link.get_target(),
233        }
234    }
235}
236
237impl TryFrom<FilteredLink> for LinkToOne {
238    type Error = FilteredLink;
239
240    fn try_from(filtered_link: FilteredLink) -> Result<Self, Self::Error> {
241        if filtered_link.condition_set.is_empty().not() {
242            return Err(filtered_link);
243        }
244        match filtered_link.link {
245            MultiLink::ForwardLinkToOne(link) => Ok(LinkToOne::ForwardLinkToOne(link)),
246            MultiLink::ReverseLinkToOne(link) => Ok(LinkToOne::ReverseLinkToOne(link)),
247            _ => Err(filtered_link),
248        }
249    }
250}
251
252#[derive(Debug, Clone, Copy)]
253pub enum MultiLink {
254    ForwardLinkToOne(ForwardLinkToOne),
255    ReverseLinkToOne(ReverseLinkToOne),
256    ReverseLinkToMany(ReverseLinkToMany),
257}
258
259impl Link for MultiLink {
260    fn get_direction(&self) -> LinkDirection {
261        match self {
262            MultiLink::ForwardLinkToOne(link) => link.get_direction(),
263            MultiLink::ReverseLinkToOne(link) => link.get_direction(),
264            MultiLink::ReverseLinkToMany(link) => link.get_direction(),
265        }
266    }
267
268    fn get_join_quantity(&self) -> JoinQuantity {
269        match self {
270            MultiLink::ForwardLinkToOne(link) => link.get_join_quantity(),
271            MultiLink::ReverseLinkToOne(link) => link.get_join_quantity(),
272            MultiLink::ReverseLinkToMany(link) => link.get_join_quantity(),
273        }
274    }
275
276    fn get_start(&self) -> Reference {
277        match self {
278            MultiLink::ForwardLinkToOne(link) => link.get_start(),
279            MultiLink::ReverseLinkToOne(link) => link.get_start(),
280            MultiLink::ReverseLinkToMany(link) => link.get_start(),
281        }
282    }
283
284    fn get_end(&self) -> Reference {
285        match self {
286            MultiLink::ForwardLinkToOne(link) => link.get_end(),
287            MultiLink::ReverseLinkToOne(link) => link.get_end(),
288            MultiLink::ReverseLinkToMany(link) => link.get_end(),
289        }
290    }
291
292    fn get_base(&self) -> Reference {
293        match self {
294            MultiLink::ForwardLinkToOne(link) => link.get_base(),
295            MultiLink::ReverseLinkToOne(link) => link.get_base(),
296            MultiLink::ReverseLinkToMany(link) => link.get_base(),
297        }
298    }
299
300    fn get_target(&self) -> Reference {
301        match self {
302            MultiLink::ForwardLinkToOne(link) => link.get_target(),
303            MultiLink::ReverseLinkToOne(link) => link.get_target(),
304            MultiLink::ReverseLinkToMany(link) => link.get_target(),
305        }
306    }
307}
308
309#[derive(Debug)]
310pub struct FilteredLink {
311    pub link: MultiLink,
312    pub condition_set: ConditionSet,
313}
314
315impl From<MultiLink> for FilteredLink {
316    fn from(link: MultiLink) -> Self {
317        Self {
318            link,
319            condition_set: ConditionSet::default(),
320        }
321    }
322}
323
324impl Link for FilteredLink {
325    fn get_direction(&self) -> LinkDirection {
326        self.link.get_direction()
327    }
328
329    fn get_join_quantity(&self) -> JoinQuantity {
330        self.link.get_join_quantity()
331    }
332
333    fn get_start(&self) -> Reference {
334        self.link.get_start()
335    }
336
337    fn get_end(&self) -> Reference {
338        self.link.get_end()
339    }
340
341    fn get_base(&self) -> Reference {
342        self.link.get_base()
343    }
344
345    fn get_target(&self) -> Reference {
346        self.link.get_target()
347    }
348}