use std::sync::atomic::Ordering;
use cratestack_core::CoolError;
use crate::SqlxRuntime;
use crate::sqlx;
pub const AUDIT_TABLE_DDL: &str = r#"
CREATE TABLE IF NOT EXISTS cratestack_audit (
event_id UUID PRIMARY KEY,
schema_name TEXT NOT NULL,
model TEXT NOT NULL,
operation TEXT NOT NULL,
primary_key JSONB NOT NULL,
actor JSONB NOT NULL,
tenant TEXT,
before JSONB,
after JSONB,
request_id TEXT,
occurred_at TIMESTAMPTZ NOT NULL,
delivered_at TIMESTAMPTZ,
attempts BIGINT NOT NULL DEFAULT 0,
last_error TEXT
);
CREATE INDEX IF NOT EXISTS cratestack_audit_model_idx
ON cratestack_audit (schema_name, model, occurred_at DESC);
CREATE INDEX IF NOT EXISTS cratestack_audit_tenant_idx
ON cratestack_audit (tenant, occurred_at DESC)
WHERE tenant IS NOT NULL;
CREATE INDEX IF NOT EXISTS cratestack_audit_undelivered_idx
ON cratestack_audit (occurred_at)
WHERE delivered_at IS NULL;
"#;
pub(crate) async fn ensure_audit_table(runtime: &SqlxRuntime) -> Result<(), CoolError> {
if runtime.audit_table_ensured().load(Ordering::Acquire) {
return Ok(());
}
sqlx::raw_sql(AUDIT_TABLE_DDL)
.execute(runtime.pool())
.await
.map_err(|error| CoolError::Database(error.to_string()))?;
runtime.audit_table_ensured().store(true, Ordering::Release);
Ok(())
}