Skip to main content
Version: 0.7.x

Writing Migration

Each migration contains two methods: up and down. The up method is used to alter the database schema, such as adding new tables, columns or indexes, while the down method revert the actions performed in the up method.

Creating Migration File

You can create a migration by duplicating an existing migration file or by copying the template below. Remember to name the file according to naming convention mYYYYMMDD_HHMMSS_migration_name.rs and update the MigrationName::name method accordingly.

migration/src/m20220101_000001_create_table.rs
use sea_schema::migration::prelude::*;

pub struct Migration;

impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220101_000001_create_table"
}
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table( ... )
.await
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table( ... )
.await
}
}

Additionally, you have to include the new migration in MigratorTrait::migrations method. Note that the migrations should be sorted in chronological order.

migration/src/lib.rs
pub use sea_schema::migration::*;

mod m20220101_000001_create_table;

pub struct Migrator;

#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220101_000001_create_table::Migration),
]
}
}

Defining Migration

The SchemaManager helps you define migration in either SeaQuery or raw SQL

SeaQuery

Click here to take a quick tour of SeaQuery.

Schema Creation Methods

  • Create Table

    use entity::post;

    manager
    .create_table(
    sea_query::Table::create()
    .table(post::Entity)
    .if_not_exists()
    .col(
    ColumnDef::new(post::Column::Id)
    .integer()
    .not_null()
    .auto_increment()
    .primary_key(),
    )
    .col(ColumnDef::new(post::Column::Title).string().not_null())
    .col(ColumnDef::new(post::Column::Text).string().not_null())
    .to_owned()
    )
    If you don't have SeaORM entities defined?
    manager
    .create_table(
    Table::create()
    .table(Post::Table)
    .if_not_exists()
    .col(
    ColumnDef::new(Post::Id)
    .integer()
    .not_null()
    .auto_increment()
    .primary_key(),
    )
    .col(ColumnDef::new(Post::Title).string().not_null())
    .col(ColumnDef::new(Post::Text).string().not_null())
    .to_owned()
    )

    // Define the identifiers using SeaQuery's `Iden` macro
    #[derive(Iden)]
    pub enum Post {
    Table,
    Id,
    Title,
    Text,
    }
  • Create Index

    manager.create_index(sea_query::Index::create())
  • Create Foreign Key

    manager.create_foreign_key(sea_query::ForeignKey::create())
  • Create Data Type (PostgreSQL only)

    manager.create_type(sea_query::Type::create())

Schema Mutation Methods

  • Drop Table

    use entity::post;

    manager
    .drop_table(
    sea_query::Table::drop()
    .table(post::Entity)
    .to_owned()
    )
    If you don't have SeaORM entities defined?
    manager
    .drop_table(
    sea_query::Table::drop()
    .table(Post::Table)
    .to_owned()
    )

    // Define the identifiers using SeaQuery's `Iden` macro
    #[derive(Iden)]
    pub enum Post {
    Table,
    Id,
    Title,
    Text,
    }
  • Alter Table

    manager.alter_table(sea_query::Table::alter())
  • Rename Table

    manager.rename_table(sea_query::Table::rename())
  • Truncate Table

    manager.truncate_table(sea_query::Table::truncate())
  • Drop Index

    manager.drop_index(sea_query::Index::drop())
  • Drop Foreign Key

    manager.drop_foreign_key(sea_query::ForeignKey::drop())
  • Alter Data Type (PostgreSQL only)

    manager.alter_type(sea_query::Type::alter())
  • Drop Data Type (PostgreSQL only)

    manager.drop_type(sea_query::extension::postgres::Type())

Schema Inspection Methods

  • Has Table
    manager.has_table(table_name)
  • Has Column
    manager.has_column(table_name, column_name)

Raw SQL

You can define a migration in raw SQL too.

use sea_orm::Statement;
use sea_schema::migration::prelude::*;

pub struct Migration;

impl MigrationName for Migration {
fn name(&self) -> &str {
"m20220101_000001_create_table"
}
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let sql = "CREATE TABLE `cake` ( `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(255) NOT NULL )";
let stmt = Statement::from_string(manager.get_database_backend(), sql.to_owned());
manager.get_connection().execute(stmt).await.map(|_| ())
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let sql = "DROP TABLE `cake`";
let stmt = Statement::from_string(manager.get_database_backend(), sql.to_owned());
manager.get_connection().execute(stmt).await.map(|_| ())
}
}