From 50a17b2d20df8869e718172f2278d28b41d5f5b8 Mon Sep 17 00:00:00 2001 From: Spencer Ferris <3319370+spencewenski@users.noreply.github.com> Date: Tue, 23 Jul 2024 01:48:18 -0700 Subject: [PATCH] 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. --- examples/full/entity/src/lib.rs | 4 + examples/full/entity/src/prelude.rs | 3 + examples/full/entity/src/user.rs | 33 +++++++ examples/full/migration/Cargo.toml | 1 + examples/full/migration/src/lib.rs | 9 +- src/lib.rs | 2 + src/migration/check.rs | 28 ++++++ src/migration/mod.rs | 8 ++ src/migration/schema.rs | 92 +++++++++++++++++++ src/migration/user/create_table.rs | 56 +++++++++++ ...0240714_203550_create_user_table_int_pk.rs | 27 ++++++ ...240714_203551_create_user_table_uuid_pk.rs | 27 ++++++ ...0533_add_user_account_management_fields.rs | 84 +++++++++++++++++ src/migration/user/mod.rs | 52 +++++++++++ ...ate_table__tests__create_table_int_pk.snap | 5 + ...te_table__tests__create_table_uuid_pk.snap | 5 + ...user__create_table__tests__drop_table.snap | 5 + ...ields__tests__alter_table_add_columns.snap | 5 + ...elds__tests__alter_table_drop_columns.snap | 5 + 19 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 examples/full/entity/src/prelude.rs create mode 100644 examples/full/entity/src/user.rs create mode 100644 src/migration/check.rs create mode 100644 src/migration/mod.rs create mode 100644 src/migration/schema.rs create mode 100644 src/migration/user/create_table.rs create mode 100644 src/migration/user/m20240714_203550_create_user_table_int_pk.rs create mode 100644 src/migration/user/m20240714_203551_create_user_table_uuid_pk.rs create mode 100644 src/migration/user/m20240723_070533_add_user_account_management_fields.rs create mode 100644 src/migration/user/mod.rs create mode 100644 src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_int_pk.snap create mode 100644 src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_uuid_pk.snap create mode 100644 src/migration/user/snapshots/roadster__migration__user__create_table__tests__drop_table.snap create mode 100644 src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_add_columns.snap create mode 100644 src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_drop_columns.snap diff --git a/examples/full/entity/src/lib.rs b/examples/full/entity/src/lib.rs index 8b137891..4a0e926d 100644 --- a/examples/full/entity/src/lib.rs +++ b/examples/full/entity/src/lib.rs @@ -1 +1,5 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0-rc.7 +pub mod prelude; + +pub mod user; diff --git a/examples/full/entity/src/prelude.rs b/examples/full/entity/src/prelude.rs new file mode 100644 index 00000000..61c6a2a1 --- /dev/null +++ b/examples/full/entity/src/prelude.rs @@ -0,0 +1,3 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0-rc.7 + +pub use super::user::Entity as User; diff --git a/examples/full/entity/src/user.rs b/examples/full/entity/src/user.rs new file mode 100644 index 00000000..4ace6c9b --- /dev/null +++ b/examples/full/entity/src/user.rs @@ -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, + pub email_confirmation_token: Option, + pub email_confirmed_at: Option, + pub last_sign_in_at: Option, + pub recovery_sent_at: Option, + pub recovery_token: Option, + pub email_change_sent_at: Option, + pub email_change_token_new: Option, + pub email_change_token_current: Option, + pub deleted_at: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/full/migration/Cargo.toml b/examples/full/migration/Cargo.toml index 242da68e..2f36378d 100644 --- a/examples/full/migration/Cargo.toml +++ b/examples/full/migration/Cargo.toml @@ -10,6 +10,7 @@ path = "src/lib.rs" [dependencies] tokio = { workspace = true } +roadster = { path = "../../..", default-features = false, features = ["db-sql"] } [dependencies.sea-orm-migration] version = "1.0.0-rc.5" diff --git a/examples/full/migration/src/lib.rs b/examples/full/migration/src/lib.rs index 2c605afb..8bcc9d2a 100644 --- a/examples/full/migration/src/lib.rs +++ b/examples/full/migration/src/lib.rs @@ -1,3 +1,4 @@ +use roadster::migration::user::UserMigrator; pub use sea_orm_migration::prelude::*; mod m20220101_000001_create_table; @@ -7,6 +8,12 @@ pub struct Migrator; #[async_trait::async_trait] impl MigratorTrait for Migrator { fn migrations() -> Vec> { - vec![Box::new(m20220101_000001_create_table::Migration)] + let migrations: Vec> = + vec![Box::new(m20220101_000001_create_table::Migration)]; + + migrations + .into_iter() + .chain(UserMigrator::migrations()) + .collect() } } diff --git a/src/lib.rs b/src/lib.rs index 77105fc2..b8699e73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,8 @@ pub mod config; pub mod error; pub mod health_check; pub mod middleware; +#[cfg(feature = "db-sql")] +pub mod migration; pub mod service; #[cfg(any(test, feature = "testing"))] pub mod testing; diff --git a/src/migration/check.rs b/src/migration/check.rs new file mode 100644 index 00000000..32610465 --- /dev/null +++ b/src/migration/check.rs @@ -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(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(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(name: T, len: u64) -> SimpleExpr +where + T: IntoIden + 'static, +{ + Expr::expr(Func::char_length(Expr::col(name))).gte(len) +} diff --git a/src/migration/mod.rs b/src/migration/mod.rs new file mode 100644 index 00000000..7318c08b --- /dev/null +++ b/src/migration/mod.rs @@ -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; diff --git a/src/migration/schema.rs b/src/migration/schema.rs new file mode 100644 index 00000000..f38788d5 --- /dev/null +++ b/src/migration/schema.rs @@ -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(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(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(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(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(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(name: T, default: D) -> ColumnDef +where + T: IntoIden, + D: Into, +{ + pk_uuid(name).default(default).to_owned() +} diff --git a/src/migration/user/create_table.rs b/src/migration/user/create_table.rs new file mode 100644 index 00000000..2c0b7b7d --- /dev/null +++ b/src/migration/user/create_table.rs @@ -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)); + } +} diff --git a/src/migration/user/m20240714_203550_create_user_table_int_pk.rs b/src/migration/user/m20240714_203550_create_user_table_int_pk.rs new file mode 100644 index 00000000..abfa7191 --- /dev/null +++ b/src/migration/user/m20240714_203550_create_user_table_int_pk.rs @@ -0,0 +1,27 @@ +//! Migrations to create a basic `user` table that contains the following fields: +//! +//! - Id (BIGINT) +//! - Name +//! - Username +//! - Email +//! - 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 + } +} diff --git a/src/migration/user/m20240714_203551_create_user_table_uuid_pk.rs b/src/migration/user/m20240714_203551_create_user_table_uuid_pk.rs new file mode 100644 index 00000000..1175d053 --- /dev/null +++ b/src/migration/user/m20240714_203551_create_user_table_uuid_pk.rs @@ -0,0 +1,27 @@ +//! Migrations to create a basic `user` table that contains the following fields: +//! +//! - Id (UUID) +//! - Name +//! - Username +//! - Email +//! - 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 + } +} diff --git a/src/migration/user/m20240723_070533_add_user_account_management_fields.rs b/src/migration/user/m20240723_070533_add_user_account_management_fields.rs new file mode 100644 index 00000000..cd4e6593 --- /dev/null +++ b/src/migration/user/m20240723_070533_add_user_account_management_fields.rs @@ -0,0 +1,84 @@ +//! Migrations to add some common account management fields to the `user` table. The following +//! fields are added: +//! +//! - EmailConfirmationSentAt +//! - EmailConfirmationToken +//! - EmailConfirmedAt +//! - LastSignInAt +//! - RecoverySentAt +//! - RecoveryToken +//! - EmailChangeSentAt +//! - EmailChangeTokenNew +//! - EmailChangeTokenCurrent +//! - DeletedAt + +use crate::migration::user::User; +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.alter_table(alter_table_add_columns()).await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.alter_table(alter_table_drop_columns()).await + } +} + +fn alter_table_add_columns() -> TableAlterStatement { + Table::alter() + .table(User::Table) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::EmailConfirmationSentAt)) + .add_column_if_not_exists(string_null(User::EmailConfirmationToken)) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::EmailConfirmedAt)) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::LastSignInAt)) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::RecoverySentAt)) + .add_column_if_not_exists(string_null(User::RecoveryToken)) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::EmailChangeSentAt)) + .add_column_if_not_exists(string_null(User::EmailChangeTokenNew)) + .add_column_if_not_exists(string_null(User::EmailChangeTokenCurrent)) + .add_column_if_not_exists(timestamp_with_time_zone_null(User::DeletedAt)) + .to_owned() +} + +fn alter_table_drop_columns() -> TableAlterStatement { + Table::alter() + .table(User::Table) + .drop_column(User::EmailConfirmationSentAt) + .drop_column(User::EmailConfirmationToken) + .drop_column(User::EmailConfirmedAt) + .drop_column(User::LastSignInAt) + .drop_column(User::RecoverySentAt) + .drop_column(User::RecoveryToken) + .drop_column(User::EmailChangeSentAt) + .drop_column(User::EmailChangeTokenNew) + .drop_column(User::EmailChangeTokenCurrent) + .drop_column(User::DeletedAt) + .to_owned() +} + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + use sea_orm::sea_query::PostgresQueryBuilder; + + #[test] + #[cfg_attr(coverage_nightly, coverage(off))] + fn alter_table_add_columns() { + let query = super::alter_table_add_columns(); + + assert_snapshot!(query.to_string(PostgresQueryBuilder)); + } + + #[test] + #[cfg_attr(coverage_nightly, coverage(off))] + fn alter_table_drop_columns() { + let query = super::alter_table_drop_columns(); + + assert_snapshot!(query.to_string(PostgresQueryBuilder)); + } +} diff --git a/src/migration/user/mod.rs b/src/migration/user/mod.rs new file mode 100644 index 00000000..0c3c6e76 --- /dev/null +++ b/src/migration/user/mod.rs @@ -0,0 +1,52 @@ +use sea_orm_migration::prelude::*; + +mod create_table; +pub mod m20240714_203550_create_user_table_int_pk; +pub mod m20240714_203551_create_user_table_uuid_pk; +pub mod m20240723_070533_add_user_account_management_fields; + +/// The collection of migrations defined to create a `user` table. Migrations authored +/// by `roadster` will automatically be added here. +/// +/// Note that the migration uses a `UUID` field for the `id` Primary Key field. If you would like +/// to use a `BIGINT` instead, you can do one of the following: +/// +/// 1. Use the [m20240714_203550_create_user_table_int_pk::Migration] instead -- simply add it to +/// your main [MigratorTrait] implementation before the migrations from [UserMigrator]. +/// 2. Add an `alter table` migration after the migrations from [UserMigrator]. +#[non_exhaustive] +pub struct UserMigrator; + +#[async_trait::async_trait] +impl MigratorTrait for UserMigrator { + fn migrations() -> Vec> { + vec![ + Box::new(m20240714_203551_create_user_table_uuid_pk::Migration), + Box::new(m20240723_070533_add_user_account_management_fields::Migration), + ] + } +} + +/// Contains the identifiers/fields created by all the `user` migrations. +#[derive(DeriveIden)] +pub(crate) enum User { + Table, + Id, + Name, + Username, + Email, + Password, + EmailConfirmationSentAt, + EmailConfirmationToken, + EmailConfirmedAt, + LastSignInAt, + RecoverySentAt, + RecoveryToken, + EmailChangeSentAt, + /// Token sent to the new email to confirm it's a valid email and the user has access to it. + EmailChangeTokenNew, + /// Token sent to the current email to confirm the user authorized the email change. + EmailChangeTokenCurrent, + /// When the user was deleted. + DeletedAt, +} diff --git a/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_int_pk.snap b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_int_pk.snap new file mode 100644 index 00000000..095d7e60 --- /dev/null +++ b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_int_pk.snap @@ -0,0 +1,5 @@ +--- +source: src/migration/user/create_table.rs +expression: query.to_string(PostgresQueryBuilder) +--- +CREATE TABLE IF NOT EXISTS "user" ( "created_at" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, "id" bigserial NOT NULL PRIMARY KEY, "name" varchar NOT NULL CHECK (CHAR_LENGTH("name") > 0), "username" varchar NOT NULL UNIQUE CHECK (CHAR_LENGTH("username") > 0), "email" varchar NOT NULL UNIQUE CHECK (CHAR_LENGTH("email") > 0), "password" varchar NOT NULL ) diff --git a/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_uuid_pk.snap b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_uuid_pk.snap new file mode 100644 index 00000000..6e944df9 --- /dev/null +++ b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__create_table_uuid_pk.snap @@ -0,0 +1,5 @@ +--- +source: src/migration/user/create_table.rs +expression: query.to_string(PostgresQueryBuilder) +--- +CREATE TABLE IF NOT EXISTS "user" ( "created_at" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, "id" uuid PRIMARY KEY, "name" varchar NOT NULL CHECK (CHAR_LENGTH("name") > 0), "username" varchar NOT NULL UNIQUE CHECK (CHAR_LENGTH("username") > 0), "email" varchar NOT NULL UNIQUE CHECK (CHAR_LENGTH("email") > 0), "password" varchar NOT NULL ) diff --git a/src/migration/user/snapshots/roadster__migration__user__create_table__tests__drop_table.snap b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__drop_table.snap new file mode 100644 index 00000000..b863429e --- /dev/null +++ b/src/migration/user/snapshots/roadster__migration__user__create_table__tests__drop_table.snap @@ -0,0 +1,5 @@ +--- +source: src/migration/user/create_table.rs +expression: query.to_string(PostgresQueryBuilder) +--- +DROP TABLE "user" diff --git a/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_add_columns.snap b/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_add_columns.snap new file mode 100644 index 00000000..d881cfd9 --- /dev/null +++ b/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_add_columns.snap @@ -0,0 +1,5 @@ +--- +source: src/migration/user/m20240723_070533_add_user_account_management_fields.rs +expression: query.to_string(PostgresQueryBuilder) +--- +ALTER TABLE "user" ADD COLUMN IF NOT EXISTS "email_confirmation_sent_at" timestamp with time zone NULL, ADD COLUMN IF NOT EXISTS "email_confirmation_token" varchar NULL, ADD COLUMN IF NOT EXISTS "email_confirmed_at" timestamp with time zone NULL, ADD COLUMN IF NOT EXISTS "last_sign_in_at" timestamp with time zone NULL, ADD COLUMN IF NOT EXISTS "recovery_sent_at" timestamp with time zone NULL, ADD COLUMN IF NOT EXISTS "recovery_token" varchar NULL, ADD COLUMN IF NOT EXISTS "email_change_sent_at" timestamp with time zone NULL, ADD COLUMN IF NOT EXISTS "email_change_token_new" varchar NULL, ADD COLUMN IF NOT EXISTS "email_change_token_current" varchar NULL, ADD COLUMN IF NOT EXISTS "deleted_at" timestamp with time zone NULL diff --git a/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_drop_columns.snap b/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_drop_columns.snap new file mode 100644 index 00000000..21e34180 --- /dev/null +++ b/src/migration/user/snapshots/roadster__migration__user__m20240723_070533_add_user_account_management_fields__tests__alter_table_drop_columns.snap @@ -0,0 +1,5 @@ +--- +source: src/migration/user/m20240723_070533_add_user_account_management_fields.rs +expression: query.to_string(PostgresQueryBuilder) +--- +ALTER TABLE "user" DROP COLUMN "email_confirmation_sent_at", DROP COLUMN "email_confirmation_token", DROP COLUMN "email_confirmed_at", DROP COLUMN "last_sign_in_at", DROP COLUMN "recovery_sent_at", DROP COLUMN "recovery_token", DROP COLUMN "email_change_sent_at", DROP COLUMN "email_change_token_new", DROP COLUMN "email_change_token_current", DROP COLUMN "deleted_at"