Skip to main content

sea_orm/entity/
primary_key.rs

1use super::{ColumnTrait, IdenStatic, Iterable};
2use crate::{TryFromU64, TryGetableMany};
3use sea_query::{FromValueTuple, IntoValueTuple};
4use std::fmt::Debug;
5
6/// Describes the primary key of an entity: which column variants make it
7/// up, the Rust value type (a tuple for composite keys), and whether the
8/// database auto-generates it.
9///
10/// Usually generated by `#[derive(DerivePrimaryKey)]` or implied by the
11/// `#[sea_orm(primary_key)]` attribute on `Model` fields. Manual impls look
12/// like:
13///
14/// ```ignore
15/// use sea_orm::entity::prelude::*;
16///
17/// #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
18/// pub enum PrimaryKey {
19///     Id,
20/// }
21///
22/// impl PrimaryKeyTrait for PrimaryKey {
23///     type ValueType = i32;
24///     fn auto_increment() -> bool { true }
25/// }
26/// ```
27pub trait PrimaryKeyTrait: IdenStatic + Iterable {
28    /// Rust type of the primary-key value. A single column is its own type
29    /// (e.g. `i32`); composite keys use a tuple (e.g. `(i32, String)`).
30    type ValueType: Sized
31        + Send
32        + Debug
33        + PartialEq
34        + IntoValueTuple
35        + FromValueTuple
36        + TryGetableMany
37        + TryFromU64
38        + PrimaryKeyArity;
39
40    /// `true` if the database generates the primary key (e.g. `SERIAL` /
41    /// `IDENTITY` / `AUTOINCREMENT`). Auto-increment keys can be left as
42    /// `NotSet` on insert.
43    fn auto_increment() -> bool;
44}
45
46/// Conversion between an entity's `PrimaryKey` enum and its `Column` enum.
47/// Generated alongside [`PrimaryKeyTrait`] for every entity.
48pub trait PrimaryKeyToColumn {
49    /// The entity's column enum (i.e. `<Self::Entity as EntityTrait>::Column`).
50    type Column: ColumnTrait;
51
52    /// Convert a primary-key variant into the matching column.
53    fn into_column(self) -> Self::Column;
54
55    /// Reverse of [`into_column`](Self::into_column). Returns `None` if
56    /// `col` is not part of the primary key.
57    fn from_column(col: Self::Column) -> Option<Self>
58    where
59        Self: Sized;
60}
61
62/// Number of columns a primary key spans — 1 for a single-column key,
63/// `n` for a composite key represented as an `n`-tuple.
64pub trait PrimaryKeyArity {
65    /// Number of columns in the primary key.
66    const ARITY: usize;
67}
68
69impl<V> PrimaryKeyArity for V
70where
71    V: crate::TryGetable,
72{
73    const ARITY: usize = 1;
74}
75
76macro_rules! impl_pk_arity {
77    ($len:expr, $($tuple_arg:ident),*) => {
78        impl<$($tuple_arg: crate::TryGetableMany,)*> PrimaryKeyArity for ($($tuple_arg,)*) {
79            const ARITY: usize = $len;
80        }
81    }
82}
83
84impl_pk_arity!(1, T1);
85impl_pk_arity!(2, T1, T2);
86impl_pk_arity!(3, T1, T2, T3);
87impl_pk_arity!(4, T1, T2, T3, T4);
88impl_pk_arity!(5, T1, T2, T3, T4, T5);
89impl_pk_arity!(6, T1, T2, T3, T4, T5, T6);
90impl_pk_arity!(7, T1, T2, T3, T4, T5, T6, T7);
91impl_pk_arity!(8, T1, T2, T3, T4, T5, T6, T7, T8);
92impl_pk_arity!(9, T1, T2, T3, T4, T5, T6, T7, T8, T9);
93impl_pk_arity!(10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
94impl_pk_arity!(11, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
95impl_pk_arity!(12, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
96
97#[cfg(test)]
98mod tests {
99    use crate::{EntityTrait, Identity};
100
101    #[test]
102    #[cfg(feature = "macros")]
103    fn test_composite_primary_key() {
104        mod primary_key_of_1 {
105            use crate as sea_orm;
106            use crate::entity::prelude::*;
107
108            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
109            #[sea_orm(table_name = "primary_key_of_1")]
110            pub struct Model {
111                #[sea_orm(primary_key)]
112                pub id: i32,
113                pub owner: String,
114                pub name: String,
115                pub description: String,
116            }
117
118            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
119            pub enum Relation {}
120
121            impl ActiveModelBehavior for ActiveModel {}
122        }
123
124        mod primary_key_of_2 {
125            use crate as sea_orm;
126            use crate::entity::prelude::*;
127
128            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
129            #[sea_orm(table_name = "primary_key_of_2")]
130            pub struct Model {
131                #[sea_orm(primary_key, auto_increment = false)]
132                pub id_1: i32,
133                #[sea_orm(primary_key, auto_increment = false)]
134                pub id_2: String,
135                pub owner: String,
136                pub name: String,
137                pub description: String,
138            }
139
140            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
141            pub enum Relation {}
142
143            impl ActiveModelBehavior for ActiveModel {}
144        }
145
146        mod primary_key_of_3 {
147            use crate as sea_orm;
148            use crate::entity::prelude::*;
149
150            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
151            #[sea_orm(table_name = "primary_key_of_3")]
152            pub struct Model {
153                #[sea_orm(primary_key, auto_increment = false)]
154                pub id_1: i32,
155                #[sea_orm(primary_key, auto_increment = false)]
156                pub id_2: String,
157                #[sea_orm(primary_key, auto_increment = false)]
158                pub id_3: Uuid,
159                pub owner: String,
160                pub name: String,
161                pub description: String,
162            }
163
164            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
165            pub enum Relation {}
166
167            impl ActiveModelBehavior for ActiveModel {}
168        }
169
170        mod primary_key_of_4 {
171            use crate as sea_orm;
172            use crate::entity::prelude::*;
173
174            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
175            #[sea_orm(table_name = "primary_key_of_4")]
176            pub struct Model {
177                #[sea_orm(primary_key, auto_increment = false)]
178                pub id_1: TimeDateTimeWithTimeZone,
179                #[sea_orm(primary_key, auto_increment = false)]
180                pub id_2: Uuid,
181                #[sea_orm(primary_key, auto_increment = false)]
182                pub id_3: Json,
183                #[sea_orm(primary_key, auto_increment = false)]
184                pub id_4: Decimal,
185                pub owner: String,
186                pub name: String,
187                pub description: String,
188            }
189
190            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
191            pub enum Relation {}
192
193            impl ActiveModelBehavior for ActiveModel {}
194        }
195
196        mod primary_key_of_11 {
197            use crate as sea_orm;
198            use crate::entity::prelude::*;
199
200            #[derive(Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
201            #[sea_orm(
202                rs_type = "String",
203                db_type = "String(StringLen::N(1))",
204                enum_name = "category"
205            )]
206            pub enum DeriveCategory {
207                #[sea_orm(string_value = "B")]
208                Big,
209                #[sea_orm(string_value = "S")]
210                Small,
211            }
212
213            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
214            #[sea_orm(table_name = "primary_key_of_11")]
215            pub struct Model {
216                #[sea_orm(primary_key, auto_increment = false)]
217                pub id_1: Vec<u8>,
218                #[sea_orm(primary_key, auto_increment = false)]
219                pub id_2: DeriveCategory,
220                #[sea_orm(primary_key, auto_increment = false)]
221                pub id_3: Date,
222                #[sea_orm(primary_key, auto_increment = false)]
223                pub id_4: DateTime,
224                #[sea_orm(primary_key, auto_increment = false)]
225                pub id_5: Time,
226                #[sea_orm(primary_key, auto_increment = false)]
227                pub id_6: TimeTime,
228                #[sea_orm(primary_key, auto_increment = false)]
229                pub id_7: DateTime,
230                #[sea_orm(primary_key, auto_increment = false)]
231                pub id_8: TimeDateTime,
232                #[sea_orm(primary_key, auto_increment = false)]
233                pub id_9: DateTimeLocal,
234                #[sea_orm(primary_key, auto_increment = false)]
235                pub id_10: DateTimeUtc,
236                #[sea_orm(primary_key, auto_increment = false)]
237                pub id_11: DateTimeWithTimeZone,
238                pub owner: String,
239                pub name: String,
240                pub description: String,
241            }
242
243            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
244            pub enum Relation {}
245
246            impl ActiveModelBehavior for ActiveModel {}
247        }
248
249        mod primary_key_of_12 {
250            use crate as sea_orm;
251            use crate::entity::prelude::*;
252
253            #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
254            #[sea_orm(table_name = "primary_key_of_12")]
255            pub struct Model {
256                #[sea_orm(primary_key, auto_increment = false)]
257                pub id_1: String,
258                #[sea_orm(primary_key, auto_increment = false)]
259                pub id_2: i8,
260                #[sea_orm(primary_key, auto_increment = false)]
261                pub id_3: u8,
262                #[sea_orm(primary_key, auto_increment = false)]
263                pub id_4: i16,
264                #[sea_orm(primary_key, auto_increment = false)]
265                pub id_5: u16,
266                #[sea_orm(primary_key, auto_increment = false)]
267                pub id_6: i32,
268                #[sea_orm(primary_key, auto_increment = false)]
269                pub id_7: u32,
270                #[sea_orm(primary_key, auto_increment = false)]
271                pub id_8: i64,
272                #[sea_orm(primary_key, auto_increment = false)]
273                pub id_9: u64,
274                #[sea_orm(primary_key, auto_increment = false)]
275                pub id_10: f32,
276                #[sea_orm(primary_key, auto_increment = false)]
277                pub id_11: f64,
278                #[sea_orm(primary_key, auto_increment = false)]
279                pub id_12: bool,
280                pub owner: String,
281                pub name: String,
282                pub description: String,
283            }
284
285            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
286            pub enum Relation {}
287
288            impl ActiveModelBehavior for ActiveModel {}
289        }
290
291        assert_eq!(
292            primary_key_of_3::Entity::primary_key_identity(),
293            Identity::Ternary("id_1".into(), "id_2".into(), "id_3".into())
294        );
295    }
296}