use rusqlite::{OptionalExtension, params}; use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use crate::{domain::FolderId, storage::StateStore}; impl StateStore { pub fn record_successful_sync(&self, folder_id: FolderId) -> anyhow::Result<()> { let completed_at = OffsetDateTime::now_utc().format(&Rfc3339)?; self.connection.execute( "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, ?2, NULL) ON CONFLICT(folder_id) DO UPDATE SET last_successful_sync = excluded.last_successful_sync, last_error = NULL", params![folder_id.to_string(), completed_at], )?; Ok(()) } pub fn record_sync_failure( &self, folder_id: FolderId, error: &anyhow::Error, ) -> anyhow::Result<()> { self.connection.execute( "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, NULL, ?2) ON CONFLICT(folder_id) DO UPDATE SET last_error = excluded.last_error", params![folder_id.to_string(), error.to_string()], )?; Ok(()) } pub fn last_successful_sync( &self, folder_id: FolderId, ) -> anyhow::Result> { let timestamp: Option = self .connection .query_row( "SELECT last_successful_sync FROM sync_state WHERE folder_id = ?1", params![folder_id.to_string()], |row| row.get(0), ) .optional()?; timestamp .map(|value| OffsetDateTime::parse(&value, &Rfc3339).map_err(Into::into)) .transpose() } pub fn last_sync_error(&self, folder_id: FolderId) -> anyhow::Result> { self.connection .query_row( "SELECT last_error FROM sync_state WHERE folder_id = ?1", params![folder_id.to_string()], |row| row.get(0), ) .optional() .map(|value| value.flatten()) .map_err(Into::into) } }