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(parent: Table, child: Table, parent_key: ColumnRef, child_key: ColumnRef) -> Self {
96 Self {
97 parent,
98 child,
99 parent_key,
100 child_key,
101 _marker: PhantomData,
102 }
103 }
104
105 pub fn selectin(self) -> crate::load::SelectIn<Self> {
106 crate::load::SelectIn::new(self)
107 }
108
109 pub fn joined(self) -> crate::load::Joined<Self> {
110 crate::load::Joined::new(self)
111 }
112}
113
114impl<Parent, Child> RelationInfo for HasMany<Parent, Child> {
115 type Parent = Parent;
116
117 fn relation(&self) -> Relation {
118 Relation {
119 kind: RelationKind::HasMany,
120 parent: self.parent,
121 child: self.child,
122 parent_key: self.parent_key,
123 child_key: self.child_key,
124 join_table: None,
125 join_parent_key: None,
126 join_child_key: None,
127 }
128 }
129}
130
131impl<Parent, Child> RelationTarget for HasMany<Parent, Child> {
132 type Target = Child;
133}
134
135#[derive(Debug, Clone, Copy)]
136pub struct BelongsTo<Child, Parent> {
137 child: Table,
138 parent: Table,
139 child_key: ColumnRef,
140 parent_key: ColumnRef,
141 _marker: PhantomData<(Child, Parent)>,
142}
143
144impl<Child, Parent> BelongsTo<Child, Parent> {
145 pub const fn new(child: Table, parent: Table, child_key: ColumnRef, parent_key: ColumnRef) -> Self {
146 Self {
147 child,
148 parent,
149 child_key,
150 parent_key,
151 _marker: PhantomData,
152 }
153 }
154
155 pub fn selectin(self) -> crate::load::SelectIn<Self> {
156 crate::load::SelectIn::new(self)
157 }
158
159 pub fn joined(self) -> crate::load::Joined<Self> {
160 crate::load::Joined::new(self)
161 }
162}
163
164impl<Child, Parent> RelationInfo for BelongsTo<Child, Parent> {
165 type Parent = Child;
166
167 fn relation(&self) -> Relation {
168 Relation {
169 kind: RelationKind::BelongsTo,
170 parent: self.parent,
171 child: self.child,
172 parent_key: self.parent_key,
173 child_key: self.child_key,
174 join_table: None,
175 join_parent_key: None,
176 join_child_key: None,
177 }
178 }
179}
180
181impl<Child, Parent> RelationTarget for BelongsTo<Child, Parent> {
182 type Target = Parent;
183}
184
185pub trait ManyToManyThrough {
186 type Through;
187}
188
189#[derive(Debug, Clone, Copy)]
190pub struct ManyToMany<Parent, Child, Through> {
191 parent: Table,
192 child: Table,
193 join: Table,
194 parent_key: ColumnRef,
195 child_key: ColumnRef,
196 join_parent_key: ColumnRef,
197 join_child_key: ColumnRef,
198 _marker: PhantomData<(Parent, Child, Through)>,
199}
200
201impl<Parent, Child, Through> ManyToMany<Parent, Child, Through> {
202 pub const fn new(
203 parent: Table,
204 child: Table,
205 join: Table,
206 parent_key: ColumnRef,
207 child_key: ColumnRef,
208 join_parent_key: ColumnRef,
209 join_child_key: ColumnRef,
210 ) -> Self {
211 Self {
212 parent,
213 child,
214 join,
215 parent_key,
216 child_key,
217 join_parent_key,
218 join_child_key,
219 _marker: PhantomData,
220 }
221 }
222
223 pub fn selectin(self) -> crate::load::SelectIn<Self> {
224 crate::load::SelectIn::new(self)
225 }
226
227 pub fn joined(self) -> crate::load::Joined<Self> {
228 crate::load::Joined::new(self)
229 }
230}
231
232impl<Parent, Child, Through> RelationInfo for ManyToMany<Parent, Child, Through> {
233 type Parent = Parent;
234
235 fn relation(&self) -> Relation {
236 Relation {
237 kind: RelationKind::ManyToMany,
238 parent: self.parent,
239 child: self.child,
240 parent_key: self.parent_key,
241 child_key: self.child_key,
242 join_table: Some(self.join),
243 join_parent_key: Some(self.join_parent_key),
244 join_child_key: Some(self.join_child_key),
245 }
246 }
247}
248
249impl<Parent, Child, Through> RelationTarget for ManyToMany<Parent, Child, Through> {
250 type Target = Child;
251}
252
253impl<Parent, Child, Through> ManyToManyThrough for ManyToMany<Parent, Child, Through> {
254 type Through = Through;
255}