1use std::marker::PhantomData;
2
3use crate::expr::{BinaryOp, Expr, ExprNode};
4use crate::schema::{ColumnRef, Table};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum RelationKind {
8 HasMany,
9 BelongsTo,
10 ManyToMany,
11}
12
13#[derive(Debug, Clone, Copy)]
14pub struct Relation {
15 pub kind: RelationKind,
16 pub parent: Table,
17 pub child: Table,
18 pub parent_key: ColumnRef,
19 pub child_key: ColumnRef,
20 pub join_table: Option<Table>,
21 pub join_parent_key: Option<ColumnRef>,
22 pub join_child_key: Option<ColumnRef>,
23}
24
25impl Relation {
26 pub fn on_expr(&self) -> Expr<bool> {
27 let left = match self.kind {
28 RelationKind::ManyToMany => self.join_parent_key.unwrap_or(self.child_key),
29 _ => self.child_key,
30 };
31 Expr::new(ExprNode::Binary {
32 left: Box::new(ExprNode::Column(left)),
33 op: BinaryOp::Eq,
34 right: Box::new(ExprNode::Column(self.parent_key)),
35 })
36 }
37
38 pub fn join_table(&self) -> Table {
39 match self.kind {
40 RelationKind::HasMany => self.child,
41 RelationKind::ManyToMany => self.join_table.unwrap_or(self.child),
42 RelationKind::BelongsTo => self.parent,
43 }
44 }
45
46 pub fn join_steps(&self) -> Vec<(Table, Expr<bool>)> {
47 if self.kind == RelationKind::ManyToMany {
48 let join_table = self.join_table.expect("many-to-many join table");
49 let join_parent_key = self.join_parent_key.expect("many-to-many join parent key");
50 let join_child_key = self.join_child_key.expect("many-to-many join child key");
51
52 let first = Expr::new(ExprNode::Binary {
53 left: Box::new(ExprNode::Column(join_parent_key)),
54 op: BinaryOp::Eq,
55 right: Box::new(ExprNode::Column(self.parent_key)),
56 });
57 let second = Expr::new(ExprNode::Binary {
58 left: Box::new(ExprNode::Column(join_child_key)),
59 op: BinaryOp::Eq,
60 right: Box::new(ExprNode::Column(self.child_key)),
61 });
62 vec![(join_table, first), (self.child, second)]
63 } else {
64 vec![(self.join_table(), self.on_expr())]
65 }
66 }
67}
68
69pub trait RelationInfo {
70 type Parent;
71 fn relation(&self) -> Relation;
72}
73
74pub trait RelationTarget {
75 type Target;
76}
77
78pub trait BelongsToSpec<Parent> {
79 const CHILD_TABLE: Table;
80 const PARENT_TABLE: Table;
81 const CHILD_KEY: ColumnRef;
82 const PARENT_KEY: ColumnRef;
83}
84
85#[derive(Debug, Clone, Copy)]
86pub struct HasMany<Parent, Child> {
87 parent: Table,
88 child: Table,
89 parent_key: ColumnRef,
90 child_key: ColumnRef,
91 _marker: PhantomData<(Parent, Child)>,
92}
93
94impl<Parent, Child> HasMany<Parent, Child> {
95 pub const fn new(
96 parent: Table,
97 child: Table,
98 parent_key: ColumnRef,
99 child_key: ColumnRef,
100 ) -> Self {
101 Self {
102 parent,
103 child,
104 parent_key,
105 child_key,
106 _marker: PhantomData,
107 }
108 }
109
110 pub fn selectin(self) -> crate::load::SelectIn<Self> {
111 crate::load::SelectIn::new(self)
112 }
113
114 pub fn joined(self) -> crate::load::Joined<Self> {
115 crate::load::Joined::new(self)
116 }
117}
118
119impl<Parent, Child> RelationInfo for HasMany<Parent, Child> {
120 type Parent = Parent;
121
122 fn relation(&self) -> Relation {
123 Relation {
124 kind: RelationKind::HasMany,
125 parent: self.parent,
126 child: self.child,
127 parent_key: self.parent_key,
128 child_key: self.child_key,
129 join_table: None,
130 join_parent_key: None,
131 join_child_key: None,
132 }
133 }
134}
135
136impl<Parent, Child> RelationTarget for HasMany<Parent, Child> {
137 type Target = Child;
138}
139
140#[derive(Debug, Clone, Copy)]
141pub struct BelongsTo<Child, Parent> {
142 child: Table,
143 parent: Table,
144 child_key: ColumnRef,
145 parent_key: ColumnRef,
146 _marker: PhantomData<(Child, Parent)>,
147}
148
149impl<Child, Parent> BelongsTo<Child, Parent> {
150 pub const fn new(
151 child: Table,
152 parent: Table,
153 child_key: ColumnRef,
154 parent_key: ColumnRef,
155 ) -> Self {
156 Self {
157 child,
158 parent,
159 child_key,
160 parent_key,
161 _marker: PhantomData,
162 }
163 }
164
165 pub fn selectin(self) -> crate::load::SelectIn<Self> {
166 crate::load::SelectIn::new(self)
167 }
168
169 pub fn joined(self) -> crate::load::Joined<Self> {
170 crate::load::Joined::new(self)
171 }
172}
173
174impl<Child, Parent> RelationInfo for BelongsTo<Child, Parent> {
175 type Parent = Child;
176
177 fn relation(&self) -> Relation {
178 Relation {
179 kind: RelationKind::BelongsTo,
180 parent: self.parent,
181 child: self.child,
182 parent_key: self.parent_key,
183 child_key: self.child_key,
184 join_table: None,
185 join_parent_key: None,
186 join_child_key: None,
187 }
188 }
189}
190
191impl<Child, Parent> RelationTarget for BelongsTo<Child, Parent> {
192 type Target = Parent;
193}
194
195pub trait ManyToManyThrough {
196 type Through;
197}
198
199#[derive(Debug, Clone, Copy)]
200pub struct ManyToMany<Parent, Child, Through> {
201 parent: Table,
202 child: Table,
203 join: Table,
204 parent_key: ColumnRef,
205 child_key: ColumnRef,
206 join_parent_key: ColumnRef,
207 join_child_key: ColumnRef,
208 _marker: PhantomData<(Parent, Child, Through)>,
209}
210
211impl<Parent, Child, Through> ManyToMany<Parent, Child, Through> {
212 pub const fn new(
213 parent: Table,
214 child: Table,
215 join: Table,
216 parent_key: ColumnRef,
217 child_key: ColumnRef,
218 join_parent_key: ColumnRef,
219 join_child_key: ColumnRef,
220 ) -> Self {
221 Self {
222 parent,
223 child,
224 join,
225 parent_key,
226 child_key,
227 join_parent_key,
228 join_child_key,
229 _marker: PhantomData,
230 }
231 }
232
233 pub fn selectin(self) -> crate::load::SelectIn<Self> {
234 crate::load::SelectIn::new(self)
235 }
236
237 pub fn joined(self) -> crate::load::Joined<Self> {
238 crate::load::Joined::new(self)
239 }
240}
241
242impl<Parent, Child, Through> RelationInfo for ManyToMany<Parent, Child, Through> {
243 type Parent = Parent;
244
245 fn relation(&self) -> Relation {
246 Relation {
247 kind: RelationKind::ManyToMany,
248 parent: self.parent,
249 child: self.child,
250 parent_key: self.parent_key,
251 child_key: self.child_key,
252 join_table: Some(self.join),
253 join_parent_key: Some(self.join_parent_key),
254 join_child_key: Some(self.join_child_key),
255 }
256 }
257}
258
259impl<Parent, Child, Through> RelationTarget for ManyToMany<Parent, Child, Through> {
260 type Target = Child;
261}
262
263impl<Parent, Child, Through> ManyToManyThrough for ManyToMany<Parent, Child, Through> {
264 type Through = Through;
265}