filter for media files list endpoint (global, non-scoped)

This commit is contained in:
Brandon Thomas committed 2024-04-29 18:38:38 -04:00
1 parent da1595a1e9
commit d33fd77e7a
2 files changed
+94 -16

No files matched your search

@@ -1,3 +1,4 @@
use std::collections::HashSet;
use chrono::{DateTime, Utc};
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
use sqlx::mysql::MySqlRow;
@@ -84,7 +85,9 @@ pub struct MediaFileListItem {
pub struct ListMediaFilesArgs<'a> {
pub limit: usize,
pub maybe_filter_media_type: Option<MediaFileType>,
pub maybe_filter_media_types: Option<&'a HashSet<MediaFileType>>,
pub maybe_filter_media_classes: Option<&'a HashSet<MediaFileClass>>,
pub maybe_filter_engine_categories: Option<&'a HashSet<MediaFileEngineCategory>>,
pub maybe_offset: Option<usize>,
pub cursor_is_reversed: bool,
pub sort_ascending: bool,
@@ -95,7 +98,9 @@ pub struct ListMediaFilesArgs<'a> {
pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult<MediaFileListPage> {
let mut query = query_builder(
args.maybe_filter_media_type,
args.maybe_filter_media_types,
args.maybe_filter_media_classes,
args.maybe_filter_engine_categories,
args.limit,
args.maybe_offset,
args.cursor_is_reversed,
@@ -166,7 +171,9 @@ pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult<Medi
}
fn query_builder<'a>(
maybe_filter_media_type: Option<MediaFileType>,
maybe_filter_media_types: Option<&HashSet<MediaFileType>>,
maybe_filter_media_classes: Option<&HashSet<MediaFileClass>>,
maybe_filter_engine_categories: Option<&HashSet<MediaFileEngineCategory>>,
limit: usize,
maybe_offset: Option<usize>,
cursor_is_reversed: bool,
@@ -248,18 +255,70 @@ LEFT OUTER JOIN prompts
let mut first_predicate_added = false;
if let Some(media_type) = maybe_filter_media_type {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
if let Some(media_types) = maybe_filter_media_types {
// NB: `WHERE IN` comma separated syntax will be wrong if list has zero length
// We'll skip the predicate if the list isn't empty.
if !media_types.is_empty() {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" m.media_type IN ( ");
let mut separated = query_builder.separated(", ");
for media_type in media_types.iter() {
separated.push_bind(media_type.to_str());
}
separated.push_unseparated(") ");
}
}
if let Some(media_classes) = maybe_filter_media_classes {
// NB: `WHERE IN` comma separated syntax will be wrong if list has zero length
// We'll skip the predicate if the list isn't empty.
if !media_classes.is_empty() {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" m.media_class IN ( ");
let mut separated = query_builder.separated(", ");
for media_class in media_classes.iter() {
separated.push_bind(media_class.to_str());
}
separated.push_unseparated(") ");
}
}
if let Some(engine_categories) = maybe_filter_engine_categories {
// NB: `WHERE IN` comma separated syntax will be wrong if list has zero length
// We'll skip the predicate if the list isn't empty.
if !engine_categories.is_empty() {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" m.maybe_engine_category IN ( ");
let mut separated = query_builder.separated(", ");
for engine_category in engine_categories.iter() {
separated.push_bind(engine_category.to_str());
}
separated.push_unseparated(") ");
}
// FIXME: Binding shouldn't require to_str().
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
// incorrect binding and runtime error.
query_builder.push(" m.media_type = ");
query_builder.push_bind(media_type.to_str());
}
match view_as {
@@ -27,6 +27,9 @@ use crate::http_server::common_responses::media_file_cover_image_details::{Media
use crate::http_server::common_responses::media_file_origin_details::MediaFileOriginDetails;
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats;
use crate::http_server::endpoints::media_files::list::helpers::get_scoped_engine_categories::get_scoped_engine_categories;
use crate::http_server::endpoints::media_files::list::helpers::get_scoped_media_classes::get_scoped_media_classes;
use crate::http_server::endpoints::media_files::list::helpers::get_scoped_media_types::get_scoped_media_types;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::server_state::ServerState;
use crate::util::allowed_explore_media_access::allowed_explore_media_access;
@@ -39,7 +42,17 @@ pub struct ListMediaFilesQueryParams {
pub cursor: Option<String>,
pub cursor_is_reversed: Option<bool>,
pub filter_media_type: Option<MediaFileType>,
/// NB: This can be one (or more comma-separated values) from `MediaFileType`.
/// ?filter_media_type=image or ?filter_media_type=image,video (etc.)
pub filter_media_type: Option<String>,
/// NB: This can be one (or more comma-separated values) from `MediaFileClass`.
/// ?filter_media_type=animation or ?filter_media_type=animation,character (etc.)
pub filter_media_classes: Option<String>,
/// NB: This can be one (or more comma-separated values) from `MediaFileEngineCategory`.
/// ?filter_engine_categories=scene or ?filter_engine_categories=animation,character,object (etc.)
pub filter_engine_categories: Option<String>,
}
#[derive(Serialize, ToSchema)]
@@ -213,9 +226,15 @@ pub async fn list_media_files_handler(
ViewAs::AnotherUser
};
let mut maybe_filter_media_types = get_scoped_media_types(query.filter_media_type.as_deref());
let mut maybe_filter_media_classes = get_scoped_media_classes(query.filter_media_classes.as_deref());
let mut maybe_filter_engine_categories = get_scoped_engine_categories(query.filter_engine_categories.as_deref());
let query_results = list_media_files(ListMediaFilesArgs {
limit,
maybe_filter_media_type: query.filter_media_type,
maybe_filter_media_types: maybe_filter_media_types.as_ref(),
maybe_filter_media_classes: maybe_filter_media_classes.as_ref(),
maybe_filter_engine_categories: maybe_filter_engine_categories.as_ref(),
maybe_offset: cursor,
cursor_is_reversed,
sort_ascending,