use async_graphql::SimpleObject; use async_trait::async_trait; use sea_orm::{ActiveValue, FromJsonQueryResult, entity::prelude::*, sea_query::OnConflict}; use serde::{Deserialize, Serialize}; use super::subscription_bangumi; use crate::{app::AppContextTrait, errors::RecorderResult}; #[derive( Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult, SimpleObject, )] pub struct BangumiFilter { pub name: Option>, pub group: Option>, } #[derive( Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult, SimpleObject, )] pub struct BangumiExtra { pub name_zh: Option, pub s_name_zh: Option, pub name_en: Option, pub s_name_en: Option, pub name_jp: Option, pub s_name_jp: Option, } #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, SimpleObject)] #[sea_orm(table_name = "bangumi")] pub struct Model { #[sea_orm(default_expr = "Expr::current_timestamp()")] pub created_at: DateTimeUtc, #[sea_orm(default_expr = "Expr::current_timestamp()")] pub updated_at: DateTimeUtc, #[sea_orm(primary_key)] pub id: i32, pub mikan_bangumi_id: Option, pub subscriber_id: i32, pub display_name: String, pub raw_name: String, pub season: i32, pub season_raw: Option, pub fansub: Option, pub mikan_fansub_id: Option, pub filter: Option, pub rss_link: Option, pub poster_link: Option, pub save_path: Option, #[sea_orm(default = "false")] pub deleted: bool, pub homepage: Option, pub extra: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::subscriptions::Entity")] Subscription, #[sea_orm( belongs_to = "super::subscribers::Entity", from = "Column::SubscriberId", to = "super::subscribers::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] Subscriber, #[sea_orm(has_many = "super::episodes::Entity")] Episode, #[sea_orm(has_many = "super::subscription_bangumi::Entity")] SubscriptionBangumi, } impl Related for Entity { fn to() -> RelationDef { Relation::Episode.def() } } impl Related for Entity { fn to() -> RelationDef { Relation::SubscriptionBangumi.def() } } impl Related for Entity { fn to() -> RelationDef { super::subscription_bangumi::Relation::Subscription.def() } fn via() -> Option { Some(super::subscription_bangumi::Relation::Bangumi.def().rev()) } } impl Related for Entity { fn to() -> RelationDef { Relation::Subscriber.def() } } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)] pub enum RelatedEntity { #[sea_orm(entity = "super::subscriptions::Entity")] Subscription, #[sea_orm(entity = "super::subscribers::Entity")] Subscriber, #[sea_orm(entity = "super::episodes::Entity")] Episode, #[sea_orm(entity = "super::subscription_bangumi::Entity")] SubscriptionBangumi, } impl Model { pub async fn get_or_insert_from_mikan( ctx: &dyn AppContextTrait, subscriber_id: i32, subscription_id: i32, mikan_bangumi_id: String, mikan_fansub_id: String, f: F, ) -> RecorderResult where F: AsyncFnOnce(&mut ActiveModel) -> RecorderResult<()>, { let db = ctx.db(); if let Some(existed) = Entity::find() .filter( Column::MikanBangumiId .eq(Some(mikan_bangumi_id.clone())) .and(Column::MikanFansubId.eq(Some(mikan_fansub_id.clone()))), ) .one(db) .await? { Ok(existed) } else { let mut bgm = ActiveModel { mikan_bangumi_id: ActiveValue::Set(Some(mikan_bangumi_id)), mikan_fansub_id: ActiveValue::Set(Some(mikan_fansub_id)), subscriber_id: ActiveValue::Set(subscriber_id), ..Default::default() }; f(&mut bgm).await?; let bgm = Entity::insert(bgm) .on_conflict( OnConflict::columns([ Column::MikanBangumiId, Column::MikanFansubId, Column::SubscriberId, ]) .update_columns([ Column::RawName, Column::Extra, Column::Fansub, Column::PosterLink, Column::Season, Column::SeasonRaw, ]) .to_owned(), ) .exec_with_returning(db) .await?; subscription_bangumi::Entity::insert(subscription_bangumi::ActiveModel { subscription_id: ActiveValue::Set(subscription_id), bangumi_id: ActiveValue::Set(bgm.id), ..Default::default() }) .on_conflict_do_nothing() .exec(db) .await?; Ok(bgm) } } } #[async_trait] impl ActiveModelBehavior for ActiveModel {}