feat: add basic webui
This commit is contained in:
373
apps/recorder/src/migrations/defs.rs
Normal file
373
apps/recorder/src/migrations/defs.rs
Normal file
@@ -0,0 +1,373 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use sea_orm::{DeriveIden, Statement};
|
||||
use sea_orm_migration::prelude::{extension::postgres::IntoTypeRef, *};
|
||||
|
||||
use crate::migrations::extension::postgres::Type;
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum GeneralIds {
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Subscribers {
|
||||
Table,
|
||||
Id,
|
||||
Pid,
|
||||
DisplayName,
|
||||
DownloaderId,
|
||||
BangumiConf,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Subscriptions {
|
||||
Table,
|
||||
Id,
|
||||
DisplayName,
|
||||
SubscriberId,
|
||||
Category,
|
||||
SourceUrl,
|
||||
Enabled,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Bangumi {
|
||||
Table,
|
||||
Id,
|
||||
MikanBangumiId,
|
||||
DisplayName,
|
||||
SubscriptionId,
|
||||
SubscriberId,
|
||||
RawName,
|
||||
Season,
|
||||
SeasonRaw,
|
||||
Fansub,
|
||||
MikanFansubId,
|
||||
Filter,
|
||||
RssLink,
|
||||
PosterLink,
|
||||
SavePath,
|
||||
Deleted,
|
||||
Homepage,
|
||||
Extra,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Episodes {
|
||||
Table,
|
||||
Id,
|
||||
MikanEpisodeId,
|
||||
RawName,
|
||||
DisplayName,
|
||||
BangumiId,
|
||||
SubscriptionId,
|
||||
SubscriberId,
|
||||
DownloadId,
|
||||
SavePath,
|
||||
Resolution,
|
||||
Season,
|
||||
SeasonRaw,
|
||||
Fansub,
|
||||
PosterLink,
|
||||
EpisodeIndex,
|
||||
Homepage,
|
||||
Subtitle,
|
||||
Deleted,
|
||||
Source,
|
||||
Extra,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Downloads {
|
||||
Table,
|
||||
Id,
|
||||
OriginalName,
|
||||
DisplayName,
|
||||
SubscriptionId,
|
||||
Status,
|
||||
CurrSize,
|
||||
AllSize,
|
||||
Mime,
|
||||
Url,
|
||||
Homepage,
|
||||
SavePath,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
pub enum Downloaders {
|
||||
Table,
|
||||
Id,
|
||||
Category,
|
||||
Endpoint,
|
||||
Password,
|
||||
Username,
|
||||
SubscriberId,
|
||||
SavePath,
|
||||
}
|
||||
|
||||
macro_rules! create_postgres_enum_for_active_enum {
|
||||
($manager: expr, $active_enum: expr, $($enum_value:expr),+) => {
|
||||
{
|
||||
use sea_orm::ActiveEnum;
|
||||
let values = [$($enum_value,)+].map(|v| ActiveEnum::to_value(&v));
|
||||
($manager).create_postgres_enum_for_active_enum($active_enum, values)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait CustomSchemaManagerExt {
|
||||
async fn create_postgres_auto_update_ts_fn(&self, col_name: &str) -> Result<(), DbErr>;
|
||||
async fn create_postgres_auto_update_ts_fn_for_col<C: IntoIden + 'static + Send>(
|
||||
&self,
|
||||
col: C,
|
||||
) -> Result<(), DbErr> {
|
||||
let column_ident = col.into_iden();
|
||||
self.create_postgres_auto_update_ts_fn(&column_ident.to_string())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_postgres_auto_update_ts_trigger(
|
||||
&self,
|
||||
tab_name: &str,
|
||||
col_name: &str,
|
||||
) -> Result<(), DbErr>;
|
||||
|
||||
async fn create_postgres_auto_update_ts_trigger_for_col<
|
||||
T: IntoIden + 'static + Send,
|
||||
C: IntoIden + 'static + Send,
|
||||
>(
|
||||
&self,
|
||||
tab: T,
|
||||
col: C,
|
||||
) -> Result<(), DbErr> {
|
||||
let column_ident = col.into_iden();
|
||||
let table_ident = tab.into_iden();
|
||||
self.create_postgres_auto_update_ts_trigger(
|
||||
&table_ident.to_string(),
|
||||
&column_ident.to_string(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop_postgres_auto_update_ts_fn(&self, col_name: &str) -> Result<(), DbErr>;
|
||||
|
||||
async fn drop_postgres_auto_update_ts_fn_for_col<C: IntoIden + Send>(
|
||||
&self,
|
||||
col: C,
|
||||
) -> Result<(), DbErr> {
|
||||
let column_ident = col.into_iden();
|
||||
self.drop_postgres_auto_update_ts_fn(&column_ident.to_string())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop_postgres_auto_update_ts_trigger(
|
||||
&self,
|
||||
tab_name: &str,
|
||||
col_name: &str,
|
||||
) -> Result<(), DbErr>;
|
||||
|
||||
async fn drop_postgres_auto_update_ts_trigger_for_col<
|
||||
T: IntoIden + 'static + Send,
|
||||
C: IntoIden + 'static + Send,
|
||||
>(
|
||||
&self,
|
||||
tab: T,
|
||||
col: C,
|
||||
) -> Result<(), DbErr> {
|
||||
let column_ident = col.into_iden();
|
||||
let table_ident = tab.into_iden();
|
||||
self.drop_postgres_auto_update_ts_trigger(
|
||||
&table_ident.to_string(),
|
||||
&column_ident.to_string(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_postgres_enum_for_active_enum<
|
||||
E: IntoTypeRef + IntoIden + Send + Clone,
|
||||
I: IntoIterator<Item = String> + Send,
|
||||
>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
values: I,
|
||||
) -> Result<(), DbErr>;
|
||||
|
||||
async fn add_postgres_enum_values_for_active_enum<
|
||||
E: IntoTypeRef + IntoIden + Send + Clone,
|
||||
I: IntoIterator<Item = String> + Send,
|
||||
>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
values: I,
|
||||
) -> Result<(), DbErr>;
|
||||
|
||||
async fn drop_postgres_enum_for_active_enum<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<(), DbErr>;
|
||||
|
||||
async fn if_postgres_enum_exists<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<bool, DbErr>;
|
||||
|
||||
async fn get_postgres_enum_values<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<HashSet<String>, DbErr>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl CustomSchemaManagerExt for SchemaManager<'_> {
|
||||
async fn create_postgres_auto_update_ts_fn(&self, col_name: &str) -> Result<(), DbErr> {
|
||||
let sql = format!(
|
||||
"CREATE OR REPLACE FUNCTION update_{col_name}_column() RETURNS TRIGGER AS $$ BEGIN \
|
||||
NEW.{col_name} = current_timestamp; RETURN NEW; END; $$ language 'plpgsql';"
|
||||
);
|
||||
|
||||
self.get_connection()
|
||||
.execute(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_postgres_auto_update_ts_trigger(
|
||||
&self,
|
||||
tab_name: &str,
|
||||
col_name: &str,
|
||||
) -> Result<(), DbErr> {
|
||||
let sql = format!(
|
||||
"CREATE OR REPLACE TRIGGER update_{tab_name}_{col_name}_column_trigger BEFORE UPDATE \
|
||||
ON {tab_name} FOR EACH ROW EXECUTE PROCEDURE update_{col_name}_column();"
|
||||
);
|
||||
self.get_connection()
|
||||
.execute(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop_postgres_auto_update_ts_fn(&self, col_name: &str) -> Result<(), DbErr> {
|
||||
let sql = format!("DROP FUNCTION IF EXISTS update_{col_name}_column();");
|
||||
self.get_connection()
|
||||
.execute(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop_postgres_auto_update_ts_trigger(
|
||||
&self,
|
||||
tab_name: &str,
|
||||
col_name: &str,
|
||||
) -> Result<(), DbErr> {
|
||||
let sql = format!(
|
||||
"DROP TRIGGER IF EXISTS update_{tab_name}_{col_name}_column_trigger ON {tab_name};"
|
||||
);
|
||||
self.get_connection()
|
||||
.execute(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_postgres_enum_for_active_enum<
|
||||
E: IntoTypeRef + IntoIden + Send + Clone,
|
||||
I: IntoIterator<Item = String> + Send,
|
||||
>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
values: I,
|
||||
) -> Result<(), DbErr> {
|
||||
let existed = self.if_postgres_enum_exists(enum_name.clone()).await?;
|
||||
if !existed {
|
||||
let idents = values.into_iter().map(Alias::new).collect::<Vec<_>>();
|
||||
self.create_type(Type::create().as_enum(enum_name).values(idents).to_owned())
|
||||
.await?;
|
||||
} else {
|
||||
self.add_postgres_enum_values_for_active_enum(enum_name, values)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_postgres_enum_values_for_active_enum<
|
||||
E: IntoTypeRef + IntoIden + Send + Clone,
|
||||
I: IntoIterator<Item = String> + Send,
|
||||
>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
values: I,
|
||||
) -> Result<(), DbErr> {
|
||||
let exists_values = self.get_postgres_enum_values(enum_name.clone()).await?;
|
||||
let to_add_values = values
|
||||
.into_iter()
|
||||
.filter(|v| !exists_values.contains(v as &str))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if to_add_values.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut type_alter = Type::alter().name(enum_name);
|
||||
|
||||
for v in to_add_values {
|
||||
type_alter = type_alter.add_value(Alias::new(v));
|
||||
}
|
||||
|
||||
self.alter_type(type_alter.to_owned()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn drop_postgres_enum_for_active_enum<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<(), DbErr> {
|
||||
if self.if_postgres_enum_exists(enum_name.clone()).await? {
|
||||
self.drop_type(Type::drop().name(enum_name).to_owned())
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn if_postgres_enum_exists<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<bool, DbErr> {
|
||||
let enum_name: String = enum_name.into_iden().to_string();
|
||||
let sql = format!("SELECT 1 FROM pg_type WHERE typname = '{enum_name}'");
|
||||
let result = self
|
||||
.get_connection()
|
||||
.query_one(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
Ok(result.is_some())
|
||||
}
|
||||
|
||||
async fn get_postgres_enum_values<E: IntoTypeRef + IntoIden + Send + Clone>(
|
||||
&self,
|
||||
enum_name: E,
|
||||
) -> Result<HashSet<String>, DbErr> {
|
||||
let enum_name: String = enum_name.into_iden().to_string();
|
||||
let sql = format!(
|
||||
"SELECT pg_enum.enumlabel AS enumlabel FROM pg_type JOIN pg_enum ON pg_enum.enumtypid \
|
||||
= pg_type.oid WHERE pg_type.typname = '{enum_name}';"
|
||||
);
|
||||
|
||||
let results = self
|
||||
.get_connection()
|
||||
.query_all(Statement::from_string(self.get_database_backend(), sql))
|
||||
.await?;
|
||||
|
||||
let mut items = HashSet::new();
|
||||
for r in results {
|
||||
items.insert(r.try_get::<String>("", "enumlabel")?);
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
}
|
||||
284
apps/recorder/src/migrations/m20220101_000001_init.rs
Normal file
284
apps/recorder/src/migrations/m20220101_000001_init.rs
Normal file
@@ -0,0 +1,284 @@
|
||||
use loco_rs::schema::jsonb_null;
|
||||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use super::defs::{
|
||||
Bangumi, CustomSchemaManagerExt, Episodes, GeneralIds, Subscribers, Subscriptions,
|
||||
};
|
||||
use crate::models::{
|
||||
subscribers::ROOT_SUBSCRIBER,
|
||||
subscriptions::{self, SubscriptionCategoryEnum},
|
||||
};
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_postgres_auto_update_ts_fn_for_col(GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Subscribers::Table)
|
||||
.col(pk_auto(Subscribers::Id))
|
||||
.col(string_len_uniq(Subscribers::Pid, 64))
|
||||
.col(string(Subscribers::DisplayName))
|
||||
.col(jsonb_null(Subscribers::BangumiConf))
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_postgres_auto_update_ts_trigger_for_col(
|
||||
Subscribers::Table,
|
||||
GeneralIds::UpdatedAt,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let insert = Query::insert()
|
||||
.into_table(Subscribers::Table)
|
||||
.columns([Subscribers::Pid, Subscribers::DisplayName])
|
||||
.values_panic([ROOT_SUBSCRIBER.into(), ROOT_SUBSCRIBER.into()])
|
||||
.to_owned();
|
||||
manager.exec_stmt(insert).await?;
|
||||
|
||||
create_postgres_enum_for_active_enum!(
|
||||
manager,
|
||||
subscriptions::SubscriptionCategoryEnum,
|
||||
subscriptions::SubscriptionCategory::Mikan,
|
||||
subscriptions::SubscriptionCategory::Manual
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Subscriptions::Table)
|
||||
.col(pk_auto(Subscriptions::Id))
|
||||
.col(string(Subscriptions::DisplayName))
|
||||
.col(integer(Subscriptions::SubscriberId))
|
||||
.col(text(Subscriptions::SourceUrl))
|
||||
.col(boolean(Subscriptions::Enabled))
|
||||
.col(enumeration(
|
||||
Subscriptions::Category,
|
||||
subscriptions::SubscriptionCategoryEnum,
|
||||
subscriptions::SubscriptionCategory::iden_values(),
|
||||
))
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_subscriptions_subscriber_id")
|
||||
.from(Subscriptions::Table, Subscriptions::SubscriberId)
|
||||
.to(Subscribers::Table, Subscribers::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_postgres_auto_update_ts_trigger_for_col(
|
||||
Subscriptions::Table,
|
||||
GeneralIds::UpdatedAt,
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Bangumi::Table)
|
||||
.col(pk_auto(Bangumi::Id))
|
||||
.col(text_null(Bangumi::MikanBangumiId))
|
||||
.col(integer(Bangumi::SubscriptionId))
|
||||
.col(integer(Bangumi::SubscriberId))
|
||||
.col(text(Bangumi::DisplayName))
|
||||
.col(text(Bangumi::RawName))
|
||||
.col(integer(Bangumi::Season))
|
||||
.col(text_null(Bangumi::SeasonRaw))
|
||||
.col(text_null(Bangumi::Fansub))
|
||||
.col(text_null(Bangumi::MikanFansubId))
|
||||
.col(jsonb_null(Bangumi::Filter))
|
||||
.col(text_null(Bangumi::RssLink))
|
||||
.col(text_null(Bangumi::PosterLink))
|
||||
.col(text_null(Bangumi::SavePath))
|
||||
.col(boolean(Bangumi::Deleted).default(false))
|
||||
.col(text_null(Bangumi::Homepage))
|
||||
.col(jsonb_null(Bangumi::Extra))
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_bangumi_subscription_id")
|
||||
.from(Bangumi::Table, Bangumi::SubscriptionId)
|
||||
.to(Subscriptions::Table, Subscriptions::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_bangumi_subscriber_id")
|
||||
.from(Bangumi::Table, Bangumi::SubscriberId)
|
||||
.to(Subscribers::Table, Subscribers::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("idx_bangumi_mikan_bangumi_id")
|
||||
.table(Bangumi::Table)
|
||||
.col(Bangumi::MikanBangumiId)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("idx_bangumi_mikan_fansub_id")
|
||||
.table(Bangumi::Table)
|
||||
.col(Bangumi::MikanFansubId)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_postgres_auto_update_ts_trigger_for_col(Bangumi::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Episodes::Table)
|
||||
.col(pk_auto(Episodes::Id))
|
||||
.col(text_null(Episodes::MikanEpisodeId))
|
||||
.col(text(Episodes::RawName))
|
||||
.col(text(Episodes::DisplayName))
|
||||
.col(integer(Episodes::BangumiId))
|
||||
.col(integer(Episodes::SubscriptionId))
|
||||
.col(integer(Episodes::SubscriberId))
|
||||
.col(text_null(Episodes::SavePath))
|
||||
.col(text_null(Episodes::Resolution))
|
||||
.col(integer(Episodes::Season))
|
||||
.col(text_null(Episodes::SeasonRaw))
|
||||
.col(text_null(Episodes::Fansub))
|
||||
.col(text_null(Episodes::PosterLink))
|
||||
.col(integer(Episodes::EpisodeIndex))
|
||||
.col(text_null(Episodes::Homepage))
|
||||
.col(text_null(Episodes::Subtitle))
|
||||
.col(boolean(Episodes::Deleted).default(false))
|
||||
.col(text_null(Episodes::Source))
|
||||
.col(jsonb_null(Episodes::Extra))
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_episodes_subscription_id")
|
||||
.from(Episodes::Table, Episodes::SubscriptionId)
|
||||
.to(Subscriptions::Table, Subscriptions::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_episodes_bangumi_id")
|
||||
.from(Episodes::Table, Episodes::BangumiId)
|
||||
.to(Bangumi::Table, Bangumi::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_episodes_subscriber_id")
|
||||
.from(Episodes::Table, Episodes::SubscriberId)
|
||||
.to(Subscribers::Table, Subscribers::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("idx_episodes_mikan_episode_id")
|
||||
.table(Episodes::Table)
|
||||
.col(Episodes::MikanEpisodeId)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("idx_episodes_bangumi_id_mikan_episode_id")
|
||||
.table(Episodes::Table)
|
||||
.col(Episodes::BangumiId)
|
||||
.col(Episodes::MikanEpisodeId)
|
||||
.unique()
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_postgres_auto_update_ts_trigger_for_col(Episodes::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Episodes::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_trigger_for_col(Episodes::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Bangumi::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_trigger_for_col(Bangumi::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Subscriptions::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_trigger_for_col(
|
||||
Subscriptions::Table,
|
||||
GeneralIds::UpdatedAt,
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Subscribers::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_trigger_for_col(Subscribers::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_enum_for_active_enum(subscriptions::SubscriptionCategoryEnum)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_fn_for_col(GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_enum_for_active_enum(SubscriptionCategoryEnum)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
128
apps/recorder/src/migrations/m20240224_082543_add_downloads.rs
Normal file
128
apps/recorder/src/migrations/m20240224_082543_add_downloads.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use loco_rs::schema::table_auto;
|
||||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use super::defs::*;
|
||||
use crate::models::prelude::{
|
||||
downloads::{DownloadMimeEnum, DownloadStatusEnum},
|
||||
DownloadMime, DownloadStatus,
|
||||
};
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
create_postgres_enum_for_active_enum!(
|
||||
manager,
|
||||
DownloadMimeEnum,
|
||||
DownloadMime::BitTorrent,
|
||||
DownloadMime::OctetStream
|
||||
)
|
||||
.await?;
|
||||
|
||||
create_postgres_enum_for_active_enum!(
|
||||
manager,
|
||||
DownloadStatusEnum,
|
||||
DownloadStatus::Downloading,
|
||||
DownloadStatus::Paused,
|
||||
DownloadStatus::Pending,
|
||||
DownloadStatus::Completed,
|
||||
DownloadStatus::Failed,
|
||||
DownloadStatus::Deleted
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Downloads::Table)
|
||||
.col(pk_auto(Downloads::Id))
|
||||
.col(string(Downloads::OriginalName))
|
||||
.col(string(Downloads::DisplayName))
|
||||
.col(integer(Downloads::SubscriptionId))
|
||||
.col(enumeration(
|
||||
Downloads::Status,
|
||||
DownloadStatusEnum,
|
||||
DownloadMime::iden_values(),
|
||||
))
|
||||
.col(enumeration(
|
||||
Downloads::Mime,
|
||||
DownloadMimeEnum,
|
||||
DownloadMime::iden_values(),
|
||||
))
|
||||
.col(big_unsigned(Downloads::AllSize))
|
||||
.col(big_unsigned(Downloads::CurrSize))
|
||||
.col(text(Downloads::Url))
|
||||
.col(text_null(Downloads::Homepage))
|
||||
.col(text_null(Downloads::SavePath))
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_downloads_subscription_id")
|
||||
.from(Downloads::Table, Downloads::SubscriptionId)
|
||||
.to(Subscriptions::Table, Subscriptions::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.name("idx_downloads_url")
|
||||
.table(Downloads::Table)
|
||||
.col(Downloads::Url)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Episodes::Table)
|
||||
.add_column_if_not_exists(integer_null(Episodes::DownloadId))
|
||||
.add_foreign_key(
|
||||
TableForeignKey::new()
|
||||
.name("fk_episodes_download_id")
|
||||
.from_tbl(Episodes::Table)
|
||||
.from_col(Episodes::DownloadId)
|
||||
.to_tbl(Downloads::Table)
|
||||
.to_col(Downloads::Id)
|
||||
.on_update(ForeignKeyAction::Restrict)
|
||||
.on_delete(ForeignKeyAction::SetNull),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Episodes::Table)
|
||||
.drop_foreign_key(Alias::new("fk_episodes_download_id"))
|
||||
.drop_column(Episodes::DownloadId)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Downloads::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_enum_for_active_enum(DownloadMimeEnum)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_enum_for_active_enum(DownloadStatusEnum)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use crate::{
|
||||
migrations::defs::{CustomSchemaManagerExt, Downloaders, GeneralIds, Subscribers},
|
||||
models::{downloaders::DownloaderCategoryEnum, prelude::DownloaderCategory},
|
||||
};
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
create_postgres_enum_for_active_enum!(
|
||||
manager,
|
||||
DownloaderCategoryEnum,
|
||||
DownloaderCategory::QBittorrent
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
table_auto(Downloaders::Table)
|
||||
.col(pk_auto(Downloaders::Id))
|
||||
.col(text(Downloaders::Endpoint))
|
||||
.col(string_null(Downloaders::Username))
|
||||
.col(string_null(Downloaders::Password))
|
||||
.col(enumeration(
|
||||
Downloaders::Category,
|
||||
DownloaderCategoryEnum,
|
||||
DownloaderCategory::iden_values(),
|
||||
))
|
||||
.col(text(Downloaders::SavePath))
|
||||
.col(integer(Downloaders::SubscriberId))
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_downloader_subscriber_id")
|
||||
.from_tbl(Downloaders::Table)
|
||||
.from_col(Downloaders::SubscriberId)
|
||||
.to_tbl(Subscribers::Table)
|
||||
.to_col(Subscribers::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Restrict),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_postgres_auto_update_ts_trigger_for_col(
|
||||
Downloaders::Table,
|
||||
GeneralIds::UpdatedAt,
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Subscribers::Table)
|
||||
.add_column_if_not_exists(integer_null(Subscribers::DownloaderId))
|
||||
.add_foreign_key(
|
||||
TableForeignKey::new()
|
||||
.name("fk_subscribers_downloader_id")
|
||||
.from_tbl(Subscribers::Table)
|
||||
.from_col(Subscribers::DownloaderId)
|
||||
.to_tbl(Downloaders::Table)
|
||||
.to_col(Downloaders::Id)
|
||||
.on_delete(ForeignKeyAction::SetNull)
|
||||
.on_update(ForeignKeyAction::Restrict),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.alter_table(
|
||||
Table::alter()
|
||||
.table(Subscribers::Table)
|
||||
.drop_foreign_key(Alias::new("fk_subscribers_downloader_id"))
|
||||
.drop_column(Subscribers::DownloaderId)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_auto_update_ts_trigger_for_col(Downloaders::Table, GeneralIds::UpdatedAt)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Downloaders::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_postgres_enum_for_active_enum(DownloaderCategoryEnum)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
20
apps/recorder/src/migrations/mod.rs
Normal file
20
apps/recorder/src/migrations/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
#[macro_use]
|
||||
pub mod defs;
|
||||
pub mod m20220101_000001_init;
|
||||
pub mod m20240224_082543_add_downloads;
|
||||
pub mod m20240225_060853_subscriber_add_downloader;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20220101_000001_init::Migration),
|
||||
Box::new(m20240224_082543_add_downloads::Migration),
|
||||
Box::new(m20240225_060853_subscriber_add_downloader::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user