use chrono::NaiveDateTime;
use sea_orm::{ColumnTrait, ConnectionTrait, EntityTrait, QueryFilter};
use crate::entity::{self, Column};
use crate::error::AuditError;
pub async fn prune_older_than<C: ConnectionTrait>(
cutoff: NaiveDateTime,
conn: &C,
) -> Result<u64, AuditError> {
let result = entity::Entity::delete_many()
.filter(Column::CreatedAt.lt(cutoff))
.exec(conn)
.await?;
Ok(result.rows_affected)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::entry::AuditEntry;
use crate::target::AuditTarget;
use chrono::Utc;
use sea_orm::{Database, DatabaseConnection};
use sea_orm_migration::prelude::*;
use std::time::Duration;
struct TestMigrator;
#[async_trait::async_trait]
impl MigratorTrait for TestMigrator {
fn migrations() -> Vec<Box<dyn sea_orm_migration::MigrationTrait>> {
vec![Box::new(crate::migration::Migration)]
}
}
async fn fresh_db() -> DatabaseConnection {
let conn = Database::connect("sqlite::memory:")
.await
.expect("connect sqlite::memory:");
TestMigrator::up(&conn, None).await.expect("run migration");
conn
}
#[tokio::test]
async fn prune_older_than_test() {
let conn = fresh_db().await;
for i in 0..3 {
AuditEntry::record("test.old_event")
.target(AuditTarget::new("test", format!("old{i}")))
.write(&conn)
.await
.unwrap();
}
tokio::time::sleep(Duration::from_secs(2)).await;
let cutoff = Utc::now().naive_utc();
tokio::time::sleep(Duration::from_secs(2)).await;
for i in 0..2 {
AuditEntry::record("test.new_event")
.target(AuditTarget::new("test", format!("new{i}")))
.write(&conn)
.await
.unwrap();
}
let all_before = crate::query::recent(&conn, 100).await.unwrap();
assert_eq!(all_before.len(), 5, "should have 5 rows pre-prune");
let deleted = prune_older_than(cutoff, &conn).await.unwrap();
assert_eq!(deleted, 3, "should delete exactly the 3 old rows");
let all_after = crate::query::recent(&conn, 100).await.unwrap();
assert_eq!(all_after.len(), 2, "should have 2 rows post-prune");
assert!(
all_after.iter().all(|e| e.action == "test.new_event"),
"only new_event entries should survive"
);
let deleted_again = prune_older_than(cutoff, &conn).await.unwrap();
assert_eq!(deleted_again, 0);
}
}