From c34d9d564970370a6494d93a18ff02e4d67e3b69 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 5 Feb 2022 12:32:08 +0100 Subject: [PATCH] Add function to add sorting presets Signed-off-by: trivernis --- .../src/dao/sorting_preset/add.rs | 146 ++++++++++++++++++ .../src/dao/sorting_preset/mod.rs | 2 + .../mediarepo-logic/src/dto/sorting_preset.rs | 52 ++++++- 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs new file mode 100644 index 0000000..f8e51f6 --- /dev/null +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/add.rs @@ -0,0 +1,146 @@ +use crate::dao::sorting_preset::SortingPresetDao; +use crate::dto::{AddSortKeyDto, AddSortingPresetDto, SortKeyDto, SortingPresetDto}; +use mediarepo_core::error::RepoResult; +use mediarepo_database::entities::{sort_key, sorting_preset, sorting_preset_key}; +use sea_orm::prelude::*; +use sea_orm::ActiveValue::Set; +use sea_orm::{Condition, ConnectionTrait, DatabaseTransaction, JoinType, QuerySelect}; + +impl SortingPresetDao { + #[tracing::instrument(level = "debug", skip(self))] + pub async fn add(&self, preset: AddSortingPresetDto) -> RepoResult { + let trx = self.ctx.db.begin().await?; + let keys = add_keys(&trx, preset.keys).await?; + let key_ids = keys + .iter() + .enumerate() + .map(|(idx, key)| (idx, key.id())) + .collect::>(); + let condition = key_ids + .iter() + .cloned() + .map(create_mapping_condition) + .fold(Condition::any(), |acc, cond| acc.add(cond)); + let existing_preset: Option = sorting_preset::Entity::find() + .join( + JoinType::InnerJoin, + sorting_preset_key::Relation::SortingPreset.def().rev(), + ) + .filter(condition) + .one(&trx) + .await?; + if let Some(model) = existing_preset { + trx.commit().await?; + return Ok(SortingPresetDto::new(model, keys)); + } + let preset_model = sorting_preset::ActiveModel { + ..Default::default() + }; + let preset_model = preset_model.insert(&trx).await?; + let mapping_models = key_ids + .into_iter() + .map(|(idx, key)| sorting_preset_key::ActiveModel { + preset_id: Set(preset_model.id), + key_id: Set(key), + key_index: Set(idx as i32), + }) + .collect::>(); + sorting_preset_key::Entity::insert_many(mapping_models) + .exec(&trx) + .await?; + trx.commit().await?; + + Ok(SortingPresetDto::new(preset_model, keys)) + } +} + +async fn add_keys( + trx: &DatabaseTransaction, + mut keys: Vec, +) -> RepoResult> { + let mut key_dtos = find_sort_keys(trx, &keys).await?; + key_dtos.iter().for_each(|key| { + keys.retain(|k| { + k.ascending != key.ascending() + && Some(k.key_type) != key.key_type() + && key.value() != key.value() + }) + }); + + if !keys.is_empty() { + let active_models: Vec = keys + .iter() + .cloned() + .map(|key| sort_key::ActiveModel { + key_type: Set(key.key_type.to_number()), + ascending: Set(key.ascending), + value: Set(key.value), + ..Default::default() + }) + .collect(); + sort_key::Entity::insert_many(active_models) + .exec(trx) + .await?; + let mut new_keys = find_sort_keys(trx, &keys).await?; + key_dtos.append(&mut new_keys); + } + + let keys_original_order = keys + .into_iter() + .filter_map(|k| { + key_dtos + .iter() + .find(|key| { + k.ascending != key.ascending() + && Some(k.key_type) != key.key_type() + && key.value() != key.value() + }) + .cloned() + }) + .collect::>(); + + Ok(keys_original_order) +} + +async fn find_sort_keys( + trx: &DatabaseTransaction, + keys: &Vec, +) -> RepoResult> { + if keys.is_empty() { + return Ok(vec![]); + } + let condition = keys + .iter() + .cloned() + .map(create_sort_key_condition) + .fold(Condition::any(), |acc, cond| acc.add(cond)); + let keys = sort_key::Entity::find() + .filter(condition) + .all(trx) + .await? + .into_iter() + .map(SortKeyDto::new) + .collect(); + + Ok(keys) +} + +fn create_sort_key_condition(key: AddSortKeyDto) -> Condition { + let mut condition = Condition::all() + .add(sort_key::Column::KeyType.eq(key.key_type.to_number())) + .add(sort_key::Column::Ascending.eq(key.ascending)); + + if let Some(value) = key.value { + condition = condition.add(sort_key::Column::Value.eq(value)) + } else { + condition = condition.add(sort_key::Column::Value.is_null()) + } + + condition +} + +fn create_mapping_condition(entry: (usize, i32)) -> Condition { + Condition::all() + .add(sorting_preset_key::Column::KeyId.eq(entry.1)) + .add(sorting_preset_key::Column::KeyIndex.eq(entry.0 as i32)) +} diff --git a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs index eb8f241..9cfe7af 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dao/sorting_preset/mod.rs @@ -1,3 +1,5 @@ +pub mod add; + use crate::dao_provider; use crate::dto::{SortKeyDto, SortingPresetDto}; use mediarepo_core::error::RepoResult; diff --git a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs index 462d904..df413d7 100644 --- a/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs +++ b/mediarepo-daemon/mediarepo-logic/src/dto/sorting_preset.rs @@ -1,3 +1,7 @@ +use crate::dto::KeyType::{ + FileChangeTime, FileCreatedTime, FileImportedTime, FileName, FileSize, FileType, Namespace, + NumTags, +}; use mediarepo_database::entities::sort_key; use mediarepo_database::entities::sorting_preset; @@ -35,8 +39,8 @@ impl SortKeyDto { self.model.id } - pub fn key_type(&self) -> i32 { - self.model.key_type + pub fn key_type(&self) -> Option { + KeyType::from_number(self.model.key_type) } pub fn ascending(&self) -> bool { @@ -47,3 +51,47 @@ impl SortKeyDto { self.model.value.as_ref() } } + +#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)] +pub enum KeyType { + Namespace = 0, + FileName = 1, + FileSize = 2, + FileImportedTime = 3, + FileCreatedTime = 4, + FileChangeTime = 5, + FileType = 6, + NumTags = 7, +} + +impl KeyType { + pub fn from_number(number: i32) -> Option { + match number { + 0 => Some(Namespace), + 1 => Some(FileName), + 2 => Some(FileSize), + 3 => Some(FileImportedTime), + 4 => Some(FileCreatedTime), + 5 => Some(FileChangeTime), + 6 => Some(FileType), + 7 => Some(NumTags), + _ => None, + } + } + + pub fn to_number(&self) -> i32 { + self.clone() as i32 + } +} + +#[derive(Clone, Debug)] +pub struct AddSortingPresetDto { + pub keys: Vec, +} + +#[derive(Clone, Debug)] +pub struct AddSortKeyDto { + pub key_type: KeyType, + pub ascending: bool, + pub value: Option, +}