Skip to main content

rainier_orm/
column.rs

1//! Column metadata + the `SqlType` mapping from a Rust type to a column
2//! SQL type. Adding a new supported field type is a single `SqlType` impl.
3
4/// The SQL column type, dialect-independent. Rendered per-dialect in
5/// [`crate::schema`].
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum ColumnType {
8    Bool,
9    Int,
10    BigInt,
11    Uint,
12    BigUint,
13    Double,
14    Text,
15    Binary,
16    Timestamp,
17    Date,
18}
19
20/// One column's metadata, produced by `#[derive(Entity)]` as a `const`.
21#[derive(Debug, Clone, Copy)]
22pub struct ColumnSpec {
23    pub name: &'static str,
24    pub ty: ColumnType,
25    pub nullable: bool,
26    pub pk: bool,
27    pub auto_increment: bool,
28    /// A single-column `UNIQUE` constraint, rendered inline on the column.
29    /// Composite uniqueness is an [`IndexSpec`] with `unique = true` instead.
30    pub unique: bool,
31}
32
33/// A secondary index over one or more columns, produced as a separate
34/// `CREATE [UNIQUE] INDEX`. Single-column indexes come from `#[orm(index)]`
35/// on a field; composite ones from `#[orm(index = "a, b")]` /
36/// `#[orm(unique = "a, b")]` on the struct.
37#[derive(Debug, Clone, Copy)]
38pub struct IndexSpec {
39    pub name: &'static str,
40    pub columns: &'static [&'static str],
41    pub unique: bool,
42}
43
44/// A foreign-key constraint. The local columns reference
45/// `foreign_table(foreign_columns)`. Generated from
46/// `#[orm(references = "table(col)")]` on a field.
47///
48/// This is a *constraint* (database-enforced referential integrity within one
49/// database), not an ORM relationship: there is no lazy/eager navigation
50/// attached to it. See the crate docs on why relationships stay explicit.
51#[derive(Debug, Clone, Copy)]
52pub struct ForeignKeySpec {
53    pub name: &'static str,
54    pub columns: &'static [&'static str],
55    pub foreign_table: &'static str,
56    pub foreign_columns: &'static [&'static str],
57    pub on_delete: Option<RefAction>,
58    pub on_update: Option<RefAction>,
59}
60
61/// The referential action for a foreign key's `ON DELETE` / `ON UPDATE`.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum RefAction {
64    Cascade,
65    Restrict,
66    SetNull,
67    SetDefault,
68    NoAction,
69}
70
71/// Maps a Rust field type to its column type. The derive reads
72/// `<FieldType as SqlType>::{COLUMN_TYPE, NULLABLE}`, so `Option<T>` becomes
73/// a nullable `T` automatically and new types need only this impl.
74pub trait SqlType {
75    const COLUMN_TYPE: ColumnType;
76    const NULLABLE: bool = false;
77}
78
79macro_rules! sql_type {
80    ($t:ty, $ct:expr) => {
81        impl SqlType for $t {
82            const COLUMN_TYPE: ColumnType = $ct;
83        }
84    };
85}
86
87sql_type!(bool, ColumnType::Bool);
88sql_type!(i32, ColumnType::Int);
89sql_type!(i64, ColumnType::BigInt);
90sql_type!(u32, ColumnType::Uint);
91sql_type!(u64, ColumnType::BigUint);
92sql_type!(f64, ColumnType::Double);
93sql_type!(String, ColumnType::Text);
94sql_type!(Vec<u8>, ColumnType::Binary);
95sql_type!(chrono::DateTime<chrono::Utc>, ColumnType::Timestamp);
96sql_type!(chrono::NaiveDate, ColumnType::Date);
97
98impl<T: SqlType> SqlType for Option<T> {
99    const COLUMN_TYPE: ColumnType = T::COLUMN_TYPE;
100    const NULLABLE: bool = true;
101}