feat(labrinth): user preferences (#7177)

* feat(labrinth): initial preferences structure

* feat(labrinth): use partially to derive partial structs

* feat(labrinth): preference defaults

* fix(labrinth): derive debug

* feat(labrinth): user preferences db setup

* feat(labrinth): user preferences routes

* fix(labrinth): nested partial structs

* fix(labrinth): serialize enums as snake case

* refactor(labrinth-derive): rename to component-derive

* feat(component-derive): nested components

* refactor(component-derive): change suffixes to prefixes

* refactor(component-derive): rename edit to partial

* feat(component-derive): skip serializing empty option

* refactor(labrinth): wrap errors

* feat(component-derive): diff function

* style(labrinth): fmt

* refactor(labrinth): use component derive and only store overrides

* chore: update query cache

* docs(labrinth): add preferences to openapi

* fix(labrinth): lock row for update

* remove: partially

* refactor(component-derive): split impls to separate functions

* feat(component-derive): wrap impls to isolate naming

* refactor(labrinth): split out auth conditions

* feat(labrinth): store auto

* feat(labrinth): store hosting privacy

* style(labrinth): cargo fmt
This commit is contained in:
Sychic
2026-08-17 17:57:57 +00:00
committed by GitHub
parent b3b0b85691
commit 46d07163cd
18 changed files with 680 additions and 173 deletions
+1
View File
@@ -38,6 +38,7 @@ pub mod team_item;
pub mod thread_item;
pub mod user_item;
pub mod user_limits;
pub mod user_preferences_item;
pub mod user_subscription_item;
pub mod users_compliance;
pub mod users_notifications_preferences_item;
@@ -0,0 +1,75 @@
use crate::database::Executor;
use crate::database::models::DBUserId;
use crate::models::v3::preferences::PartialUserPreferences;
use sqlx::types::Json;
pub struct DBUserPreferences;
impl DBUserPreferences {
pub async fn get<'a, E>(
user_id: DBUserId,
exec: E,
) -> Result<Option<PartialUserPreferences>, sqlx::Error>
where
E: Executor<'a, Database = sqlx::Postgres>,
{
let row = sqlx::query!(
r#"
SELECT preferences AS "preferences: Json<PartialUserPreferences>"
FROM user_preferences
WHERE user_id = $1
"#,
user_id.0,
)
.fetch_optional(exec)
.await?;
Ok(row.map(|row| row.preferences.0))
}
pub async fn get_for_update<'a, E>(
user_id: DBUserId,
exec: E,
) -> Result<Option<PartialUserPreferences>, sqlx::Error>
where
E: Executor<'a, Database = sqlx::Postgres>,
{
let row = sqlx::query!(
r#"
SELECT preferences AS "preferences: Json<PartialUserPreferences>"
FROM user_preferences
WHERE user_id = $1
FOR UPDATE
"#,
user_id.0,
)
.fetch_optional(exec)
.await?;
Ok(row.map(|row| row.preferences.0))
}
pub async fn upsert<'a, E>(
user_id: DBUserId,
preferences: &PartialUserPreferences,
exec: E,
) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = sqlx::Postgres>,
{
sqlx::query!(
r#"
INSERT INTO user_preferences (user_id, preferences)
VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE
SET preferences = EXCLUDED.preferences
"#,
user_id.0,
Json(preferences) as Json<&PartialUserPreferences>,
)
.execute(exec)
.await?;
Ok(())
}
}