sea_orm/entity/
identity.rs

1use crate::{ColumnTrait, EntityTrait, IdenStatic};
2use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
3use std::{borrow::Cow, fmt::Write};
4
5/// List of column identifier
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub enum Identity {
8    /// Column identifier consists of 1 column
9    Unary(DynIden),
10    /// Column identifier consists of 2 columns
11    Binary(DynIden, DynIden),
12    /// Column identifier consists of 3 columns
13    Ternary(DynIden, DynIden, DynIden),
14    /// Column identifier consists of more than 3 columns
15    Many(Vec<DynIden>),
16}
17
18impl Identity {
19    /// Get arity for this value
20    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    /// Iterate components of Identity
30    pub fn iter(&self) -> BorrowedIdentityIter<'_> {
31        BorrowedIdentityIter {
32            identity: self,
33            index: 0,
34        }
35    }
36
37    /// Check if this identity contains a component column
38    pub fn contains(&self, col: &DynIden) -> bool {
39        self.iter().any(|c| c == col)
40    }
41
42    /// Check if this identity is a superset of another identity
43    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/// Iterator for [`Identity`]
94#[derive(Debug)]
95pub struct BorrowedIdentityIter<'a> {
96    identity: &'a Identity,
97    index: usize,
98}
99
100/// Iterator for [`Identity`]
101#[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
167/// Performs a conversion into an [Identity]
168pub trait IntoIdentity {
169    /// Method to perform the conversion
170    fn into_identity(self) -> Identity;
171}
172
173/// Check the [Identity] of an Entity
174pub trait IdentityOf<E>
175where
176    E: EntityTrait,
177{
178    /// Method to call to perform this check
179    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}