- db: metadata_with_secret_snapshot / strip / parse 辅助 - add/update/delete/rollback 在写 entries_history 前合并快照 - rollback: 按历史快照同步 entry_secrets、更新或插入 secrets - 满足 clippy collapsible_if
65 lines
1.6 KiB
Rust
65 lines
1.6 KiB
Rust
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<Uuid>,
|
|
) -> Result<Vec<HistoryEntry>> {
|
|
#[derive(sqlx::FromRow)]
|
|
struct Row {
|
|
version: i64,
|
|
action: String,
|
|
created_at: chrono::DateTime<chrono::Utc>,
|
|
}
|
|
|
|
let entry = resolve_entry(pool, name, folder, user_id).await?;
|
|
|
|
let rows: Vec<Row> = 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<Uuid>,
|
|
) -> Result<Value> {
|
|
let entries = run(pool, name, folder, limit, user_id).await?;
|
|
Ok(serde_json::to_value(entries)?)
|
|
}
|