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]]
|
[[package]]
|
||||||
name = "sqlx"
|
name = "sqlx"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3c3a85280daca669cfd3bcb68a337882a8bc57ec882f72c5d13a430613a738e"
|
checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-macros",
|
"sqlx-macros",
|
||||||
|
|
@ -2903,9 +2903,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-core"
|
name = "sqlx-core"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f743f2a3cea30a58cd479013f75550e879009e3a02f616f18ca699335aa248c3"
|
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -2938,9 +2938,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros"
|
name = "sqlx-macros"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f4200e0fde19834956d4252347c12a083bdcb237d7a1a1446bffd8768417dce"
|
checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -2951,9 +2951,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros-core"
|
name = "sqlx-macros-core"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "882ceaa29cade31beca7129b6beeb05737f44f82dbe2a9806ecea5a7093d00b7"
|
checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"either",
|
"either",
|
||||||
|
|
@ -2970,16 +2970,15 @@ dependencies = [
|
||||||
"sqlx-postgres",
|
"sqlx-postgres",
|
||||||
"sqlx-sqlite",
|
"sqlx-sqlite",
|
||||||
"syn",
|
"syn",
|
||||||
"tempfile",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-mysql"
|
name = "sqlx-mysql"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7"
|
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
|
|
@ -3020,9 +3019,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-postgres"
|
name = "sqlx-postgres"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6"
|
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
|
|
@ -3058,9 +3057,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-sqlite"
|
name = "sqlx-sqlite"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c26083e9a520e8eb87a06b12347679b142dc2ea29e6e409f805644a7a979a5bc"
|
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
@ -3248,19 +3247,6 @@ dependencies = [
|
||||||
"yaml-rust",
|
"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]]
|
[[package]]
|
||||||
name = "tendril"
|
name = "tendril"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,7 @@ pub fn make_service(
|
||||||
.post(services::ron::recipe::add_tags)
|
.post(services::ron::recipe::add_tags)
|
||||||
.delete(services::ron::recipe::rm_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(
|
.route(
|
||||||
"/recipe/{id}/difficulty",
|
"/recipe/{id}/difficulty",
|
||||||
patch(services::ron::recipe::set_difficulty),
|
patch(services::ron::recipe::set_difficulty),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::u32;
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use common::ron_api::Difficulty;
|
use common::ron_api::Difficulty;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
@ -380,29 +382,20 @@ WHERE [Recipe].[user_id] = $1
|
||||||
.map_err(DBError::from)
|
.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(
|
sqlx::query_scalar(
|
||||||
r#"
|
r#"
|
||||||
SELECT [name] FROM [Tag]
|
SELECT [name], COUNT([name]) as [nb_used] FROM [Tag]
|
||||||
ORDER BY [name]
|
INNER JOIN [RecipeTag] ON [RecipeTag].[tag_id] = [Tag].[id]
|
||||||
"#,
|
INNER JOIN [Recipe] ON [Recipe].[id] = [RecipeTag].[recipe_id]
|
||||||
)
|
|
||||||
.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]
|
|
||||||
WHERE [Recipe].[lang] = $1
|
WHERE [Recipe].[lang] = $1
|
||||||
ORDER BY [name]
|
GROUP BY [Tag].[name]
|
||||||
|
ORDER BY [nb_used] DESC, [name]
|
||||||
|
LIMIT $2
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(lang)
|
.bind(lang)
|
||||||
|
.bind(max_number.unwrap_or(u32::MAX))
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await
|
.await
|
||||||
.map_err(DBError::from)
|
.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_1).await?, tags_1);
|
||||||
assert_eq!(connection.get_recipes_tags(recipe_id_2).await?, tags_2);
|
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?;
|
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!(
|
assert_eq!(
|
||||||
connection.get_recipes_tags(recipe_id_1).await?,
|
connection.get_recipes_tags(recipe_id_1).await?,
|
||||||
|
|
@ -1098,13 +1097,12 @@ VALUES
|
||||||
connection.get_recipes_tags(recipe_id_2).await?,
|
connection.get_recipes_tags(recipe_id_2).await?,
|
||||||
["def", "xyz"]
|
["def", "xyz"]
|
||||||
);
|
);
|
||||||
assert_eq!(connection.get_all_tags().await?, ["def", "xyz"]);
|
assert_eq!(connection.get_all_tags("en", None).await?, ["xyz", "def"]);
|
||||||
assert_eq!(connection.get_all_tags_by_lang("en").await?, ["def", "xyz"]);
|
|
||||||
|
|
||||||
connection.rm_recipe_tags(recipe_id_1, &tags_1).await?;
|
connection.rm_recipe_tags(recipe_id_1, &tags_1).await?;
|
||||||
connection.rm_recipe_tags(recipe_id_2, &tags_2).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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
debug_handler,
|
debug_handler,
|
||||||
extract::{Extension, Path, Query, State},
|
extract::{Extension, Path, State},
|
||||||
http::{HeaderMap, StatusCode},
|
http::{HeaderMap, StatusCode},
|
||||||
response::{IntoResponse, Result},
|
response::{IntoResponse, Result},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
|
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
|
||||||
use common::ron_api;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::Context,
|
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]
|
#[debug_handler]
|
||||||
pub async fn add_tags(
|
pub async fn add_tags(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use ron::ser::{PrettyConfig, to_string_pretty};
|
use ron::ser::{PrettyConfig, to_string_pretty};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::FromRepr;
|
||||||
|
|
||||||
/*** Generic types ***/
|
/*** Generic types ***/
|
||||||
|
|
||||||
|
|
@ -20,7 +21,7 @@ pub struct DateRange {
|
||||||
/*** Recipe ***/
|
/*** Recipe ***/
|
||||||
|
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, FromRepr, Clone, Copy, PartialEq, Debug)]
|
||||||
pub enum Difficulty {
|
pub enum Difficulty {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Easy = 1,
|
Easy = 1,
|
||||||
|
|
@ -29,14 +30,9 @@ pub enum Difficulty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u32> for Difficulty {
|
impl TryFrom<u32> for Difficulty {
|
||||||
type Error = &'static str;
|
type Error = String;
|
||||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||||
Ok(match value {
|
Difficulty::from_repr(value).ok_or(format!("Unable to convert difficulty from {}", value))
|
||||||
1 => Self::Easy,
|
|
||||||
2 => Self::Medium,
|
|
||||||
3 => Self::Hard,
|
|
||||||
_ => Self::Unknown,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,8 @@ pub fn setup_page(recipe_id: i64) {
|
||||||
if difficulty.value() != current_difficulty {
|
if difficulty.value() != current_difficulty {
|
||||||
current_difficulty = difficulty.value();
|
current_difficulty = difficulty.value();
|
||||||
let difficulty =
|
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 {
|
spawn_local(async move {
|
||||||
let _ = request::patch::<(), _>(
|
let _ = request::patch::<(), _>(
|
||||||
&format!("recipe/{recipe_id}/difficulty"),
|
&format!("recipe/{recipe_id}/difficulty"),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue