1use crate::{ColumnTrait, EntityTrait, IdenStatic};
2use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
3use std::{borrow::Cow, fmt::Write};
4
5#[derive(Debug, Clone)]
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(crate) fn iter(&self) -> Iter<'_> {
30 Iter {
31 identity: self,
32 index: 0,
33 }
34 }
35}
36
37impl IntoIterator for Identity {
38 type Item = DynIden;
39 type IntoIter = std::vec::IntoIter<Self::Item>;
40
41 fn into_iter(self) -> Self::IntoIter {
42 match self {
43 Identity::Unary(ident1) => vec![ident1].into_iter(),
44 Identity::Binary(ident1, ident2) => vec![ident1, ident2].into_iter(),
45 Identity::Ternary(ident1, ident2, ident3) => vec![ident1, ident2, ident3].into_iter(),
46 Identity::Many(vec) => vec.into_iter(),
47 }
48 }
49}
50
51impl Iden for Identity {
52 fn quoted(&self) -> Cow<'static, str> {
53 match self {
54 Identity::Unary(iden) => iden.inner(),
55 Identity::Binary(iden1, iden2) => Cow::Owned(format!("{iden1}{iden2}")),
56 Identity::Ternary(iden1, iden2, iden3) => Cow::Owned(format!("{iden1}{iden2}{iden3}")),
57 Identity::Many(vec) => {
58 let mut s = String::new();
59 for iden in vec.iter() {
60 write!(&mut s, "{iden}").expect("Infallible");
61 }
62 Cow::Owned(s)
63 }
64 }
65 }
66
67 fn to_string(&self) -> String {
68 match self.quoted() {
69 Cow::Borrowed(s) => s.to_owned(),
70 Cow::Owned(s) => s,
71 }
72 }
73
74 fn unquoted(&self) -> &str {
75 panic!("Should not call this")
76 }
77}
78
79pub(crate) struct Iter<'a> {
80 identity: &'a Identity,
81 index: usize,
82}
83
84impl<'a> Iterator for Iter<'a> {
85 type Item = &'a DynIden;
86
87 fn next(&mut self) -> Option<Self::Item> {
88 let result = match self.identity {
89 Identity::Unary(iden1) => {
90 if self.index == 0 {
91 Some(iden1)
92 } else {
93 None
94 }
95 }
96 Identity::Binary(iden1, iden2) => match self.index {
97 0 => Some(iden1),
98 1 => Some(iden2),
99 _ => None,
100 },
101 Identity::Ternary(iden1, iden2, iden3) => match self.index {
102 0 => Some(iden1),
103 1 => Some(iden2),
104 2 => Some(iden3),
105 _ => None,
106 },
107 Identity::Many(vec) => vec.get(self.index),
108 };
109 self.index += 1;
110 result
111 }
112}
113
114pub trait IntoIdentity {
116 fn into_identity(self) -> Identity;
118}
119
120pub trait IdentityOf<E>
122where
123 E: EntityTrait,
124{
125 fn identity_of(self) -> Identity;
127}
128
129impl IntoIdentity for Identity {
130 fn into_identity(self) -> Identity {
131 self
132 }
133}
134
135impl IntoIdentity for String {
136 fn into_identity(self) -> Identity {
137 self.as_str().into_identity()
138 }
139}
140
141impl IntoIdentity for &str {
142 fn into_identity(self) -> Identity {
143 Identity::Unary(SeaRc::new(Alias::new(self)))
144 }
145}
146
147impl<T> IntoIdentity for T
148where
149 T: IdenStatic,
150{
151 fn into_identity(self) -> Identity {
152 Identity::Unary(self.into_iden())
153 }
154}
155
156impl<T, C> IntoIdentity for (T, C)
157where
158 T: IdenStatic,
159 C: IdenStatic,
160{
161 fn into_identity(self) -> Identity {
162 Identity::Binary(self.0.into_iden(), self.1.into_iden())
163 }
164}
165
166impl<T, C, R> IntoIdentity for (T, C, R)
167where
168 T: IdenStatic,
169 C: IdenStatic,
170 R: IdenStatic,
171{
172 fn into_identity(self) -> Identity {
173 Identity::Ternary(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
174 }
175}
176
177macro_rules! impl_into_identity {
178 ( $($T:ident : $N:tt),+ $(,)? ) => {
179 impl< $($T),+ > IntoIdentity for ( $($T),+ )
180 where
181 $($T: IdenStatic),+
182 {
183 fn into_identity(self) -> Identity {
184 Identity::Many(vec![
185 $(self.$N.into_iden()),+
186 ])
187 }
188 }
189 };
190}
191
192#[rustfmt::skip]
193mod impl_into_identity {
194 use super::*;
195
196 impl_into_identity!(T0:0, T1:1, T2:2, T3:3);
197 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4);
198 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
199 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
200 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
201 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
202 impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
203 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);
204 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);
205}
206
207impl<E, C> IdentityOf<E> for C
208where
209 E: EntityTrait<Column = C>,
210 C: ColumnTrait,
211{
212 fn identity_of(self) -> Identity {
213 self.into_identity()
214 }
215}
216
217macro_rules! impl_identity_of {
218 ( $($T:ident),+ $(,)? ) => {
219 impl<E, C> IdentityOf<E> for ( $($T),+ )
220 where
221 E: EntityTrait<Column = C>,
222 C: ColumnTrait,
223 {
224 fn identity_of(self) -> Identity {
225 self.into_identity()
226 }
227 }
228 };
229}
230
231#[rustfmt::skip]
232mod impl_identity_of {
233 use super::*;
234
235 impl_identity_of!(C, C);
236 impl_identity_of!(C, C, C);
237 impl_identity_of!(C, C, C, C);
238 impl_identity_of!(C, C, C, C, C);
239 impl_identity_of!(C, C, C, C, C, C);
240 impl_identity_of!(C, C, C, C, C, C, C);
241 impl_identity_of!(C, C, C, C, C, C, C, C);
242 impl_identity_of!(C, C, C, C, C, C, C, C, C);
243 impl_identity_of!(C, C, C, C, C, C, C, C, C, C);
244 impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C);
245 impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C, C);
246}