feat: add article_history DB module (check, insert, cleanup)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
master
oabrivard 3 months ago
parent c271c240a2
commit 5a928aa990

@ -0,0 +1,76 @@
//! Article history: tracks which article URLs have been used in past syntheses.
//!
//! Prevents the same article from appearing in multiple syntheses.
use std::collections::HashSet;
use sqlx::PgPool;
use uuid::Uuid;
use crate::errors::AppError;
/// Check which URL hashes already exist in history for this user.
///
/// Returns the set of url_hashes that were found (i.e., already used).
pub async fn check_urls_exist(
pool: &PgPool,
user_id: Uuid,
url_hashes: &[String],
) -> Result<HashSet<String>, AppError> {
if url_hashes.is_empty() {
return Ok(HashSet::new());
}
let rows = sqlx::query_scalar::<_, String>(
"SELECT url_hash FROM article_history WHERE user_id = $1 AND url_hash = ANY($2)",
)
.bind(user_id)
.bind(url_hashes)
.fetch_all(pool)
.await?;
Ok(rows.into_iter().collect())
}
/// Insert article URLs into history.
///
/// Uses ON CONFLICT DO NOTHING to silently skip duplicates.
pub async fn insert_urls(
pool: &PgPool,
user_id: Uuid,
urls: &[(String, String)], // Vec<(url, url_hash)>
) -> Result<(), AppError> {
if urls.is_empty() {
return Ok(());
}
for (url, url_hash) in urls {
sqlx::query(
"INSERT INTO article_history (user_id, url_hash, url) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING",
)
.bind(user_id)
.bind(url_hash)
.bind(url)
.execute(pool)
.await?;
}
Ok(())
}
/// Delete history entries older than N days for this user.
///
/// Returns the number of deleted rows.
pub async fn cleanup_old(
pool: &PgPool,
user_id: Uuid,
days: i32,
) -> Result<u64, AppError> {
let result = sqlx::query(
"DELETE FROM article_history WHERE user_id = $1 AND created_at < now() - make_interval(days => $2)",
)
.bind(user_id)
.bind(days)
.execute(pool)
.await?;
Ok(result.rows_affected())
}

@ -1,3 +1,4 @@
pub mod article_history;
pub mod api_keys; pub mod api_keys;
pub mod audit; pub mod audit;
pub mod magic_links; pub mod magic_links;

Loading…
Cancel
Save