december improvements #2
@@ -138,6 +138,7 @@ function MediaPage() {
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="original_filename">Filename</SelectItem>
|
<SelectItem value="original_filename">Filename</SelectItem>
|
||||||
|
<SelectItem value="tag.name">Tag</SelectItem>
|
||||||
<SelectItem value="metadata.Make">Make</SelectItem>
|
<SelectItem value="metadata.Make">Make</SelectItem>
|
||||||
<SelectItem value="metadata.Model">Model</SelectItem>
|
<SelectItem value="metadata.Model">Model</SelectItem>
|
||||||
<SelectItem value="metadata.ISO">ISO</SelectItem>
|
<SelectItem value="metadata.ISO">ISO</SelectItem>
|
||||||
|
|||||||
@@ -273,6 +273,55 @@ impl FilterStrategy for MetadataFilterStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TagFilterStrategy;
|
||||||
|
|
||||||
|
impl FilterStrategy for TagFilterStrategy {
|
||||||
|
fn can_handle(&self, field: &str) -> bool {
|
||||||
|
field == "tag.name"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_join<'a>(
|
||||||
|
&self,
|
||||||
|
_query: &mut SqlxQueryBuilder<'a, sqlx::Postgres>,
|
||||||
|
_field: &'a str,
|
||||||
|
) -> CoreResult<()> {
|
||||||
|
// We use EXISTS subqueries in apply_condition, so no main query join is needed.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_condition<'a>(
|
||||||
|
&self,
|
||||||
|
query: &mut SqlxQueryBuilder<'a, sqlx::Postgres>,
|
||||||
|
condition: &'a libertas_core::schema::FilterCondition,
|
||||||
|
) -> CoreResult<()> {
|
||||||
|
use libertas_core::schema::FilterOperator;
|
||||||
|
|
||||||
|
let op = match condition.operator {
|
||||||
|
FilterOperator::Eq => "=",
|
||||||
|
FilterOperator::Neq => "!=",
|
||||||
|
FilterOperator::Like => "ILIKE",
|
||||||
|
FilterOperator::Gt => ">",
|
||||||
|
FilterOperator::Lt => "<",
|
||||||
|
FilterOperator::Gte => ">=",
|
||||||
|
FilterOperator::Lte => "<=",
|
||||||
|
};
|
||||||
|
|
||||||
|
query.push(" AND EXISTS (SELECT 1 FROM media_tags mt JOIN tags t ON mt.tag_id = t.id WHERE mt.media_id = media.id AND t.name ");
|
||||||
|
query.push(op);
|
||||||
|
query.push(" ");
|
||||||
|
|
||||||
|
if condition.operator == FilterOperator::Like {
|
||||||
|
query.push_bind(format!("%{}%", condition.value));
|
||||||
|
} else {
|
||||||
|
query.push_bind(&condition.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
query.push(" ) ");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait QueryBuilder<T> {
|
pub trait QueryBuilder<T> {
|
||||||
fn apply_options_to_query<'a>(
|
fn apply_options_to_query<'a>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -25,17 +25,22 @@ impl PostgresMediaRepository {
|
|||||||
.allowed_sort_columns
|
.allowed_sort_columns
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| vec!["created_at".to_string(), "original_filename".to_string()]);
|
.unwrap_or_else(|| vec!["created_at".to_string(), "original_filename".to_string()]);
|
||||||
|
|
||||||
allowed_columns.push("date_taken".to_string());
|
allowed_columns.push("date_taken".to_string());
|
||||||
|
|
||||||
let sort_strategies: Vec<Box<dyn crate::query_builder::SortStrategy>> = vec![
|
let sort_strategies: Vec<Box<dyn crate::query_builder::SortStrategy>> = vec![
|
||||||
Box::new(crate::query_builder::StandardSortStrategy::new(allowed_columns.clone())),
|
Box::new(crate::query_builder::StandardSortStrategy::new(
|
||||||
|
allowed_columns.clone(),
|
||||||
|
)),
|
||||||
Box::new(crate::query_builder::MetadataSortStrategy),
|
Box::new(crate::query_builder::MetadataSortStrategy),
|
||||||
];
|
];
|
||||||
|
|
||||||
let filter_strategies: Vec<Box<dyn crate::query_builder::FilterStrategy>> = vec![
|
let filter_strategies: Vec<Box<dyn crate::query_builder::FilterStrategy>> = vec![
|
||||||
Box::new(crate::query_builder::StandardFilterStrategy::new(allowed_columns)),
|
Box::new(crate::query_builder::StandardFilterStrategy::new(
|
||||||
|
allowed_columns,
|
||||||
|
)),
|
||||||
Box::new(crate::query_builder::MetadataFilterStrategy),
|
Box::new(crate::query_builder::MetadataFilterStrategy),
|
||||||
|
Box::new(crate::query_builder::TagFilterStrategy),
|
||||||
];
|
];
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -119,15 +124,14 @@ impl MediaRepository for PostgresMediaRepository {
|
|||||||
) -> CoreResult<(Vec<Media>, i64)> {
|
) -> CoreResult<(Vec<Media>, i64)> {
|
||||||
let count_base_sql = "SELECT COUNT(DISTINCT media.id) as total FROM media";
|
let count_base_sql = "SELECT COUNT(DISTINCT media.id) as total FROM media";
|
||||||
let mut count_query = sqlx::QueryBuilder::new(count_base_sql);
|
let mut count_query = sqlx::QueryBuilder::new(count_base_sql);
|
||||||
|
|
||||||
count_query = self.query_builder.apply_joins(count_query, options)?;
|
count_query = self.query_builder.apply_joins(count_query, options)?;
|
||||||
|
|
||||||
count_query.push(" WHERE media.owner_id = ");
|
count_query.push(" WHERE media.owner_id = ");
|
||||||
count_query.push_bind(user_id);
|
count_query.push_bind(user_id);
|
||||||
|
|
||||||
let (mut count_query, metadata_filter_count) = self
|
let (mut count_query, metadata_filter_count) =
|
||||||
.query_builder
|
self.query_builder.apply_conditions(count_query, options)?;
|
||||||
.apply_conditions(count_query, options)?;
|
|
||||||
|
|
||||||
if metadata_filter_count > 0 {
|
if metadata_filter_count > 0 {
|
||||||
count_query.push(" GROUP BY media.id ");
|
count_query.push(" GROUP BY media.id ");
|
||||||
@@ -148,15 +152,14 @@ impl MediaRepository for PostgresMediaRepository {
|
|||||||
|
|
||||||
let data_base_sql = "SELECT media.id, media.owner_id, media.storage_path, media.original_filename, media.mime_type, media.hash, media.created_at, media.thumbnail_path, media.date_taken FROM media";
|
let data_base_sql = "SELECT media.id, media.owner_id, media.storage_path, media.original_filename, media.mime_type, media.hash, media.created_at, media.thumbnail_path, media.date_taken FROM media";
|
||||||
let mut data_query = sqlx::QueryBuilder::new(data_base_sql);
|
let mut data_query = sqlx::QueryBuilder::new(data_base_sql);
|
||||||
|
|
||||||
data_query = self.query_builder.apply_joins(data_query, options)?;
|
data_query = self.query_builder.apply_joins(data_query, options)?;
|
||||||
|
|
||||||
data_query.push(" WHERE media.owner_id = ");
|
data_query.push(" WHERE media.owner_id = ");
|
||||||
data_query.push_bind(user_id);
|
data_query.push_bind(user_id);
|
||||||
|
|
||||||
let (mut data_query, metadata_filter_count) = self
|
let (mut data_query, metadata_filter_count) =
|
||||||
.query_builder
|
self.query_builder.apply_conditions(data_query, options)?;
|
||||||
.apply_conditions(data_query, options)?;
|
|
||||||
|
|
||||||
if metadata_filter_count > 0 {
|
if metadata_filter_count > 0 {
|
||||||
data_query.push(" GROUP BY media.id ");
|
data_query.push(" GROUP BY media.id ");
|
||||||
@@ -192,15 +195,14 @@ impl MediaRepository for PostgresMediaRepository {
|
|||||||
JOIN face_regions fr ON media.id = fr.media_id
|
JOIN face_regions fr ON media.id = fr.media_id
|
||||||
";
|
";
|
||||||
let mut count_query = sqlx::QueryBuilder::new(count_base_sql);
|
let mut count_query = sqlx::QueryBuilder::new(count_base_sql);
|
||||||
|
|
||||||
count_query = self.query_builder.apply_joins(count_query, options)?;
|
count_query = self.query_builder.apply_joins(count_query, options)?;
|
||||||
|
|
||||||
count_query.push(" WHERE fr.person_id = ");
|
count_query.push(" WHERE fr.person_id = ");
|
||||||
count_query.push_bind(person_id);
|
count_query.push_bind(person_id);
|
||||||
|
|
||||||
let (mut count_query, _metadata_filter_count) = self
|
let (mut count_query, _metadata_filter_count) =
|
||||||
.query_builder
|
self.query_builder.apply_conditions(count_query, options)?;
|
||||||
.apply_conditions(count_query, options)?;
|
|
||||||
|
|
||||||
let total_items_result = count_query
|
let total_items_result = count_query
|
||||||
.build_query_scalar()
|
.build_query_scalar()
|
||||||
@@ -216,15 +218,14 @@ impl MediaRepository for PostgresMediaRepository {
|
|||||||
JOIN face_regions fr ON media.id = fr.media_id
|
JOIN face_regions fr ON media.id = fr.media_id
|
||||||
";
|
";
|
||||||
let mut data_query = sqlx::QueryBuilder::new(data_base_sql);
|
let mut data_query = sqlx::QueryBuilder::new(data_base_sql);
|
||||||
|
|
||||||
data_query = self.query_builder.apply_joins(data_query, options)?;
|
data_query = self.query_builder.apply_joins(data_query, options)?;
|
||||||
|
|
||||||
data_query.push(" WHERE fr.person_id = ");
|
data_query.push(" WHERE fr.person_id = ");
|
||||||
data_query.push_bind(person_id);
|
data_query.push_bind(person_id);
|
||||||
|
|
||||||
let (mut data_query, _metadata_filter_count) = self
|
let (mut data_query, _metadata_filter_count) =
|
||||||
.query_builder
|
self.query_builder.apply_conditions(data_query, options)?;
|
||||||
.apply_conditions(data_query, options)?;
|
|
||||||
|
|
||||||
data_query.push(" GROUP BY media.id ");
|
data_query.push(" GROUP BY media.id ");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user