Add support for negated tag queries

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 7cf30cbfa1
commit b9bf5861b6

@ -841,7 +841,7 @@ dependencies = [
[[package]]
name = "mediarepo-api"
version = "0.1.0"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=af90986e88cc4ef7d797ecc9cfd0c306b2d4c7cd#af90986e88cc4ef7d797ecc9cfd0c306b2d4c7cd"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cb2b0e467b3554b07d04f98d9244d8e4952db68#6cb2b0e467b3554b07d04f98d9244d8e4952db68"
dependencies = [
"chrono",
"serde",

@ -90,20 +90,32 @@ impl File {
#[tracing::instrument(level = "debug", skip(db))]
pub(crate) async fn find_by_tags(
db: DatabaseConnection,
tag_ids: Vec<i64>,
tag_ids: Vec<(i64, bool)>,
) -> RepoResult<Vec<Self>> {
let mut condition = Condition::all();
for tag in tag_ids {
condition = condition.add(
hash::Column::Id.in_subquery(
Query::select()
.expr(Expr::col(hash_tag::Column::HashId))
.from(hash_tag::Entity)
.cond_where(hash_tag::Column::TagId.eq(tag))
.to_owned(),
),
);
for (tag, negated) in tag_ids {
condition = if negated {
condition.add(
hash::Column::Id.not_in_subquery(
Query::select()
.expr(Expr::col(hash_tag::Column::HashId))
.from(hash_tag::Entity)
.cond_where(hash_tag::Column::TagId.eq(tag))
.to_owned(),
),
)
} else {
condition.add(
hash::Column::Id.in_subquery(
Query::select()
.expr(Expr::col(hash_tag::Column::HashId))
.from(hash_tag::Entity)
.cond_where(hash_tag::Column::TagId.eq(tag))
.to_owned(),
),
)
}
}
let results: Vec<(hash::Model, Option<file::Model>)> = hash::Entity::find()
.find_also_related(file::Entity)

@ -9,8 +9,10 @@ use mediarepo_core::image_processing::ThumbnailSize;
use mediarepo_core::utils::parse_namespace_and_tag;
use mediarepo_database::get_database;
use sea_orm::DatabaseConnection;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Cursor;
use std::iter::FromIterator;
use std::path::PathBuf;
use tokio::fs::OpenOptions;
use tokio::io::BufReader;
@ -97,9 +99,23 @@ impl Repo {
/// Finds all files by a list of tags
#[tracing::instrument(level = "debug", skip(self))]
pub async fn find_files_by_tags(&self, tags: Vec<String>) -> RepoResult<Vec<File>> {
let tags = self.find_all_tags(tags).await?;
let tag_ids = tags.into_iter().map(|tag| tag.id()).collect();
pub async fn find_files_by_tags(&self, tags: Vec<(String, bool)>) -> RepoResult<Vec<File>> {
let db_tags = self
.find_all_tags(tags.iter().map(|t| t.0.clone()).collect())
.await?;
let tag_map: HashMap<String, bool> = HashMap::from_iter(tags.into_iter());
let tag_ids: Vec<(i64, bool)> = db_tags
.into_iter()
.map(|tag| {
(
tag.id(),
tag_map
.get(&tag.normalized_name())
.cloned()
.unwrap_or(false),
)
})
.collect();
File::find_by_tags(self.db.clone(), tag_ids).await
}

@ -32,7 +32,7 @@ impl Tag {
#[tracing::instrument(level = "debug", skip(db))]
pub async fn all(db: DatabaseConnection) -> RepoResult<Vec<Self>> {
let tags: Vec<Self> = tag::Entity::find()
.inner_join(namespace::Entity)
.left_join(namespace::Entity)
.select_also(namespace::Entity)
.all(&db)
.await?
@ -135,4 +135,13 @@ impl Tag {
.clone()
.map(|n| Namespace::new(self.db.clone(), n))
}
/// Returns the normalized name of the tag (namespace:tag)
pub fn normalized_name(&self) -> String {
if let Some(namespace) = &self.namespace {
format!("{}:{}", namespace.name, self.model.name)
} else {
self.model.name.to_owned()
}
}
}

@ -764,7 +764,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "mediarepo-api"
version = "0.1.0"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=af90986e88cc4ef7d797ecc9cfd0c306b2d4c7cd#af90986e88cc4ef7d797ecc9cfd0c306b2d4c7cd"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cb2b0e467b3554b07d04f98d9244d8e4952db68#6cb2b0e467b3554b07d04f98d9244d8e4952db68"
dependencies = [
"chrono",
"serde",

@ -29,4 +29,4 @@ features = ["tokio-executor"]
[dependencies.mediarepo-api]
git = "https://github.com/Trivernis/mediarepo-api.git"
rev = "af90986e88cc4ef7d797ecc9cfd0c306b2d4c7cd"
rev = "6cb2b0e467b3554b07d04f98d9244d8e4952db68"

@ -51,7 +51,7 @@ impl FilesNamespace {
async fn find_files(ctx: &Context, event: Event) -> IPCResult<()> {
let tags = event.data::<FindFilesByTagsRequest>()?;
let repo = get_repo_from_context(ctx).await;
let tags = tags.tags.into_iter().map(|t| t.name).collect();
let tags = tags.tags.into_iter().map(|t| (t.name, t.negate)).collect();
let files = repo.find_files_by_tags(tags).await?;
let responses: Vec<FileMetadataResponse> = files
.into_iter()

Loading…
Cancel
Save