Add a API entry point to get all tags
This commit is contained in:
parent
6e017e41a3
commit
c24b0caeaf
7 changed files with 55 additions and 63 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
|
@ -2890,9 +2890,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c3a85280daca669cfd3bcb68a337882a8bc57ec882f72c5d13a430613a738e"
|
||||
checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
|
|
@ -2903,9 +2903,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f743f2a3cea30a58cd479013f75550e879009e3a02f616f18ca699335aa248c3"
|
||||
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
|
|
@ -2938,9 +2938,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4200e0fde19834956d4252347c12a083bdcb237d7a1a1446bffd8768417dce"
|
||||
checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2951,9 +2951,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-macros-core"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "882ceaa29cade31beca7129b6beeb05737f44f82dbe2a9806ecea5a7093d00b7"
|
||||
checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"either",
|
||||
|
|
@ -2970,16 +2970,15 @@ dependencies = [
|
|||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-mysql"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7"
|
||||
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
|
|
@ -3020,9 +3019,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-postgres"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6"
|
||||
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
|
|
@ -3058,9 +3057,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-sqlite"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c26083e9a520e8eb87a06b12347679b142dc2ea29e6e409f805644a7a979a5bc"
|
||||
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"chrono",
|
||||
|
|
@ -3248,19 +3247,6 @@ dependencies = [
|
|||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tendril"
|
||||
version = "0.4.3"
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use chrono::NaiveDate;
|
||||
use ron::ser::{PrettyConfig, to_string_pretty};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::FromRepr;
|
||||
|
||||
/*** Generic types ***/
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ pub struct DateRange {
|
|||
/*** Recipe ***/
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Debug)]
|
||||
#[derive(Serialize, Deserialize, FromRepr, Clone, Copy, PartialEq, Debug)]
|
||||
pub enum Difficulty {
|
||||
Unknown = 0,
|
||||
Easy = 1,
|
||||
|
|
@ -29,14 +30,9 @@ pub enum Difficulty {
|
|||
}
|
||||
|
||||
impl TryFrom<u32> for Difficulty {
|
||||
type Error = &'static str;
|
||||
type Error = String;
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
1 => Self::Easy,
|
||||
2 => Self::Medium,
|
||||
3 => Self::Hard,
|
||||
_ => Self::Unknown,
|
||||
})
|
||||
Difficulty::from_repr(value).ok_or(format!("Unable to convert difficulty from {}", value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,8 @@ pub fn setup_page(recipe_id: i64) {
|
|||
if difficulty.value() != current_difficulty {
|
||||
current_difficulty = difficulty.value();
|
||||
let difficulty =
|
||||
ron_api::Difficulty::try_from(difficulty.value().parse::<u32>().unwrap());
|
||||
ron_api::Difficulty::from_repr(difficulty.value().parse::<u32>().unwrap())
|
||||
.unwrap_or(ron_api::Difficulty::Unknown);
|
||||
spawn_local(async move {
|
||||
let _ = request::patch::<(), _>(
|
||||
&format!("recipe/{recipe_id}/difficulty"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue