1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum RelationKind {
37 HasOne,
39 HasMany,
41 BelongsTo,
43 ManyToMany,
45}
46
47impl RelationKind {
48 pub fn default_join_type(self) -> JoinKind {
53 match self {
54 RelationKind::HasOne | RelationKind::BelongsTo => JoinKind::Inner,
55 RelationKind::HasMany | RelationKind::ManyToMany => JoinKind::Left,
56 }
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum JoinKind {
63 Inner,
65 Left,
67}
68
69impl JoinKind {
70 pub fn as_sql(self) -> &'static str {
72 match self {
73 JoinKind::Inner => "INNER JOIN",
74 JoinKind::Left => "LEFT JOIN",
75 }
76 }
77}
78
79#[derive(Debug, Clone)]
84pub struct RelationDef {
85 pub name: &'static str,
87 pub from_entity: &'static str,
89 pub to_entity: &'static str,
91 pub from_key: &'static str,
93 pub to_key: &'static str,
95 pub kind: RelationKind,
97}
98
99impl RelationDef {
100 pub const fn new(
102 name: &'static str,
103 from_entity: &'static str,
104 to_entity: &'static str,
105 from_key: &'static str,
106 to_key: &'static str,
107 kind: RelationKind,
108 ) -> Self {
109 Self {
110 name,
111 from_entity,
112 to_entity,
113 from_key,
114 to_key,
115 kind,
116 }
117 }
118}
119
120pub trait RelationTrait: Send + Sync {
125 fn def(&self) -> &'static RelationDef;
127
128 fn all_relations() -> &'static [RelationDef]
130 where
131 Self: Sized;
132
133 fn relation_by_name(name: &str) -> Option<&'static RelationDef>
135 where
136 Self: Sized,
137 {
138 Self::all_relations().iter().find(|r| r.name == name)
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 static TEST_RELATIONS: &[RelationDef] = &[
147 RelationDef::new(
148 "orders",
149 "users",
150 "orders",
151 "id",
152 "user_id",
153 RelationKind::HasMany,
154 ),
155 RelationDef::new(
156 "profile",
157 "users",
158 "profiles",
159 "id",
160 "user_id",
161 RelationKind::HasOne,
162 ),
163 RelationDef::new(
164 "owner",
165 "orders",
166 "users",
167 "user_id",
168 "id",
169 RelationKind::BelongsTo,
170 ),
171 RelationDef::new(
172 "roles",
173 "users",
174 "roles",
175 "id",
176 "role_id",
177 RelationKind::ManyToMany,
178 ),
179 ];
180
181 struct User;
182
183 impl RelationTrait for User {
184 fn def(&self) -> &'static RelationDef {
185 &TEST_RELATIONS[0]
186 }
187 fn all_relations() -> &'static [RelationDef] {
188 TEST_RELATIONS
189 }
190 }
191
192 #[test]
193 fn test_relation_kind_default_join_type() {
194 assert_eq!(RelationKind::HasOne.default_join_type(), JoinKind::Inner);
195 assert_eq!(RelationKind::BelongsTo.default_join_type(), JoinKind::Inner);
196 assert_eq!(RelationKind::HasMany.default_join_type(), JoinKind::Left);
197 assert_eq!(RelationKind::ManyToMany.default_join_type(), JoinKind::Left);
198 }
199
200 #[test]
201 fn test_join_kind_as_sql() {
202 assert_eq!(JoinKind::Inner.as_sql(), "INNER JOIN");
203 assert_eq!(JoinKind::Left.as_sql(), "LEFT JOIN");
204 }
205
206 #[test]
207 fn test_relation_def_new() {
208 let def = RelationDef::new(
209 "orders",
210 "users",
211 "orders",
212 "id",
213 "user_id",
214 RelationKind::HasMany,
215 );
216 assert_eq!(def.name, "orders");
217 assert_eq!(def.from_entity, "users");
218 assert_eq!(def.to_entity, "orders");
219 assert_eq!(def.from_key, "id");
220 assert_eq!(def.to_key, "user_id");
221 assert_eq!(def.kind, RelationKind::HasMany);
222 }
223
224 #[test]
225 fn test_relation_trait_all_relations() {
226 let relations = User::all_relations();
227 assert_eq!(relations.len(), 4);
228 assert_eq!(relations[0].name, "orders");
229 assert_eq!(relations[1].name, "profile");
230 assert_eq!(relations[2].name, "owner");
231 assert_eq!(relations[3].name, "roles");
232 }
233
234 #[test]
235 fn test_relation_trait_relation_by_name() {
236 let found = User::relation_by_name("orders");
237 assert!(found.is_some());
238 assert_eq!(found.unwrap().to_entity, "orders");
239 assert_eq!(found.unwrap().kind, RelationKind::HasMany);
240
241 let not_found = User::relation_by_name("unknown");
242 assert!(not_found.is_none());
243 }
244
245 #[test]
246 fn test_relation_trait_def() {
247 let user = User;
248 let def = user.def();
249 assert_eq!(def.name, "orders");
250 assert_eq!(def.kind, RelationKind::HasMany);
251 }
252}