diff --git a/crates/bili_sync/src/adapter/mod.rs b/crates/bili_sync/src/adapter/mod.rs index 29250b6..25ba8ef 100644 --- a/crates/bili_sync/src/adapter/mod.rs +++ b/crates/bili_sync/src/adapter/mod.rs @@ -7,7 +7,6 @@ use std::pin::Pin; use anyhow::Result; use async_trait::async_trait; -use bili_sync_migration::IntoIden; pub use collection::collection_from; pub use favorite::favorite_from; use futures::Stream; @@ -32,18 +31,11 @@ pub async fn video_list_from<'a>( } } -pub const fn unique_video_columns() -> impl IntoIterator { - [ - bili_sync_entity::video::Column::CollectionId, - bili_sync_entity::video::Column::FavoriteId, - bili_sync_entity::video::Column::Bvid, - ] -} - #[async_trait] pub trait VideoListModel { /* 逻辑相关 */ + /// 获取与视频列表关联的视频总数 async fn video_count(&self, connection: &DatabaseConnection) -> Result; /// 获取未填充的视频 diff --git a/crates/bili_sync/src/utils/convert.rs b/crates/bili_sync/src/utils/convert.rs index 98810ba..399936f 100644 --- a/crates/bili_sync/src/utils/convert.rs +++ b/crates/bili_sync/src/utils/convert.rs @@ -12,8 +12,9 @@ impl VideoInfo { Some(base_model) => base_model.into_active_model(), None => { let mut tmp_model = bili_sync_entity::video::Model::default().into_active_model(); - // 注意此处要把 id 设置成 NotSet,否则 id 会是 Unchanged(0) + // 注意此处要把 id 和 created_at 设置为 NotSet,方便在 sql 中忽略这些字段,交由数据库自动生成 tmp_model.id = NotSet; + tmp_model.created_at = NotSet; tmp_model } }; diff --git a/crates/bili_sync/src/utils/model.rs b/crates/bili_sync/src/utils/model.rs index cccf01c..039b971 100644 --- a/crates/bili_sync/src/utils/model.rs +++ b/crates/bili_sync/src/utils/model.rs @@ -4,7 +4,7 @@ use bili_sync_migration::OnConflict; use sea_orm::entity::prelude::*; use sea_orm::ActiveValue::Set; -use crate::adapter::{unique_video_columns, VideoListModel}; +use crate::adapter::VideoListModel; use crate::bilibili::{PageInfo, VideoInfo}; /// 尝试创建 Video Model,如果发生冲突则忽略 @@ -18,7 +18,8 @@ pub async fn create_videos( .map(|v| video_list_model.video_model_by_info(v, None)) .collect::>(); video::Entity::insert_many(video_models) - .on_conflict(OnConflict::columns(unique_video_columns()).do_nothing().to_owned()) + // 这里想表达的是 on 索引名,但 sea-orm 的 api 似乎只支持列名而不支持索引名,好在留空可以达到相同的目的 + .on_conflict(OnConflict::new().do_nothing().to_owned()) .do_nothing() .exec(connection) .await?; diff --git a/crates/bili_sync_migration/src/m20240505_130850_add_collection.rs b/crates/bili_sync_migration/src/m20240505_130850_add_collection.rs index c23646b..fd4f90b 100644 --- a/crates/bili_sync_migration/src/m20240505_130850_add_collection.rs +++ b/crates/bili_sync_migration/src/m20240505_130850_add_collection.rs @@ -87,18 +87,10 @@ impl MigrationTrait for Migration { .to_owned(), ) .await?; - manager - .create_index( - Index::create() - .table(Video::Table) - .name("idx_video_cid_fid_bvid") - .col(Video::CollectionId) - .col(Video::FavoriteId) - .col(Video::Bvid) - .unique() - .to_owned(), - ) - .await + // 在唯一索引中,NULL 不等于 NULL,所以需要使用 ifnull 函数排除空的情况 + db.execute_unprepared("CREATE UNIQUE INDEX `idx_video_cid_fid_bvid` ON `video` (ifnull(`collection_id`, -1), ifnull(`favorite_id`, -1), `bvid`)") + .await?; + Ok(()) } async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {