diff --git a/src/feeds.rs b/src/feeds.rs index d8666d2..09576b3 100644 --- a/src/feeds.rs +++ b/src/feeds.rs @@ -31,7 +31,7 @@ impl Feed { url, user_id, added_time: now, - last_checked_time: now, + last_checked_time: chrono::DateTime::UNIX_EPOCH, categorization: Vec::new(), } } diff --git a/src/poll.rs b/src/poll.rs index e37529e..a5f409c 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -4,8 +4,9 @@ use chrono::{DateTime, Utc}; use feed_rs::model::Text; use rocket::http::Status; use rocket::serde::uuid::Uuid; -use rocket::serde::{json::Json, Serialize}; +use rocket::serde::{self, json::Json, Serialize}; use rocket_db_pools::Connection; +use sqlx::Acquire; #[derive(Debug, Serialize)] #[serde(crate = "rocket::serde")] @@ -57,7 +58,7 @@ pub async fn poll_feed( .unwrap_or(format!("")) } - let entries = feed_data + let entries: Vec = feed_data .entries .into_iter() .map(|feed_entry| Entry { @@ -71,5 +72,61 @@ pub async fn poll_feed( }) .collect(); + // Start a transaction for batch update + let mut tx = db.begin().await.map_err(|e| { + eprintln!("Failed to start transaction: {}", e); + Status::InternalServerError + })?; + + let now = Utc::now().to_rfc3339(); + for entry in &entries { + let content_json = if let Some(content) = &entry.content { + serde::json::to_string(content).ok() + } else { + None + }; + + let result = sqlx::query( + r#" + INSERT INTO feed_entries ( + id, feed_id, title, published, updated, summary, content, link, created_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT (feed_id, id) DO UPDATE SET + title = excluded.title, + published = excluded.published, + updated = excluded.updated, + summary = excluded.summary, + content = excluded.content, + link = excluded.link + "# + ) + .bind(&entry.id) + .bind(&feed_id) + .bind(&entry.title) + .bind(entry.published.map(|dt| dt.to_rfc3339())) + .bind(entry.updated.map(|dt| dt.to_rfc3339())) + .bind(&entry.summary) + .bind(content_json) + .bind(&entry.link) + .bind(&now) + .execute(&mut *tx) + .await; + + if let Err(e) = result { + eprintln!("Failed to save feed entry: {}", e); + tx.rollback().await.map_err(|e| { + eprintln!("Failed to rollback transaction: {}", e); + Status::InternalServerError + })?; + return Err(Status::InternalServerError); + } + } + + // Commit the transaction + tx.commit().await.map_err(|e| { + eprintln!("Failed to commit transaction: {}", e); + Status::InternalServerError + })?; + Ok(Json(FeedPollResponse { count, entries })) }