1use crate::{ColumnTrait, EntityTrait, IdenStatic};
2use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
3use std::{borrow::Cow, fmt::Write};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub enum Identity {
8 Unary(DynIden),
10 Binary(DynIden, DynIden),
12 Ternary(DynIden, DynIden, DynIden),
14 Many(Vec<DynIden>),
16}
17
18impl Identity {
19 pub fn arity(&self) -> usize {
21 match self {
22 Self::Unary(_) => 1,
23 Self::Binary(_, _) => 2,
24 Self::Ternary(_, _, _) => 3,
25 Self::Many(vec) => vec.len(),
26 }
27 }
28
29 pub fn iter(&self) -> BorrowedIdentityIter<'_> {
31 BorrowedIdentityIter {
32 identity: self,
33 index: 0,
34 }
35 }
36
37 pub fn contains(&self, col: &DynIden) -> bool {
39 self.iter().any(|c| c == col)
40 }
41
42 pub fn fully_contains(&self, other: &Identity) -> bool {
44 for col in other.iter() {
45 if !self.contains(col) {
46 return false;
47 }
48 }
49 true
50 }
51}
52
53impl IntoIterator for Identity {
54 type Item = DynIden;
55 type IntoIter = OwnedIdentityIter;
56
57 fn into_iter(self) -> Self::IntoIter {
58 OwnedIdentityIter {
59 identity: self,
60 index: 0,
61 }
62 }
63}
64
65impl Iden for Identity {
66 fn quoted(&self) -> Cow<'static, str> {
67 match self {
68 Identity::Unary(iden) => iden.inner(),
69 Identity::Binary(iden1, iden2) => Cow::Owned(format!("{iden1}{iden2}")),
70 Identity::Ternary(iden1, iden2, iden3) => Cow::Owned(format!("{iden1}{iden2}{iden3}")),
71 Identity::Many(vec) => {
72 let mut s = String::new();
73 for iden in vec.iter() {
74 write!(&mut s, "{iden}").expect("Infallible");
75 }
76 Cow::Owned(s)
77 }
78 }
79 }
80
81 fn to_string(&self) -> String {
82 match self.quoted() {
83 Cow::Borrowed(s) => s.to_owned(),
84 Cow::Owned(s) => s,
85 }
86 }
87
88 fn unquoted(&self) -> &str {
89 panic!("Should not call this")
90 }
91}
92
93#[derive(Debug)]
95pub struct BorrowedIdentityIter<'a> {
96 identity: &'a Identity,
97 index: usize,
98}
99
100#[derive(Debug)]
102pub struct OwnedIdentityIter {
103 identity: Identity,
104 index: usize,
105}
106
107impl<'a> Iterator for BorrowedIdentityIter<'a> {
108 type Item = &'a DynIden;
109
110 fn next(&mut self) -> Option<Self::Item> {
111 let result = match self.identity {
112 Identity::Unary(iden1) => {
113 if self.index == 0 {
114 Some(iden1)
115 } else {
116 None
117 }
118 }
119 Identity::Binary(iden1, iden2) => match self.index {
120 0 => Some(iden1),
121 1 => Some(iden2),
122 _ => None,
123 },
124 Identity::Ternary(iden1, iden2, iden3) => match self.index {
125 0 => Some(iden1),
126 1 => Some(iden2),
127 2 => Some(iden3),
128 _ => None,
129 },
130 Identity::Many(vec) => vec.get(self.index),
131 };
132 self.index += 1;
133 result
134 }
135}
136
137impl Iterator for OwnedIdentityIter {
138 type Item = DynIden;
139
140 fn next(&mut self) -> Option<Self::Item> {
141 let result = match &self.identity {
142 Identity::Unary(iden1) => {
143 if self.index == 0 {
144 Some(iden1.clone())
145 } else {
146 None
147 }
148 }
149 Identity::Binary(iden1, iden2) => match self.index {
150 0 => Some(iden1.clone()),
151 1 => Some(iden2.clone()),
152 _ => None,
153 },
154 Identity::Ternary(iden1, iden2, iden3) => match self.index {
155 0 => Some(iden1.clone()),
156 1 => Some(iden2.clone()),
157 2 => Some(iden3.clone()),
158 _ => None,
159 },
160 Identity::Many(vec) => vec.get(self.index).cloned(),
161 };
162 self.index += 1;
163 result
164 }
165}
166
167pub trait IntoIdentity {
169 fn into_identity(self) -> Identity;
171}
172
173pub trait IdentityOf<E>
175where
176 E: EntityTrait,
177{
178 fn identity_of(self) -> Identity;
180}
181
182impl IntoIdentity for Identity {
183 fn into_identity(self) -> Identity {
184 self
185 }
186}
187
188impl IntoIdentity for String {
189 fn into_identity(self) -> Identity {
190 self.as_str().into_identity()
191 }
192}
193
194impl IntoIdentity for &str {
195 fn into_identity(self) -> Identity {
196 Identity::Unary(SeaRc::new(Alias::new(self)))
197 }
198}
199
200impl<T> IntoIdentity for T
201where
202 T: IdenStatic,
203{
204 fn into_identity(self) -> Identity {
205 Identity::Unary(self.into_iden())
206 }
207}
208
209impl<T, C> IntoIdentity for (T, C)
210where
211 T: IdenStatic,
212 C: IdenStatic,
213{
214 fn into_identity(self) -> Identity {
215 Identity::Binary(self.0.into_iden(), self.1.into_iden())
216 }
217}
218
219impl<T, C, R> IntoIdentity for (T, C, R)
220where
221 T: IdenStatic,
222 C: IdenStatic,
223 R: IdenStatic,
224{
225 fn into_identity(self) -> Identity {
226 Identity::Ternary(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
227 }
228}
229
230macro_rules! impl_into_identity {
231 ( $($T:ident : $N:tt),+ $(,)? ) => {
232 impl< $($T),+ > IntoIdentity for ( $($T),+ )
233 where
234 $($T: IdenStatic),+
235 {
236 fn into_identity(self) -> Identity {
237 Identity::Many(vec![
238 $(self.$N.into_iden()),+
239 ])
240 }
241 }
242 };
243}
244
245#[rustfmt::skip]
246mod impl_into_identity {
247 use super::*;
248
249 impl_into_identity!(T0:0, T1:1, T2:2, T3:3);
250 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4);
251 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
252 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
253 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
254 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
255 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
256 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
257 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
258}
259
260impl<E, C> IdentityOf<E> for C
261where
262 E: EntityTrait<Column = C>,
263 C: ColumnTrait,
264{
265 fn identity_of(self) -> Identity {
266 self.into_identity()
267 }
268}
269
270macro_rules! impl_identity_of {
271 ( $($T:ident),+ $(,)? ) => {
272 impl<E, C> IdentityOf<E> for ( $($T),+ )
273 where
274 E: EntityTrait<Column = C>,
275 C: ColumnTrait,
276 {
277 fn identity_of(self) -> Identity {
278 self.into_identity()
279 }
280 }
281 };
282}
283
284#[rustfmt::skip]
285mod impl_identity_of {
286 use super::*;
287
288 impl_identity_of!(C, C);
289 impl_identity_of!(C, C, C);
290 impl_identity_of!(C, C, C, C);
291 impl_identity_of!(C, C, C, C, C);
292 impl_identity_of!(C, C, C, C, C, C);
293 impl_identity_of!(C, C, C, C, C, C, C);
294 impl_identity_of!(C, C, C, C, C, C, C, C);
295 impl_identity_of!(C, C, C, C, C, C, C, C, C);
296 impl_identity_of!(C, C, C, C, C, C, C, C, C, C);
297 impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C);
298 impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C, C);
299}
300
301#[cfg(test)]
302mod test {
303 use super::*;
304
305 #[test]
306 fn test_identity_contains() {
307 let abc = Identity::Ternary("a".into(), "b".into(), "c".into());
308 let a = Identity::Unary("a".into());
309 let ab = Identity::Binary("a".into(), "b".into());
310 let bc = Identity::Binary("b".into(), "c".into());
311 let d = Identity::Unary("d".into());
312 let bcd = Identity::Ternary("b".into(), "c".into(), "d".into());
313
314 assert!(abc.contains(&"a".into()));
315 assert!(abc.contains(&"b".into()));
316 assert!(abc.contains(&"c".into()));
317 assert!(!abc.contains(&"d".into()));
318
319 assert!(abc.fully_contains(&a));
320 assert!(abc.fully_contains(&ab));
321 assert!(abc.fully_contains(&bc));
322 assert!(!abc.fully_contains(&d));
323 assert!(!abc.fully_contains(&bcd));
324 }
325}