-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add SeaORM migrations and utils to create
user
table (#284)
It is pretty common that an application will need a `user` table in its DB. This PR adds a sensible default schema via SeaORM migrations, collected into a common `UserMigration` struct (that implements SeaORM's `MigratorTrait`). Also, add the migrations in the `full` example to demonstrate usage and what the generated entity structs look like.
- Loading branch information
1 parent
741c0ef
commit 50a17b2
Showing
19 changed files
with
450 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0-rc.7 | ||
pub mod prelude; | ||
|
||
pub mod user; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0-rc.7 | ||
pub use super::user::Entity as User; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0-rc.7 | ||
use sea_orm::entity::prelude::*; | ||
|
||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] | ||
#[sea_orm(table_name = "user")] | ||
pub struct Model { | ||
pub created_at: DateTimeWithTimeZone, | ||
pub updated_at: DateTimeWithTimeZone, | ||
#[sea_orm(primary_key, auto_increment = false)] | ||
pub id: Uuid, | ||
pub name: String, | ||
#[sea_orm(unique)] | ||
pub username: String, | ||
#[sea_orm(unique)] | ||
pub email: String, | ||
pub password: String, | ||
pub email_confirmation_sent_at: Option<DateTimeWithTimeZone>, | ||
pub email_confirmation_token: Option<String>, | ||
pub email_confirmed_at: Option<DateTimeWithTimeZone>, | ||
pub last_sign_in_at: Option<DateTimeWithTimeZone>, | ||
pub recovery_sent_at: Option<DateTimeWithTimeZone>, | ||
pub recovery_token: Option<String>, | ||
pub email_change_sent_at: Option<DateTimeWithTimeZone>, | ||
pub email_change_token_new: Option<String>, | ||
pub email_change_token_current: Option<String>, | ||
pub deleted_at: Option<DateTimeWithTimeZone>, | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] | ||
pub enum Relation {} | ||
|
||
impl ActiveModelBehavior for ActiveModel {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
//! Utility methods to add check constraints to columns. | ||
use sea_orm_migration::prelude::*; | ||
|
||
/// Expression to check that a string column value is not empty. | ||
pub fn str_not_empty<T>(name: T) -> SimpleExpr | ||
where | ||
T: IntoIden + 'static, | ||
{ | ||
str_len_gt(name, 0) | ||
} | ||
|
||
/// Expression to check that a string column value's length is greater than the provided value. | ||
pub fn str_len_gt<T>(name: T, len: u64) -> SimpleExpr | ||
where | ||
T: IntoIden + 'static, | ||
{ | ||
Expr::expr(Func::char_length(Expr::col(name))).gt(len) | ||
} | ||
|
||
/// Expression to check that a string column value's length is greater than or equal to the | ||
/// provided value. | ||
pub fn str_len_gte<T>(name: T, len: u64) -> SimpleExpr | ||
where | ||
T: IntoIden + 'static, | ||
{ | ||
Expr::expr(Func::char_length(Expr::col(name))).gte(len) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
//! This module provides pre-built SeaORM migrations for table schemas that are applicable | ||
//! across many different applications and problem spaces. | ||
//! | ||
//! Additionally, some utilities are provided to create some common column types. | ||
pub mod check; | ||
pub mod schema; | ||
pub mod user; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
//! Utility methods to create common column types in table create/alter statements. | ||
//! | ||
//! These utilities are similar to the ones provided by [SeaORM][sea_orm_migration::schema] and | ||
//! [Loco](https://github.com/loco-rs/loco/blob/be7ead6e2503731aea252ed8dc6542d74f2c2e4f/src/schema.rs), | ||
//! but with some minor differences. For example, our updated/created at timestamps include the | ||
//! timezone, while SeaORM/Loco do not. | ||
use sea_orm_migration::{prelude::*, schema::*}; | ||
|
||
/// Timestamp related fields. | ||
#[derive(DeriveIden)] | ||
#[non_exhaustive] | ||
pub enum Timetamps { | ||
/// When the row was created. When used with the [timestamps] method, will default to | ||
/// the current timestamp (with timezone). | ||
CreatedAt, | ||
/// When the row was updated. When used with the [timestamps] method, will be initially set to | ||
/// the current timestamp (with timezone). Updates to the row will need to provide this field | ||
/// as well in order for it to be updated. | ||
// Todo: does seaorm automatically update this? | ||
UpdatedAt, | ||
} | ||
|
||
/// Create a table if it does not exist yet and add some default columns | ||
/// (e.g., create/update timestamps). | ||
pub fn table<T: IntoIden + 'static>(name: T) -> TableCreateStatement { | ||
timestamps(Table::create().table(name).if_not_exists().to_owned()) | ||
} | ||
|
||
/// Add "timestamp with time zone" columns (`CreatedAt` and `UpdatedAt`) to a table. | ||
/// The default for each column is the current timestamp. | ||
pub fn timestamps(mut table: TableCreateStatement) -> TableCreateStatement { | ||
table | ||
.col(timestamp_with_time_zone(Timetamps::CreatedAt).default(Expr::current_timestamp())) | ||
.col(timestamp_with_time_zone(Timetamps::UpdatedAt).default(Expr::current_timestamp())) | ||
.to_owned() | ||
} | ||
|
||
/// Create an auto-incrementing primary key column using [BigInteger][sea_orm::sea_query::ColumnType::BigInteger] | ||
/// as the column type. | ||
pub fn pk_bigint_auto<T>(name: T) -> ColumnDef | ||
where | ||
T: IntoIden, | ||
{ | ||
big_integer(name).primary_key().auto_increment().to_owned() | ||
} | ||
|
||
/// Create a primary key column using [Uuid][sea_orm::sea_query::ColumnType::Uuid] as the column | ||
/// type. No default value is provided, so it needs to be generated/provided by the application. | ||
pub fn pk_uuid<T>(name: T) -> ColumnDef | ||
where | ||
T: IntoIden, | ||
{ | ||
ColumnDef::new(name).uuid().primary_key().to_owned() | ||
} | ||
|
||
/// Create a primary key column using [Uuid][sea_orm::sea_query::ColumnType::Uuid] as the column | ||
/// type. A new v4 UUID will be generated as the default if no value is provided by the application. | ||
/// | ||
/// Note: This requires that your database supports generating v4 UUIDs using a method named | ||
/// `uuid_generate_v4()`. | ||
pub fn pk_uuidv4<T>(name: T) -> ColumnDef | ||
where | ||
T: IntoIden, | ||
{ | ||
pk_uuid_default(name, Expr::cust("uuid_generate_v4()")) | ||
} | ||
|
||
/// Create a primary key column using [Uuid][sea_orm::sea_query::ColumnType::Uuid] as the column | ||
/// type. A new v7 UUID will be generated as the default if no value is provided by the application. | ||
/// | ||
/// Note: This requires that your database supports generating v7 UUIDs using a method named | ||
/// `uuid_generate_v7()`. | ||
pub fn pk_uuidv7<T>(name: T) -> ColumnDef | ||
where | ||
T: IntoIden, | ||
{ | ||
pk_uuid_default(name, Expr::cust("uuid_generate_v7()")) | ||
} | ||
|
||
/// Create a primary key column using [Uuid][sea_orm::sea_query::ColumnType::Uuid] as the column | ||
/// type. | ||
/// | ||
/// Provide a `default` expression in order to define how a default value is generated if no value | ||
/// is not provided by the application. | ||
pub fn pk_uuid_default<T, D>(name: T, default: D) -> ColumnDef | ||
where | ||
T: IntoIden, | ||
D: Into<SimpleExpr>, | ||
{ | ||
pk_uuid(name).default(default).to_owned() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use crate::migration::check::str_not_empty; | ||
use crate::migration::schema::{pk_bigint_auto, pk_uuid, table}; | ||
use crate::migration::user::User; | ||
use sea_orm_migration::{prelude::*, schema::*}; | ||
|
||
pub(crate) fn create_table_uuid_pk() -> TableCreateStatement { | ||
create_table(pk_uuid(User::Id)) | ||
} | ||
|
||
pub(crate) fn create_table_int_pk() -> TableCreateStatement { | ||
create_table(pk_bigint_auto(User::Id)) | ||
} | ||
|
||
pub(crate) fn create_table(pk_col: ColumnDef) -> TableCreateStatement { | ||
table(User::Table) | ||
.col(pk_col) | ||
.col(string(User::Name).check(str_not_empty(User::Name))) | ||
.col(string_uniq(User::Username).check(str_not_empty(User::Username))) | ||
.col(string_uniq(User::Email).check(str_not_empty(User::Email))) | ||
.col(string(User::Password)) | ||
.to_owned() | ||
} | ||
|
||
pub(crate) fn drop_table() -> TableDropStatement { | ||
Table::drop().table(User::Table).to_owned() | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use insta::assert_snapshot; | ||
use sea_orm::sea_query::PostgresQueryBuilder; | ||
|
||
#[test] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn create_table_uuid_pk() { | ||
let query = super::create_table_uuid_pk(); | ||
|
||
assert_snapshot!(query.to_string(PostgresQueryBuilder)); | ||
} | ||
|
||
#[test] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn create_table_int_pk() { | ||
let query = super::create_table_int_pk(); | ||
|
||
assert_snapshot!(query.to_string(PostgresQueryBuilder)); | ||
} | ||
|
||
#[test] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn drop_table() { | ||
let query = super::drop_table(); | ||
|
||
assert_snapshot!(query.to_string(PostgresQueryBuilder)); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/migration/user/m20240714_203550_create_user_table_int_pk.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Migrations to create a basic `user` table that contains the following fields: | ||
//! | ||
//! - Id (BIGINT) | ||
//! - Name | ||
//! - Username | ||
//! - Password | ||
//! | ||
//! To add more fields, use the other migrations in the `user` mod. | ||
use crate::migration::user::create_table::{create_table_int_pk, drop_table}; | ||
use sea_orm_migration::prelude::*; | ||
|
||
#[derive(Default, DeriveMigrationName)] | ||
#[non_exhaustive] | ||
pub struct Migration; | ||
|
||
#[async_trait::async_trait] | ||
impl MigrationTrait for Migration { | ||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager.create_table(create_table_int_pk()).await | ||
} | ||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager.drop_table(drop_table()).await | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/migration/user/m20240714_203551_create_user_table_uuid_pk.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Migrations to create a basic `user` table that contains the following fields: | ||
//! | ||
//! - Id (UUID) | ||
//! - Name | ||
//! - Username | ||
//! - Password | ||
//! | ||
//! To add more fields, use the other migrations in the `user` mod. | ||
use crate::migration::user::create_table::{create_table_uuid_pk, drop_table}; | ||
use sea_orm_migration::prelude::*; | ||
|
||
#[derive(Default, DeriveMigrationName)] | ||
#[non_exhaustive] | ||
pub struct Migration; | ||
|
||
#[async_trait::async_trait] | ||
impl MigrationTrait for Migration { | ||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager.create_table(create_table_uuid_pk()).await | ||
} | ||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager.drop_table(drop_table()).await | ||
} | ||
} |
Oops, something went wrong.