feat: 实现仅失败、仅成功、仅等待的筛选 (#610)
This commit is contained in:
@@ -1,9 +1,22 @@
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use itertools::Itertools;
|
||||
use sea_orm::{ConnectionTrait, DatabaseTransaction};
|
||||
use sea_orm::{Condition, ConnectionTrait, DatabaseTransaction};
|
||||
|
||||
use crate::api::request::StatusFilter;
|
||||
use crate::api::response::{PageInfo, SimplePageInfo, SimpleVideoInfo, VideoInfo};
|
||||
use crate::utils::status::VideoStatus;
|
||||
|
||||
impl StatusFilter {
|
||||
pub fn to_video_query(&self) -> Condition {
|
||||
let query_builder = VideoStatus::query_builder();
|
||||
match self {
|
||||
Self::Failed => query_builder.failed(),
|
||||
Self::Succeeded => query_builder.succeeded(),
|
||||
Self::Waiting => query_builder.waiting(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VideoRecord {
|
||||
fn as_id_status_tuple(&self) -> (i32, u32);
|
||||
|
||||
@@ -4,6 +4,14 @@ use validator::Validate;
|
||||
|
||||
use crate::bilibili::CollectionType;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum StatusFilter {
|
||||
Failed,
|
||||
Succeeded,
|
||||
Waiting,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct VideosRequest {
|
||||
pub collection: Option<i32>,
|
||||
@@ -11,8 +19,7 @@ pub struct VideosRequest {
|
||||
pub submission: Option<i32>,
|
||||
pub watch_later: Option<i32>,
|
||||
pub query: Option<String>,
|
||||
#[serde(default)]
|
||||
pub failed_only: bool,
|
||||
pub status_filter: Option<StatusFilter>,
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
}
|
||||
@@ -30,8 +37,7 @@ pub struct ResetFilteredVideoStatusRequest {
|
||||
pub submission: Option<i32>,
|
||||
pub watch_later: Option<i32>,
|
||||
pub query: Option<String>,
|
||||
#[serde(default)]
|
||||
pub failed_only: bool,
|
||||
pub status_filter: Option<StatusFilter>,
|
||||
#[serde(default)]
|
||||
pub force: bool,
|
||||
}
|
||||
@@ -68,8 +74,7 @@ pub struct UpdateFilteredVideoStatusRequest {
|
||||
pub submission: Option<i32>,
|
||||
pub watch_later: Option<i32>,
|
||||
pub query: Option<String>,
|
||||
#[serde(default)]
|
||||
pub failed_only: bool,
|
||||
pub status_filter: Option<StatusFilter>,
|
||||
#[serde(default)]
|
||||
#[validate(nested)]
|
||||
pub video_updates: Vec<StatusUpdate>,
|
||||
|
||||
@@ -62,8 +62,8 @@ pub async fn get_videos(
|
||||
.or(video::Column::Bvid.contains(query_word)),
|
||||
);
|
||||
}
|
||||
if params.failed_only {
|
||||
query = query.filter(VideoStatus::query_builder().any_failed())
|
||||
if let Some(status_filter) = params.status_filter {
|
||||
query = query.filter(status_filter.to_video_query());
|
||||
}
|
||||
let total_count = query.clone().count(&db).await?;
|
||||
let (page, page_size) = if let (Some(page), Some(page_size)) = (params.page, params.page_size) {
|
||||
@@ -221,8 +221,8 @@ pub async fn reset_filtered_video_status(
|
||||
.or(video::Column::Bvid.contains(query_word)),
|
||||
);
|
||||
}
|
||||
if request.failed_only {
|
||||
query = query.filter(VideoStatus::query_builder().any_failed());
|
||||
if let Some(status_filter) = request.status_filter {
|
||||
query = query.filter(status_filter.to_video_query());
|
||||
}
|
||||
let all_videos = query.into_partial_model::<SimpleVideoInfo>().all(&db).await?;
|
||||
let all_pages = page::Entity::find()
|
||||
@@ -357,8 +357,8 @@ pub async fn update_filtered_video_status(
|
||||
.or(video::Column::Bvid.contains(query_word)),
|
||||
);
|
||||
}
|
||||
if request.failed_only {
|
||||
query = query.filter(VideoStatus::query_builder().any_failed())
|
||||
if let Some(status_filter) = request.status_filter {
|
||||
query = query.filter(status_filter.to_video_query());
|
||||
}
|
||||
let mut all_videos = query.into_partial_model::<SimpleVideoInfo>().all(&db).await?;
|
||||
let mut all_pages = page::Entity::find()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bili_sync_entity::{page, video};
|
||||
use bili_sync_migration::ExprTrait;
|
||||
use bili_sync_migration::{ExprTrait, IntoCondition};
|
||||
use sea_orm::sea_query::Expr;
|
||||
use sea_orm::{ColumnTrait, Condition};
|
||||
|
||||
@@ -213,7 +213,17 @@ impl<const N: usize, C: ColumnTrait> StatusQueryBuilder<N, C> {
|
||||
Self { column }
|
||||
}
|
||||
|
||||
pub fn any_failed(&self) -> Condition {
|
||||
/// 完成状态:所有子任务的状态都是成功
|
||||
pub fn succeeded(&self) -> Condition {
|
||||
let mut condition = Condition::all();
|
||||
for offset in 0..N as i32 {
|
||||
condition = condition.add(Expr::col(self.column).right_shift(offset * 3).bit_and(7).eq(7))
|
||||
}
|
||||
condition
|
||||
}
|
||||
|
||||
/// 失败状态:存在任何失败的子任务
|
||||
pub fn failed(&self) -> Condition {
|
||||
let mut condition = Condition::any();
|
||||
for offset in 0..N as i32 {
|
||||
condition = condition.add(
|
||||
@@ -225,6 +235,15 @@ impl<const N: usize, C: ColumnTrait> StatusQueryBuilder<N, C> {
|
||||
}
|
||||
condition
|
||||
}
|
||||
|
||||
/// 等待状态:所有子任务的状态都不是失败,且其中存在未开始
|
||||
pub fn waiting(&self) -> Condition {
|
||||
let mut condition = Condition::any();
|
||||
for offset in 0..N as i32 {
|
||||
condition = condition.add(Expr::col(self.column).right_shift(offset * 3).bit_and(7).eq(0))
|
||||
}
|
||||
condition.and(self.failed().not()).into_condition()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user