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