diff --git a/mediarepo-daemon/Cargo.lock b/mediarepo-daemon/Cargo.lock index 4fb499c..b1820bd 100644 --- a/mediarepo-daemon/Cargo.lock +++ b/mediarepo-daemon/Cargo.lock @@ -848,7 +848,7 @@ dependencies = [ [[package]] name = "mediarepo-api" version = "0.1.0" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=476b9d152457f78c73f6f6a36c2421cbce9c9194#476b9d152457f78c73f6f6a36c2421cbce9c9194" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=822abb32a1aa35f209f01a6bafc3106f56d11ddc#822abb32a1aa35f209f01a6bafc3106f56d11ddc" dependencies = [ "chrono", "serde", @@ -883,6 +883,7 @@ dependencies = [ "mediarepo-core", "sea-orm", "sqlx", + "tracing", ] [[package]] @@ -909,6 +910,7 @@ dependencies = [ "compare", "mediarepo-api", "mediarepo-core", + "mediarepo-database", "mediarepo-model", "serde", "tokio", diff --git a/mediarepo-daemon/mediarepo-database/Cargo.lock b/mediarepo-daemon/mediarepo-database/Cargo.lock index 3c71dac..d5fe54b 100644 --- a/mediarepo-daemon/mediarepo-database/Cargo.lock +++ b/mediarepo-daemon/mediarepo-database/Cargo.lock @@ -764,6 +764,7 @@ dependencies = [ "mediarepo-core", "sea-orm", "sqlx", + "tracing", ] [[package]] diff --git a/mediarepo-daemon/mediarepo-database/Cargo.toml b/mediarepo-daemon/mediarepo-database/Cargo.toml index 080289e..425ca87 100644 --- a/mediarepo-daemon/mediarepo-database/Cargo.toml +++ b/mediarepo-daemon/mediarepo-database/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" [dependencies] chrono = "0.4.19" +tracing = "0.1.29" [dependencies.mediarepo-core] path = "../mediarepo-core" diff --git a/mediarepo-daemon/mediarepo-database/src/queries/tags.rs b/mediarepo-daemon/mediarepo-database/src/queries/tags.rs index e96755d..52a3095 100644 --- a/mediarepo-daemon/mediarepo-database/src/queries/tags.rs +++ b/mediarepo-daemon/mediarepo-database/src/queries/tags.rs @@ -1,43 +1,53 @@ -use crate::entities::hash; -use crate::entities::hash_tag; -use crate::entities::namespace; -use crate::entities::tag; -use sea_orm::prelude::*; -use sea_orm::sea_query::Query; -use sea_orm::{DatabaseConnection, JoinType}; +use mediarepo_core::error::RepoResult; +use sea_orm::DbBackend; +use sea_orm::FromQueryResult; +use sea_orm::{DatabaseConnection, Statement}; use std::collections::HashMap; -/* +use std::iter::FromIterator; + +#[derive(Debug, FromQueryResult)] +struct HashNamespaceTags { + hash_id: i64, + namespace: String, + tag: String, +} + +#[tracing::instrument(level = "debug", skip_all)] pub async fn get_hashes_with_namespaced_tags( - db: DatabaseConnection, + db: &DatabaseConnection, hash_ids: Vec, -) -> HashMap> { - Query::select() - .expr(hash_tag::Column::HashId) - .expr(tag::Column::Name) - .expr(namespace::Column::Name) - .from(tag::Entity) - .join( - JoinType::LeftJoin, - hash_tag::Entity, - hash_tag::Column::TagId.eq(tag::Column::Id), - ) - .join( - JoinType::InnerJoin, - namespace::Entity, - tag::Column::NamespaceId.eq(namespace::Column::Id), - ) - .build(&db) - .await?; - let tags: Vec<(tag::Model, Option)> = tag::Entity::find() - .find_also_related(namespace::Entity) - .join(JoinType::LeftJoin, hash_tag::Relation::Tag.def().rev()) - .join(JoinType::InnerJoin, hash_tag::Relation::Hash.def()) - .filter(hash::Column::Id.eq(self.hash.id)) - .all(&self.db) +) -> RepoResult>> { + let hash_namespace_tags: Vec = + HashNamespaceTags::find_by_statement(Statement::from_sql_and_values( + DbBackend::Sqlite, + format!( + r#"SELECT htm.hash_id, n.name as namespace, t.name as tag + FROM hash_tag_mappings htm + INNER JOIN tags t on htm.tag_id = t.id + JOIN namespaces n on t.namespace_id = n.id + WHERE t.namespace_id IS NOT NULL + AND htm.hash_id IN ({});"#, + hash_ids + .into_iter() + .fold(String::new(), |acc, val| format!("{}{},", acc, val)) + .trim_end_matches(",") + ) + .as_str(), + vec![], + )) + .all(&db) .await?; - let tags = tags - .into_iter() - .map(|(tag, namespace)| Tag::new(self.db.clone(), tag, namespace)) - .collect(); + let mut hash_namespaces: HashMap> = HashMap::new(); + for hnt in hash_namespace_tags { + if let Some(entry) = hash_namespaces.get_mut(&hnt.hash_id) { + entry.insert(hnt.namespace, hnt.tag); + } else { + hash_namespaces.insert( + hnt.hash_id, + HashMap::from_iter(vec![(hnt.namespace, hnt.tag)].into_iter()), + ); + } + } + + Ok(hash_namespaces) } -*/ diff --git a/mediarepo-daemon/mediarepo-model/Cargo.lock b/mediarepo-daemon/mediarepo-model/Cargo.lock index 95bcf21..2680612 100644 --- a/mediarepo-daemon/mediarepo-model/Cargo.lock +++ b/mediarepo-daemon/mediarepo-model/Cargo.lock @@ -764,6 +764,7 @@ dependencies = [ "mediarepo-core", "sea-orm", "sqlx", + "tracing", ] [[package]] diff --git a/mediarepo-daemon/mediarepo-model/src/file.rs b/mediarepo-daemon/mediarepo-model/src/file.rs index 398ad0f..71d9659 100644 --- a/mediarepo-daemon/mediarepo-model/src/file.rs +++ b/mediarepo-daemon/mediarepo-model/src/file.rs @@ -169,6 +169,11 @@ impl File { &self.hash.value } + /// Returns the hash id of the file + pub fn hash_id(&self) -> i64 { + self.hash.id + } + /// Returns the type of the file pub fn file_type(&self) -> FileType { match self.model.file_type { diff --git a/mediarepo-daemon/mediarepo-model/src/repo.rs b/mediarepo-daemon/mediarepo-model/src/repo.rs index 62acb42..24e6d32 100644 --- a/mediarepo-daemon/mediarepo-model/src/repo.rs +++ b/mediarepo-daemon/mediarepo-model/src/repo.rs @@ -40,6 +40,11 @@ impl Repo { Ok(Self::new(db)) } + /// Returns the database of the repo for raw sql queries + pub fn db(&self) -> &DatabaseConnection { + &self.db + } + /// Returns all available storages #[tracing::instrument(level = "debug", skip(self))] pub async fn storages(&self) -> RepoResult> { diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.lock b/mediarepo-daemon/mediarepo-socket/Cargo.lock index 416b4da..1c7b68a 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.lock +++ b/mediarepo-daemon/mediarepo-socket/Cargo.lock @@ -770,7 +770,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "mediarepo-api" version = "0.1.0" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=476b9d152457f78c73f6f6a36c2421cbce9c9194#476b9d152457f78c73f6f6a36c2421cbce9c9194" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=822abb32a1aa35f209f01a6bafc3106f56d11ddc#822abb32a1aa35f209f01a6bafc3106f56d11ddc" dependencies = [ "chrono", "serde", @@ -805,6 +805,7 @@ dependencies = [ "mediarepo-core", "sea-orm", "sqlx", + "tracing", ] [[package]] @@ -831,6 +832,7 @@ dependencies = [ "compare", "mediarepo-api", "mediarepo-core", + "mediarepo-database", "mediarepo-model", "serde", "tokio", diff --git a/mediarepo-daemon/mediarepo-socket/Cargo.toml b/mediarepo-daemon/mediarepo-socket/Cargo.toml index 733d461..0a6ab24 100644 --- a/mediarepo-daemon/mediarepo-socket/Cargo.toml +++ b/mediarepo-daemon/mediarepo-socket/Cargo.toml @@ -13,6 +13,9 @@ compare = "0.1.0" [dependencies.mediarepo-core] path = "../mediarepo-core" +[dependencies.mediarepo-database] +path = "../mediarepo-database" + [dependencies.mediarepo-model] path = "../mediarepo-model" @@ -30,4 +33,4 @@ features = ["tokio-executor"] [dependencies.mediarepo-api] git = "https://github.com/Trivernis/mediarepo-api.git" -rev = "476b9d152457f78c73f6f6a36c2421cbce9c9194" \ No newline at end of file +rev = "822abb32a1aa35f209f01a6bafc3106f56d11ddc" \ No newline at end of file diff --git a/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs index 0721fed..3255507 100644 --- a/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs +++ b/mediarepo-daemon/mediarepo-socket/src/namespaces/files.rs @@ -5,13 +5,12 @@ use mediarepo_api::types::files::{ AddFileRequest, FileMetadataResponse, FindFilesByTagsRequest, GetFileThumbnailsRequest, ReadFileRequest, SortDirection, SortKey, ThumbnailMetadataResponse, }; -use mediarepo_core::error::{RepoError, RepoResult}; -use mediarepo_core::futures::future; +use mediarepo_core::error::RepoError; use mediarepo_core::rmp_ipc::prelude::*; +use mediarepo_database::queries::tags::get_hashes_with_namespaced_tags; use mediarepo_model::file::File; use std::cmp::Ordering; use std::collections::HashMap; -use std::iter::FromIterator; use std::path::PathBuf; use tokio::io::AsyncReadExt; @@ -60,35 +59,21 @@ impl FilesNamespace { let repo = get_repo_from_context(ctx).await; let tags = req.tags.into_iter().map(|t| (t.name, t.negate)).collect(); let mut files = repo.find_files_by_tags(tags).await?; + let hash_ids = files.iter().map(|f| f.hash_id()).collect(); - let files_nsp: HashMap> = HashMap::from_iter( - future::join_all(files.iter().map(|f| { - let file = f.clone(); - async move { - let result: RepoResult<(String, HashMap)> = - Ok((f.hash().clone(), get_namespaces_for_file(&file).await?)); - result - } - })) - .await - .into_iter() - .filter_map(|r| match r { - Ok(value) => Some(value), - Err(e) => { - tracing::error!("{:?}", e); - None - } - }), - ); + let hash_nsp: HashMap> = + get_hashes_with_namespaced_tags(repo.db(), hash_ids).await?; let sort_expression = req.sort_expression; + tracing::debug!("sort_expression = {:?}", sort_expression); + let empty_map = HashMap::with_capacity(0); files.sort_by(|a, b| { compare_files( a, - files_nsp.get(a.hash()).unwrap(), + hash_nsp.get(&a.hash_id()).unwrap_or(&empty_map), b, - files_nsp.get(b.hash()).unwrap(), + hash_nsp.get(&b.hash_id()).unwrap_or(&empty_map), &sort_expression, ) }); @@ -205,8 +190,8 @@ fn compare_files( for sort_key in expression { let ordering = match sort_key { SortKey::Namespace(namespace) => { - let tag_a = nsp_a.get(&namespace.tag); - let tag_b = nsp_b.get(&namespace.tag); + let tag_a = nsp_a.get(&namespace.name); + let tag_b = nsp_b.get(&namespace.name); if let (Some(a), Some(b)) = ( tag_a.and_then(|a| a.parse::().ok()), @@ -252,17 +237,6 @@ fn compare_files( Ordering::Equal } -async fn get_namespaces_for_file(file: &File) -> RepoResult> { - let tags = file.tags().await?; - let namespaces: HashMap = - HashMap::from_iter(tags.into_iter().filter_map(|tag| { - let namespace = tag.namespace()?; - Some((namespace.name().clone(), tag.name().clone())) - })); - - Ok(namespaces) -} - fn compare_opts(opt_a: Option, opt_b: Option) -> Ordering { let cmp = compare::natural(); if let (Some(a), Some(b)) = (&opt_a, &opt_b) {