atmosphere_core/schema/
mod.rs

1//! SQL Schema
2//!
3//! This module provides the foundational building blocks for defining the structure and
4//! relationships of SQL tables in atmosphere. It includes traits and types that describe table
5//! structures, column details, and primary and foreign key relationships. This is essential
6//! for representing and manipulating database schema in a type-safe and Rust-idiomatic way.
7
8use sqlx::{Database, Encode, FromRow, Type};
9
10mod create;
11mod delete;
12mod read;
13mod update;
14
15pub use create::Create;
16pub use delete::Delete;
17pub use read::Read;
18pub use update::Update;
19
20pub use self::column::{Column, DataColumn, ForeignKey, PrimaryKey, TimestampColumn};
21
22/// SQL Table Definition
23///
24/// Represents the definition of a SQL table within the framework, encompassing primary keys,
25/// foreign keys, data columns, and timestamp columns. This trait should be implemented by structs
26/// that represent database tables, providing metadata and utility functions for table manipulation
27/// and query building.
28pub trait Table
29where
30    Self: Sized + Send + for<'r> FromRow<'r, <crate::Driver as Database>::Row> + 'static,
31    Self::PrimaryKey: for<'q> Encode<'q, crate::Driver> + Type<crate::Driver> + Send,
32{
33    /// The type of the primary key for the table.
34    type PrimaryKey: Sync + Sized + 'static;
35
36    /// The database schema in which the table resides.
37    const SCHEMA: &'static str;
38    /// The name of the table.
39    const TABLE: &'static str;
40
41    /// The primary key column of the table.
42    const PRIMARY_KEY: PrimaryKey<Self>;
43    /// An array of foreign key columns.
44    const FOREIGN_KEYS: &'static [ForeignKey<Self>];
45    /// An array of data columns.
46    const DATA_COLUMNS: &'static [DataColumn<Self>];
47    /// An array of timestamp columns.
48    const TIMESTAMP_COLUMNS: &'static [TimestampColumn<Self>];
49
50    /// Returns a reference to the primary key of the table instance.
51    fn pk(&self) -> &Self::PrimaryKey;
52}
53
54/// Trait representing an Entity that maps to a database table.
55///
56/// Entities are table representations that implement CRUD (Create, Read, Update, Delete)
57/// operations. This trait is automatically implemented for any type that satisfies the `Create`,
58/// `Read`, `Update`, and `Delete` trait requirements, tying together the core functionalities
59/// needed for database interaction in the framework.
60pub trait Entity: Create + Read + Update + Delete {}
61
62impl<E: Create + Read + Update + Delete> Entity for E {}
63
64/// Column types representing various aspects of table columns.
65///
66/// These types provide detailed descriptions of table columns, their roles, and their SQL
67/// representations. They are used to define the structure of a table and guide query construction
68/// and execution within the framework.
69pub mod column {
70    use crate::Table;
71    use std::marker::PhantomData;
72
73    /// An enum that encapsulates different column types of a table.
74    #[derive(Copy, Debug, PartialEq, Eq)]
75    pub enum Column<T: Table> {
76        /// A primary key
77        PrimaryKey(&'static PrimaryKey<T>),
78        /// A foreign key
79        ForeignKey(&'static ForeignKey<T>),
80        /// A data column
81        Data(&'static DataColumn<T>),
82        /// A timestamp column
83        Timestamp(&'static TimestampColumn<T>),
84    }
85
86    impl<T: Table> Clone for Column<T> {
87        fn clone(&self) -> Self {
88            match self {
89                Self::PrimaryKey(pk) => Self::PrimaryKey(*pk),
90                Self::ForeignKey(fk) => Self::ForeignKey(*fk),
91                Self::Data(data) => Self::Data(*data),
92                Self::Timestamp(ts) => Self::Timestamp(*ts),
93            }
94        }
95    }
96
97    impl<T: Table> Column<T> {
98        pub const fn field(&self) -> &'static str {
99            match self {
100                Self::PrimaryKey(pk) => pk.field,
101                Self::ForeignKey(fk) => fk.field,
102                Self::Data(data) => data.field,
103                Self::Timestamp(ts) => ts.field,
104            }
105        }
106
107        pub const fn sql(&self) -> &'static str {
108            match self {
109                Self::PrimaryKey(pk) => pk.sql,
110                Self::ForeignKey(fk) => fk.sql,
111                Self::Data(data) => data.sql,
112                Self::Timestamp(ts) => ts.sql,
113            }
114        }
115    }
116
117    /// Describes the primary key column of a table.
118    #[derive(Copy, Debug, PartialEq, Eq)]
119    pub struct PrimaryKey<T: Table> {
120        pub field: &'static str,
121        pub sql: &'static str,
122        table: PhantomData<T>,
123    }
124
125    impl<T: Table> PrimaryKey<T> {
126        pub const fn new(field: &'static str, sql: &'static str) -> Self {
127            Self {
128                field,
129                sql,
130                table: PhantomData,
131            }
132        }
133
134        pub const fn as_col(&'static self) -> Column<T> {
135            Column::PrimaryKey(self)
136        }
137    }
138
139    impl<T: Table> Clone for PrimaryKey<T> {
140        fn clone(&self) -> Self {
141            Self {
142                field: self.field,
143                sql: self.sql,
144                table: PhantomData,
145            }
146        }
147    }
148
149    /// Represents a foreign key column, establishing a relationship to another table.
150    #[derive(Copy, Debug, PartialEq, Eq)]
151    pub struct ForeignKey<T: Table> {
152        /// The rust field name of the model
153        pub field: &'static str,
154        /// The associated sql column name
155        pub sql: &'static str,
156        table: PhantomData<T>,
157    }
158
159    impl<T: Table> ForeignKey<T> {
160        pub const fn new(field: &'static str, sql: &'static str) -> Self {
161            Self {
162                field,
163                sql,
164                table: PhantomData,
165            }
166        }
167
168        pub const fn as_col(&'static self) -> Column<T> {
169            Column::ForeignKey(self)
170        }
171
172        /// # Safety
173        /// We do treat this foreign key as a column of another table. This is not smart to do - but
174        /// can become necessary when doing complex joins. This is memory safe as `Self<A>` and
175        /// `Self<B>` have the exact same memory layout, we do not store any data (A or B) but only
176        /// a `PhantomData` instance which is here transmuted.
177        pub const unsafe fn transmute<I: Table>(&'static self) -> &'static ForeignKey<I> {
178            unsafe { std::mem::transmute(self) }
179        }
180    }
181
182    impl<T: Table> Clone for ForeignKey<T> {
183        fn clone(&self) -> Self {
184            Self {
185                field: self.field,
186                sql: self.sql,
187                table: PhantomData,
188            }
189        }
190    }
191
192    /// Defines a standard data column in the table.
193    #[derive(Copy, Debug, PartialEq, Eq)]
194    pub struct DataColumn<T: Table> {
195        /// The rust field name of the model
196        pub field: &'static str,
197        /// The associated sql column name
198        pub sql: &'static str,
199        table: PhantomData<T>,
200    }
201
202    impl<T: Table> DataColumn<T> {
203        pub const fn new(field: &'static str, sql: &'static str) -> Self {
204            Self {
205                field,
206                sql,
207                table: PhantomData,
208            }
209        }
210
211        pub const fn as_col(&'static self) -> Column<T> {
212            Column::Data(self)
213        }
214    }
215
216    impl<T: Table> Clone for DataColumn<T> {
217        fn clone(&self) -> Self {
218            Self {
219                field: self.field,
220                sql: self.sql,
221                table: PhantomData,
222            }
223        }
224    }
225
226    /// The type of a timestamp column
227    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
228    pub enum TimestampKind {
229        Created,
230        Updated,
231        Deleted,
232    }
233
234    /// Specifies a timestamp column, typically used for tracking creation, update, or deletion times.
235    #[derive(Copy, Debug, PartialEq, Eq)]
236    pub struct TimestampColumn<T: Table> {
237        /// The type of this timestamp column
238        pub kind: TimestampKind,
239        /// The rust field name of the model
240        pub field: &'static str,
241        /// The associated sql column name
242        pub sql: &'static str,
243        table: PhantomData<T>,
244    }
245
246    impl<T: Table> TimestampColumn<T> {
247        pub const fn new(kind: TimestampKind, field: &'static str, sql: &'static str) -> Self {
248            Self {
249                kind,
250                field,
251                sql,
252                table: PhantomData,
253            }
254        }
255    }
256
257    impl<T: Table> Clone for TimestampColumn<T> {
258        fn clone(&self) -> Self {
259            Self {
260                kind: self.kind,
261                field: self.field,
262                sql: self.sql,
263                table: PhantomData,
264            }
265        }
266    }
267}