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}