phonograph/interim-models/src/field_form_prompt.rs
2025-10-09 08:01:01 +00:00

131 lines
3 KiB
Rust

use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use sqlx::query_as;
use uuid::Uuid;
use crate::{client::AppDbClient, language::Language};
/// A localized prompt to display above or alongside the form input for the
/// given field.
///
/// There may be zero or one `field_form_prompt` entries for each
/// `(field_id, language)` pair. (This uniqueness should be enforced by the
/// database.)
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct FieldFormPrompt {
/// Primary key (defaults to UUIDv7).
pub id: Uuid,
/// ID of the field to which this prompt belongs.
pub field_id: Uuid,
/// [ISO 639-3](https://en.wikipedia.org/wiki/List_of_ISO_639-3_codes)
/// language code.
pub language: Language,
/// Prompt content for this field, in this language.
pub content: String,
}
impl FieldFormPrompt {
/// Build an insert statement to create a new prompt.
pub fn upsert() -> UpsertBuilder {
UpsertBuilder::default()
}
/// Build an update statement to alter the content of an existing prompt.
pub fn update() -> UpdateBuilder {
UpdateBuilder::default()
}
/// Build a single-field query by field ID.
pub fn belonging_to_field(id: Uuid) -> BelongingToFieldQuery {
BelongingToFieldQuery { id }
}
}
#[derive(Builder, Clone, Debug)]
pub struct Upsert {
field_id: Uuid,
language: Language,
content: String,
}
impl Upsert {
pub async fn execute(self, app_db: &mut AppDbClient) -> Result<FieldFormPrompt, sqlx::Error> {
query_as!(
FieldFormPrompt,
r#"
insert into field_form_prompts (field_id, language, content) values ($1, $2, $3)
on conflict (field_id, language) do update set
content = excluded.content
returning
id,
field_id,
language as "language: Language",
content
"#,
self.field_id,
self.language.to_string(),
self.content,
)
.fetch_one(app_db.get_conn())
.await
}
}
#[derive(Builder, Clone, Debug, Default)]
pub struct Update {
id: Uuid,
content: String,
}
impl Update {
pub async fn execute(self, app_db: &mut AppDbClient) -> Result<FieldFormPrompt, sqlx::Error> {
query_as!(
FieldFormPrompt,
r#"
update field_form_prompts
set content = $1
where id = $2
returning
id,
field_id,
language as "language: Language",
content
"#,
self.content,
self.id,
)
.fetch_one(app_db.get_conn())
.await
}
}
#[derive(Clone, Debug)]
pub struct BelongingToFieldQuery {
id: Uuid,
}
impl BelongingToFieldQuery {
pub async fn fetch_all(
self,
app_db: &mut AppDbClient,
) -> Result<Vec<FieldFormPrompt>, sqlx::Error> {
query_as!(
FieldFormPrompt,
r#"
select
id,
field_id,
language as "language: Language",
content
from field_form_prompts
where field_id = $1
"#,
self.id,
)
.fetch_all(app_db.get_conn())
.await
}
}