use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager .create_table( Table::create() .table(Messages::Table) .if_not_exists() .col( ColumnDef::new(Messages::Id) .uuid() .not_null() .primary_key(), ) .col(ColumnDef::new(Messages::TenantId).uuid().not_null()) .col(ColumnDef::new(Messages::TemplateId).uuid().null()) .col(ColumnDef::new(Messages::SenderId).uuid().null()) .col( ColumnDef::new(Messages::SenderType) .string() .not_null() .default("system"), ) .col(ColumnDef::new(Messages::RecipientId).uuid().not_null()) .col( ColumnDef::new(Messages::RecipientType) .string() .not_null() .default("user"), ) .col(ColumnDef::new(Messages::Title).string().not_null()) .col(ColumnDef::new(Messages::Body).text().not_null()) .col( ColumnDef::new(Messages::Priority) .string() .not_null() .default("normal"), ) .col(ColumnDef::new(Messages::BusinessType).string().null()) .col(ColumnDef::new(Messages::BusinessId).uuid().null()) .col( ColumnDef::new(Messages::IsRead) .boolean() .not_null() .default(false), ) .col(ColumnDef::new(Messages::ReadAt).timestamp_with_time_zone().null()) .col( ColumnDef::new(Messages::IsArchived) .boolean() .not_null() .default(false), ) .col(ColumnDef::new(Messages::ArchivedAt).timestamp_with_time_zone().null()) .col(ColumnDef::new(Messages::SentAt).timestamp_with_time_zone().null()) .col( ColumnDef::new(Messages::Status) .string() .not_null() .default("sent"), ) .col(ColumnDef::new(Messages::CreatedAt).timestamp_with_time_zone().not_null()) .col(ColumnDef::new(Messages::UpdatedAt).timestamp_with_time_zone().not_null()) .col(ColumnDef::new(Messages::CreatedBy).uuid().not_null()) .col(ColumnDef::new(Messages::UpdatedBy).uuid().not_null()) .col(ColumnDef::new(Messages::DeletedAt).timestamp_with_time_zone().null()) .to_owned(), ) .await?; manager.get_connection().execute(sea_orm::Statement::from_string( sea_orm::DatabaseBackend::Postgres, "CREATE INDEX idx_messages_tenant_recipient ON messages (tenant_id, recipient_id) WHERE deleted_at IS NULL".to_string(), )).await.map_err(|e| DbErr::Custom(e.to_string()))?; manager.get_connection().execute(sea_orm::Statement::from_string( sea_orm::DatabaseBackend::Postgres, "CREATE INDEX idx_messages_tenant_recipient_unread ON messages (tenant_id, recipient_id) WHERE deleted_at IS NULL AND is_read = false".to_string(), )).await.map_err(|e| DbErr::Custom(e.to_string()))?; manager.get_connection().execute(sea_orm::Statement::from_string( sea_orm::DatabaseBackend::Postgres, "CREATE INDEX idx_messages_tenant_business ON messages (tenant_id, business_type, business_id) WHERE deleted_at IS NULL".to_string(), )).await.map_err(|e| DbErr::Custom(e.to_string()))?; manager .create_foreign_key( ForeignKey::create() .name("fk_messages_template") .from(Messages::Table, Messages::TemplateId) .to(MessageTemplates::Table, MessageTemplates::Id) .to_owned(), ) .await?; Ok(()) } async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { manager .drop_table(Table::drop().table(Messages::Table).to_owned()) .await } } #[derive(DeriveIden)] enum Messages { Table, Id, TenantId, TemplateId, SenderId, SenderType, RecipientId, RecipientType, Title, Body, Priority, BusinessType, BusinessId, IsRead, ReadAt, IsArchived, ArchivedAt, SentAt, Status, CreatedAt, UpdatedAt, CreatedBy, UpdatedBy, DeletedAt, } #[derive(DeriveIden)] enum MessageTemplates { Table, Id, }