use anyhow::Result; use serde_json::Value; use sqlx::PgPool; use uuid::Uuid; use crate::service::search::resolve_entry; #[derive(Debug, serde::Serialize)] pub struct HistoryEntry { pub version: i64, pub action: String, pub created_at: String, } /// Return version history for the entry identified by `name`. /// `folder` is optional; if omitted and multiple entries share the name, an error is returned. pub async fn run( pool: &PgPool, name: &str, folder: Option<&str>, limit: u32, user_id: Option, ) -> Result> { #[derive(sqlx::FromRow)] struct Row { version: i64, action: String, created_at: chrono::DateTime, } let entry = resolve_entry(pool, name, folder, user_id).await?; let rows: Vec = sqlx::query_as( "SELECT DISTINCT ON (version) version, action, created_at \ FROM entries_history \ WHERE entry_id = $1 \ ORDER BY version DESC, id DESC \ LIMIT $2", ) .bind(entry.id) .bind(limit as i64) .fetch_all(pool) .await?; Ok(rows .into_iter() .map(|r| HistoryEntry { version: r.version, action: r.action, created_at: r.created_at.format("%Y-%m-%dT%H:%M:%SZ").to_string(), }) .collect()) } pub async fn run_json( pool: &PgPool, name: &str, folder: Option<&str>, limit: u32, user_id: Option, ) -> Result { let entries = run(pool, name, folder, limit, user_id).await?; Ok(serde_json::to_value(entries)?) }