From 44af5bc8d5a5f38bdb93dbc51873657e3d0662e1 Mon Sep 17 00:00:00 2001 From: angrynode Date: Fri, 29 May 2026 14:57:01 +0200 Subject: [PATCH 1/2] feat: Table operators are a thin wrapper around DatabaseOperator --- src/database/content_folder/folder_view.rs | 4 ++-- src/database/content_folder/operator.rs | 23 +++++++++------------- src/database/operator.rs | 7 ++----- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/database/content_folder/folder_view.rs b/src/database/content_folder/folder_view.rs index 9c8933a..6889bc7 100644 --- a/src/database/content_folder/folder_view.rs +++ b/src/database/content_folder/folder_view.rs @@ -15,7 +15,7 @@ pub struct FolderView { impl FolderView { /// Loads the top-most folder view, which is not a folder and may not have parents. - pub async fn index(operator: &ContentFolderOperator) -> Result { + pub async fn index(operator: &ContentFolderOperator<'_>) -> Result { let children = operator .list() .await? @@ -37,7 +37,7 @@ impl FolderView { /// - the requested ID does not exist // TODO: optimize with custom query pub async fn from_id( - operator: &ContentFolderOperator, + operator: &ContentFolderOperator<'_>, id: i32, ) -> Result { let list = operator.list().await?; diff --git a/src/database/content_folder/operator.rs b/src/database/content_folder/operator.rs index 6789f4c..9896d0f 100644 --- a/src/database/content_folder/operator.rs +++ b/src/database/content_folder/operator.rs @@ -2,6 +2,7 @@ use chrono::Utc; use sea_orm::*; use snafu::prelude::*; +use std::ops::Deref; use std::str::FromStr; use crate::database::operation::OperationLog; @@ -9,29 +10,23 @@ use crate::database::operation::OperationType; use crate::database::operation::Table; use crate::database::operator::DatabaseOperator; use crate::extractors::normalized_path::NormalizedPathComponent; -use crate::extractors::user::User; -use crate::state::AppState; use super::*; #[derive(Clone, Debug)] -pub struct ContentFolderOperator { - pub state: AppState, - pub user: Option, +pub struct ContentFolderOperator<'a> { + pub db: &'a DatabaseOperator, } -impl ContentFolderOperator { - pub fn new(state: AppState, user: Option) -> Self { - Self { state, user } - } +impl Deref for ContentFolderOperator<'_> { + type Target = DatabaseOperator; - pub fn db(&self) -> DatabaseOperator { - DatabaseOperator { - state: self.state.clone(), - user: self.user.clone(), - } + fn deref(&self) -> &DatabaseOperator { + self.db } +} +impl ContentFolderOperator<'_> { /// List content folders /// /// Should not fail, unless SQLite was corrupted for some reason. diff --git a/src/database/operator.rs b/src/database/operator.rs index b4115e3..a1580e3 100644 --- a/src/database/operator.rs +++ b/src/database/operator.rs @@ -13,10 +13,7 @@ impl DatabaseOperator { Self { state, user } } - pub fn content_folder(&self) -> ContentFolderOperator { - ContentFolderOperator { - state: self.state.clone(), - user: self.user.clone(), - } + pub fn content_folder<'a>(&'a self) -> ContentFolderOperator<'a> { + ContentFolderOperator { db: self } } } From fe2d1e92bd5ea2e1da182efe7eabf8b47ab3d9ba Mon Sep 17 00:00:00 2001 From: angrynode Date: Fri, 29 May 2026 15:10:45 +0200 Subject: [PATCH 2/2] feat: Common logging interface via TableOperator trait --- src/database/content_folder/operator.rs | 36 ++++++++----------- src/database/operator.rs | 48 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/database/content_folder/operator.rs b/src/database/content_folder/operator.rs index 9896d0f..6a51079 100644 --- a/src/database/content_folder/operator.rs +++ b/src/database/content_folder/operator.rs @@ -1,14 +1,11 @@ -use chrono::Utc; use sea_orm::*; use snafu::prelude::*; use std::ops::Deref; use std::str::FromStr; -use crate::database::operation::OperationLog; -use crate::database::operation::OperationType; use crate::database::operation::Table; -use crate::database::operator::DatabaseOperator; +use crate::database::operator::{DatabaseOperator, TableOperator}; use crate::extractors::normalized_path::NormalizedPathComponent; use super::*; @@ -26,6 +23,12 @@ impl Deref for ContentFolderOperator<'_> { } } +impl TableOperator for ContentFolderOperator<'_> { + fn table(&self) -> Table { + Table::ContentFolder + } +} + impl ContentFolderOperator<'_> { /// List content folders /// @@ -101,24 +104,13 @@ impl ContentFolderOperator<'_> { .context(IOSnafu)?; } - let operation_log = OperationLog { - user: self.user.clone(), - date: Utc::now(), - operation: ContentFolderOperation::Create { - id: model.id, - name: model.name.to_string(), - parent: parent.as_ref().map(|x| (x.id, x.name.to_string())), - } - .into(), - operation_type: OperationType::Create, - table: Table::ContentFolder, - }; - - self.state - .logger - .write(operation_log) - .await - .context(LoggerSnafu)?; + self.log_create(ContentFolderOperation::Create { + id: model.id, + name: model.name.to_string(), + parent: parent.as_ref().map(|x| (x.id, x.name.to_string())), + }) + .await + .context(LoggerSnafu)?; Ok(model) } diff --git a/src/database/operator.rs b/src/database/operator.rs index a1580e3..8bce469 100644 --- a/src/database/operator.rs +++ b/src/database/operator.rs @@ -1,6 +1,37 @@ +use chrono::Utc; + +use std::ops::Deref; + use crate::database::content_folder::ContentFolderOperator; +use crate::database::operation::{Operation, OperationLog, OperationType, Table}; use crate::extractors::user::User; use crate::state::AppState; +use crate::state::logger::LoggerError; + +pub trait TableOperator: Deref { + fn table(&self) -> Table; + + fn log_create( + &self, + operation: impl Into, + ) -> impl std::future::Future> { + self.log(self.table(), OperationType::Create, operation.into()) + } + + fn log_update( + &self, + operation: impl Into, + ) -> impl std::future::Future> { + self.log(self.table(), OperationType::Update, operation.into()) + } + + fn log_delete( + &self, + operation: impl Into, + ) -> impl std::future::Future> { + self.log(self.table(), OperationType::Delete, operation.into()) + } +} #[derive(Clone, Debug)] pub struct DatabaseOperator { @@ -13,6 +44,23 @@ impl DatabaseOperator { Self { state, user } } + pub async fn log( + &self, + table: Table, + operation_type: OperationType, + operation: Operation, + ) -> Result<(), LoggerError> { + let operation = OperationLog { + user: self.user.clone(), + date: Utc::now(), + operation, + operation_type, + table, + }; + + self.state.logger.write(operation).await + } + pub fn content_folder<'a>(&'a self) -> ContentFolderOperator<'a> { ContentFolderOperator { db: self } }