chore: source formatting and spec allignment

This commit is contained in:
2026-07-18 14:20:23 +02:00
parent a594b99e90
commit 16a210c0ad
119 changed files with 8868 additions and 5250 deletions

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{generated_file_hash_from_row, GENERATED_FILE_HASH_COLUMNS};
use crate::db::from_row::{GENERATED_FILE_HASH_COLUMNS, generated_file_hash_from_row};
use crate::model::GeneratedFileHash;
pub fn get_generated_file_hash(
@@ -17,13 +17,21 @@ pub fn get_generated_file_hash(
)
}
pub fn upsert_generated_file_hash(conn: &Connection, hash: &GeneratedFileHash) -> rusqlite::Result<()> {
pub fn upsert_generated_file_hash(
conn: &Connection,
hash: &GeneratedFileHash,
) -> rusqlite::Result<()> {
conn.execute(
"INSERT INTO generated_file_hashes (project_id, relative_path, content_hash, updated_at)
VALUES (?1, ?2, ?3, ?4)
ON CONFLICT(project_id, relative_path)
DO UPDATE SET content_hash = excluded.content_hash, updated_at = excluded.updated_at",
params![hash.project_id, hash.relative_path, hash.content_hash, hash.updated_at],
params![
hash.project_id,
hash.relative_path,
hash.content_hash,
hash.updated_at
],
)?;
Ok(())
}
@@ -54,8 +62,8 @@ pub fn list_generated_file_hashes_by_project(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();
@@ -91,4 +99,4 @@ mod tests {
assert_eq!(stored.content_hash, "def");
assert_eq!(stored.updated_at, 99);
}
}
}

View File

@@ -1,7 +1,8 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{media_from_row, MEDIA_COLUMNS};
use crate::db::from_row::{MEDIA_COLUMNS, media_from_row};
use crate::model::Media;
use crate::util::calendar_range_unix_ms;
fn tags_to_json(tags: &[String]) -> String {
serde_json::to_string(tags).unwrap_or_else(|_| "[]".into())
@@ -133,9 +134,7 @@ pub struct MediaFilterParams {
impl MediaFilterParams {
pub fn has_active_filters(&self) -> bool {
!self.search_query.is_empty()
|| self.year.is_some()
|| !self.tags.is_empty()
!self.search_query.is_empty() || self.year.is_some() || !self.tags.is_empty()
}
}
@@ -161,49 +160,13 @@ pub fn list_media_filtered(
}
if let Some(year) = filters.year {
let start = chrono::NaiveDate::from_ymd_opt(year, 1, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let end = chrono::NaiveDate::from_ymd_opt(year + 1, 1, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
if let Some(month) = filters.month {
let m_start = chrono::NaiveDate::from_ymd_opt(year, month, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let next_month = if month == 12 {
chrono::NaiveDate::from_ymd_opt(year + 1, 1, 1)
} else {
chrono::NaiveDate::from_ymd_opt(year, month + 1, 1)
}
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
conditions.push(format!("(created_at >= ?{idx1} AND created_at < ?{idx2})"));
param_values.push(Box::new(m_start));
param_values.push(Box::new(next_month));
} else {
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
conditions.push(format!("(created_at >= ?{idx1} AND created_at < ?{idx2})"));
param_values.push(Box::new(start));
param_values.push(Box::new(end));
}
let (start, end) =
calendar_range_unix_ms(year, filters.month).ok_or(rusqlite::Error::InvalidQuery)?;
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
conditions.push(format!("(created_at >= ?{idx1} AND created_at < ?{idx2})"));
param_values.push(Box::new(start));
param_values.push(Box::new(end));
}
for tag in &filters.tags {
@@ -244,7 +207,7 @@ pub fn media_calendar_counts(
FROM media
WHERE project_id = ?1
GROUP BY y, m
ORDER BY y DESC, m DESC"
ORDER BY y DESC, m DESC",
)?;
let rows = stmt.query_map(params![project_id], |row| {
Ok((
@@ -257,22 +220,16 @@ pub fn media_calendar_counts(
}
/// Collect all distinct tag values across media for a project.
pub fn distinct_media_tags(
conn: &Connection,
project_id: &str,
) -> rusqlite::Result<Vec<String>> {
let mut stmt = conn.prepare(
"SELECT DISTINCT tags FROM media WHERE project_id = ?1 AND tags != '[]'"
)?;
let rows = stmt.query_map(params![project_id], |row| {
row.get::<_, String>(0)
})?;
pub fn distinct_media_tags(conn: &Connection, project_id: &str) -> rusqlite::Result<Vec<String>> {
let mut stmt =
conn.prepare("SELECT DISTINCT tags FROM media WHERE project_id = ?1 AND tags != '[]'")?;
let rows = stmt.query_map(params![project_id], |row| row.get::<_, String>(0))?;
let mut all_tags = std::collections::BTreeSet::new();
for json_str in rows {
if let Ok(json_str) = json_str {
if let Ok(tags) = serde_json::from_str::<Vec<String>>(&json_str) {
all_tags.extend(tags);
}
if let Ok(json_str) = json_str
&& let Ok(tags) = serde_json::from_str::<Vec<String>>(&json_str)
{
all_tags.extend(tags);
}
}
Ok(all_tags.into_iter().collect())
@@ -307,8 +264,8 @@ pub fn make_test_media(id: &str, project_id: &str) -> Media {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();

View File

@@ -1,12 +1,9 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{media_translation_from_row, MEDIA_TRANSLATION_COLUMNS};
use crate::db::from_row::{MEDIA_TRANSLATION_COLUMNS, media_translation_from_row};
use crate::model::MediaTranslation;
pub fn insert_media_translation(
conn: &Connection,
t: &MediaTranslation,
) -> rusqlite::Result<()> {
pub fn insert_media_translation(conn: &Connection, t: &MediaTranslation) -> rusqlite::Result<()> {
conn.execute(
"INSERT INTO media_translations (
id, project_id, translation_for, language, title, alt, caption,
@@ -54,10 +51,7 @@ pub fn list_media_translations_by_media(
rows.collect()
}
pub fn upsert_media_translation(
conn: &Connection,
t: &MediaTranslation,
) -> rusqlite::Result<()> {
pub fn upsert_media_translation(conn: &Connection, t: &MediaTranslation) -> rusqlite::Result<()> {
conn.execute(
"INSERT INTO media_translations (
id, project_id, translation_for, language, title, alt, caption,
@@ -98,9 +92,9 @@ pub fn delete_media_translation(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::Database;
use crate::db::queries::media::{insert_media, make_test_media};
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();
@@ -164,8 +158,6 @@ mod tests {
let db = setup();
insert_media_translation(db.conn(), &make_mt("mt1", "de")).unwrap();
delete_media_translation(db.conn(), "m1", "de").unwrap();
assert!(
get_media_translation_by_media_and_language(db.conn(), "m1", "de").is_err()
);
assert!(get_media_translation_by_media_and_language(db.conn(), "m1", "de").is_err());
}
}

View File

@@ -1,12 +1,12 @@
pub mod project;
pub mod post;
pub mod post_translation;
pub mod generated_file_hash;
pub mod media;
pub mod media_translation;
pub mod tag;
pub mod post;
pub mod post_link;
pub mod post_media;
pub mod template;
pub mod post_translation;
pub mod project;
pub mod script;
pub mod setting;
pub mod generated_file_hash;
pub mod tag;
pub mod template;

View File

@@ -1,7 +1,8 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{post_from_row, post_status_to_str, POST_COLUMNS};
use crate::db::from_row::{POST_COLUMNS, post_from_row, post_status_to_str};
use crate::model::{Post, PostStatus};
use crate::util::calendar_range_unix_ms;
fn tags_to_json(tags: &[String]) -> String {
serde_json::to_string(tags).unwrap_or_else(|_| "[]".into())
@@ -165,6 +166,10 @@ pub fn set_post_file_path(
Ok(())
}
#[expect(
clippy::too_many_arguments,
reason = "arguments mirror the published snapshot columns"
)]
pub fn set_published_snapshot(
conn: &Connection,
id: &str,
@@ -182,7 +187,16 @@ pub fn set_published_snapshot(
published_categories = ?4, published_excerpt = ?5,
published_at = ?6, updated_at = ?7
WHERE id = ?8",
params![title, content, tags, categories, excerpt, published_at, updated_at, id],
params![
title,
content,
tags,
categories,
excerpt,
published_at,
updated_at,
id
],
)?;
Ok(())
}
@@ -295,50 +309,15 @@ pub fn list_posts_filtered(
}
if let Some(year) = filters.year {
// created_at is unix ms; compute year range
let start = chrono::NaiveDate::from_ymd_opt(year, 1, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let end = chrono::NaiveDate::from_ymd_opt(year + 1, 1, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
if let Some(month) = filters.month {
let m_start = chrono::NaiveDate::from_ymd_opt(year, month, 1)
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let next_month = if month == 12 {
chrono::NaiveDate::from_ymd_opt(year + 1, 1, 1)
} else {
chrono::NaiveDate::from_ymd_opt(year, month + 1, 1)
}
.unwrap()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc()
.timestamp() * 1000;
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
filter_conditions.push(format!("(p.created_at >= ?{idx1} AND p.created_at < ?{idx2})"));
param_values.push(Box::new(m_start));
param_values.push(Box::new(next_month));
} else {
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
filter_conditions.push(format!("(p.created_at >= ?{idx1} AND p.created_at < ?{idx2})"));
param_values.push(Box::new(start));
param_values.push(Box::new(end));
}
let (start, end) =
calendar_range_unix_ms(year, filters.month).ok_or(rusqlite::Error::InvalidQuery)?;
let idx1 = param_values.len() + 1;
let idx2 = param_values.len() + 2;
filter_conditions.push(format!(
"(p.created_at >= ?{idx1} AND p.created_at < ?{idx2})"
));
param_values.push(Box::new(start));
param_values.push(Box::new(end));
}
for tag in &filters.tags {
@@ -435,22 +414,16 @@ pub fn post_calendar_counts(
}
/// Collect all distinct tag values across posts for a project.
pub fn distinct_post_tags(
conn: &Connection,
project_id: &str,
) -> rusqlite::Result<Vec<String>> {
let mut stmt = conn.prepare(
"SELECT DISTINCT tags FROM posts WHERE project_id = ?1 AND tags != '[]'"
)?;
let rows = stmt.query_map(params![project_id], |row| {
row.get::<_, String>(0)
})?;
pub fn distinct_post_tags(conn: &Connection, project_id: &str) -> rusqlite::Result<Vec<String>> {
let mut stmt =
conn.prepare("SELECT DISTINCT tags FROM posts WHERE project_id = ?1 AND tags != '[]'")?;
let rows = stmt.query_map(params![project_id], |row| row.get::<_, String>(0))?;
let mut all_tags = std::collections::BTreeSet::new();
for json_str in rows {
if let Ok(json_str) = json_str {
if let Ok(tags) = serde_json::from_str::<Vec<String>>(&json_str) {
all_tags.extend(tags);
}
if let Ok(json_str) = json_str
&& let Ok(tags) = serde_json::from_str::<Vec<String>>(&json_str)
{
all_tags.extend(tags);
}
}
Ok(all_tags.into_iter().collect())
@@ -462,17 +435,15 @@ pub fn distinct_post_categories(
project_id: &str,
) -> rusqlite::Result<Vec<String>> {
let mut stmt = conn.prepare(
"SELECT DISTINCT categories FROM posts WHERE project_id = ?1 AND categories != '[]'"
"SELECT DISTINCT categories FROM posts WHERE project_id = ?1 AND categories != '[]'",
)?;
let rows = stmt.query_map(params![project_id], |row| {
row.get::<_, String>(0)
})?;
let rows = stmt.query_map(params![project_id], |row| row.get::<_, String>(0))?;
let mut all_cats = std::collections::BTreeSet::new();
for json_str in rows {
if let Ok(json_str) = json_str {
if let Ok(cats) = serde_json::from_str::<Vec<String>>(&json_str) {
all_cats.extend(cats);
}
if let Ok(json_str) = json_str
&& let Ok(cats) = serde_json::from_str::<Vec<String>>(&json_str)
{
all_cats.extend(cats);
}
}
Ok(all_cats.into_iter().collect())
@@ -481,8 +452,8 @@ pub fn distinct_post_categories(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();
@@ -603,9 +574,17 @@ mod tests {
let db = setup();
insert_post(db.conn(), &make_post("x1", "hello")).unwrap();
set_published_snapshot(
db.conn(), "x1", "Pub Title", "Pub Body",
"[\"rust\"]", "[\"tech\"]", Some("Pub Excerpt"), 3000, 3000,
).unwrap();
db.conn(),
"x1",
"Pub Title",
"Pub Body",
"[\"rust\"]",
"[\"tech\"]",
Some("Pub Excerpt"),
3000,
3000,
)
.unwrap();
let fetched = get_post_by_id(db.conn(), "x1").unwrap();
assert_eq!(fetched.published_title.as_deref(), Some("Pub Title"));
assert_eq!(fetched.published_content.as_deref(), Some("Pub Body"));

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{post_link_from_row, POST_LINK_COLUMNS};
use crate::db::from_row::{POST_LINK_COLUMNS, post_link_from_row};
use crate::model::PostLink;
pub fn insert_post_link(conn: &Connection, link: &PostLink) -> rusqlite::Result<()> {
@@ -51,8 +51,8 @@ pub fn list_links_by_target(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();
@@ -63,17 +63,20 @@ mod tests {
"INSERT INTO posts (id, project_id, title, slug, status, created_at, updated_at)
VALUES ('a', 'p1', 'A', 'a', 'draft', 1000, 1000)",
[],
).unwrap();
)
.unwrap();
c.execute(
"INSERT INTO posts (id, project_id, title, slug, status, created_at, updated_at)
VALUES ('b', 'p1', 'B', 'b', 'draft', 1000, 1000)",
[],
).unwrap();
)
.unwrap();
c.execute(
"INSERT INTO posts (id, project_id, title, slug, status, created_at, updated_at)
VALUES ('c', 'p1', 'C', 'c', 'draft', 1000, 1000)",
[],
).unwrap();
)
.unwrap();
db
}

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{post_media_from_row, POST_MEDIA_COLUMNS};
use crate::db::from_row::{POST_MEDIA_COLUMNS, post_media_from_row};
use crate::model::PostMedia;
pub fn link_media(conn: &Connection, pm: &PostMedia) -> rusqlite::Result<()> {
@@ -65,9 +65,9 @@ pub fn update_sort_order(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::Database;
use crate::db::queries::media::{insert_media, make_test_media};
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();

View File

@@ -1,12 +1,11 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{post_status_to_str, post_translation_from_row, POST_TRANSLATION_COLUMNS};
use crate::db::from_row::{
POST_TRANSLATION_COLUMNS, post_status_to_str, post_translation_from_row,
};
use crate::model::PostTranslation;
pub fn insert_post_translation(
conn: &Connection,
t: &PostTranslation,
) -> rusqlite::Result<()> {
pub fn insert_post_translation(conn: &Connection, t: &PostTranslation) -> rusqlite::Result<()> {
if !t.status.is_valid_for_translation() {
return Err(rusqlite::Error::InvalidParameterName(
"translation status must be draft or published".to_string(),
@@ -74,10 +73,7 @@ pub fn list_post_translations_by_post(
rows.collect()
}
pub fn update_post_translation(
conn: &Connection,
t: &PostTranslation,
) -> rusqlite::Result<()> {
pub fn update_post_translation(conn: &Connection, t: &PostTranslation) -> rusqlite::Result<()> {
if !t.status.is_valid_for_translation() {
return Err(rusqlite::Error::InvalidParameterName(
"translation status must be draft or published".to_string(),
@@ -104,10 +100,7 @@ pub fn update_post_translation(
}
pub fn delete_post_translation(conn: &Connection, id: &str) -> rusqlite::Result<()> {
conn.execute(
"DELETE FROM post_translations WHERE id = ?1",
params![id],
)?;
conn.execute("DELETE FROM post_translations WHERE id = ?1", params![id])?;
Ok(())
}
@@ -125,8 +118,8 @@ pub fn delete_all_translations_for_post(
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::model::PostStatus;
fn setup() -> Database {

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{project_from_row, PROJECT_COLUMNS};
use crate::db::from_row::{PROJECT_COLUMNS, project_from_row};
use crate::model::Project;
pub fn insert_project(conn: &Connection, project: &Project) -> rusqlite::Result<()> {

View File

@@ -1,7 +1,7 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{
script_from_row, script_kind_to_str, script_status_to_str, SCRIPT_COLUMNS,
SCRIPT_COLUMNS, script_from_row, script_kind_to_str, script_status_to_str,
};
use crate::model::Script;
@@ -44,9 +44,7 @@ pub fn get_script_by_slug(
slug: &str,
) -> rusqlite::Result<Script> {
conn.query_row(
&format!(
"SELECT {SCRIPT_COLUMNS} FROM scripts WHERE project_id = ?1 AND slug = ?2"
),
&format!("SELECT {SCRIPT_COLUMNS} FROM scripts WHERE project_id = ?1 AND slug = ?2"),
params![project_id, slug],
script_from_row,
)
@@ -94,8 +92,8 @@ pub fn delete_script(conn: &Connection, id: &str) -> rusqlite::Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::model::{ScriptKind, ScriptStatus};
fn setup() -> Database {

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{setting_from_row, SETTING_COLUMNS};
use crate::db::from_row::{SETTING_COLUMNS, setting_from_row};
use crate::model::Setting;
pub fn get_setting_by_key(conn: &Connection, key: &str) -> rusqlite::Result<Setting> {

View File

@@ -1,6 +1,6 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{tag_from_row, TAG_COLUMNS};
use crate::db::from_row::{TAG_COLUMNS, tag_from_row};
use crate::model::Tag;
pub fn insert_tag(conn: &Connection, tag: &Tag) -> rusqlite::Result<()> {
@@ -73,8 +73,8 @@ pub fn delete_tag(conn: &Connection, id: &str) -> rusqlite::Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
fn setup() -> Database {
let mut db = Database::open_in_memory().unwrap();

View File

@@ -1,7 +1,7 @@
use rusqlite::{params, Connection};
use rusqlite::{Connection, params};
use crate::db::from_row::{
template_from_row, template_kind_to_str, template_status_to_str, TEMPLATE_COLUMNS,
TEMPLATE_COLUMNS, template_from_row, template_kind_to_str, template_status_to_str,
};
use crate::model::Template;
@@ -43,9 +43,7 @@ pub fn get_template_by_slug(
slug: &str,
) -> rusqlite::Result<Template> {
conn.query_row(
&format!(
"SELECT {TEMPLATE_COLUMNS} FROM templates WHERE project_id = ?1 AND slug = ?2"
),
&format!("SELECT {TEMPLATE_COLUMNS} FROM templates WHERE project_id = ?1 AND slug = ?2"),
params![project_id, slug],
template_from_row,
)
@@ -92,8 +90,8 @@ pub fn delete_template(conn: &Connection, id: &str) -> rusqlite::Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::db::Database;
use crate::db::queries::project::{insert_project, make_test_project};
use crate::model::{TemplateKind, TemplateStatus};
fn setup() -> Database {