Add a API entry point to get all tags

This commit is contained in:
Greg Burri 2025-05-20 15:32:54 +02:00
parent 6e017e41a3
commit c24b0caeaf
7 changed files with 55 additions and 63 deletions

View file

@ -155,8 +155,7 @@ pub fn make_service(
.post(services::ron::recipe::add_tags)
.delete(services::ron::recipe::rm_tags),
)
// TODO
// .route("/recipe/tags".get(services::ron::recipe::get_all_tags))
.route("/recipe/tags", get(services::ron::recipe::get_all_tags))
.route(
"/recipe/{id}/difficulty",
patch(services::ron::recipe::set_difficulty),

View file

@ -1,3 +1,5 @@
use std::u32;
use chrono::prelude::*;
use common::ron_api::Difficulty;
use itertools::Itertools;
@ -380,29 +382,20 @@ WHERE [Recipe].[user_id] = $1
.map_err(DBError::from)
}
pub async fn get_all_tags(&self) -> Result<Vec<String>> {
pub async fn get_all_tags(&self, lang: &str, max_number: Option<u32>) -> Result<Vec<String>> {
sqlx::query_scalar(
r#"
SELECT [name] FROM [Tag]
ORDER BY [name]
"#,
)
.fetch_all(&self.pool)
.await
.map_err(DBError::from)
}
pub async fn get_all_tags_by_lang(&self, lang: &str) -> Result<Vec<String>> {
sqlx::query_scalar(
r#"
SELECT DISTINCT [name] FROM [Tag]
INNER JOIN [RecipeTag] ON [RecipeTag].[tag_id] = [Tag].[id]
INNER JOIN [Recipe] ON [Recipe].[id] = [RecipeTag].[recipe_id]
SELECT [name], COUNT([name]) as [nb_used] FROM [Tag]
INNER JOIN [RecipeTag] ON [RecipeTag].[tag_id] = [Tag].[id]
INNER JOIN [Recipe] ON [Recipe].[id] = [RecipeTag].[recipe_id]
WHERE [Recipe].[lang] = $1
ORDER BY [name]
GROUP BY [Tag].[name]
ORDER BY [nb_used] DESC, [name]
LIMIT $2
"#,
)
.bind(lang)
.bind(max_number.unwrap_or(u32::MAX))
.fetch_all(&self.pool)
.await
.map_err(DBError::from)
@ -1078,9 +1071,15 @@ VALUES
assert_eq!(connection.get_recipes_tags(recipe_id_1).await?, tags_1);
assert_eq!(connection.get_recipes_tags(recipe_id_2).await?, tags_2);
assert_eq!(connection.get_all_tags().await?, ["abc", "def", "xyz"]);
assert_eq!(
connection.get_all_tags("en", None).await?,
["abc", "xyz", "def"]
);
connection.rm_recipe_tags(recipe_id_2, &["abc"]).await?;
assert_eq!(connection.get_all_tags().await?, ["abc", "def", "xyz"]);
assert_eq!(
connection.get_all_tags("en", None).await?,
["xyz", "abc", "def"] // Most used tags come first.
);
assert_eq!(
connection.get_recipes_tags(recipe_id_1).await?,
@ -1098,13 +1097,12 @@ VALUES
connection.get_recipes_tags(recipe_id_2).await?,
["def", "xyz"]
);
assert_eq!(connection.get_all_tags().await?, ["def", "xyz"]);
assert_eq!(connection.get_all_tags_by_lang("en").await?, ["def", "xyz"]);
assert_eq!(connection.get_all_tags("en", None).await?, ["xyz", "def"]);
connection.rm_recipe_tags(recipe_id_1, &tags_1).await?;
connection.rm_recipe_tags(recipe_id_2, &tags_2).await?;
assert!(connection.get_all_tags().await?.is_empty());
assert!(connection.get_all_tags("en", None).await?.is_empty());
Ok(())
}

View file

@ -1,11 +1,10 @@
use axum::{
debug_handler,
extract::{Extension, Path, Query, State},
extract::{Extension, Path, State},
http::{HeaderMap, StatusCode},
response::{IntoResponse, Result},
};
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
use common::ron_api;
use crate::{
app::Context,

View file

@ -88,6 +88,19 @@ pub async fn get_tags(
))
}
#[debug_handler]
pub async fn get_all_tags(
State(connection): State<db::Connection>,
Extension(context): Extension<Context>,
nb_max_tags: Query<Option<u32>>,
lang: Query<Option<String>>,
) -> Result<impl IntoResponse> {
let lang = lang.0.unwrap_or(context.tr.current_lang_code().to_string());
Ok(ron_response_ok(
connection.get_all_tags(&lang, nb_max_tags.0).await?,
))
}
#[debug_handler]
pub async fn add_tags(
State(connection): State<db::Connection>,