use rusqlite::Connection;
use zer_core::{
entity::{EntityId, ResolutionMethod},
error::ZerError,
record::RecordId,
};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum ResolutionEvent {
EntityCreated {
entity_id: EntityId,
record_ids: Vec<RecordId>,
},
RecordsAdded {
entity_id: EntityId,
record_ids: Vec<RecordId>,
method: ResolutionMethod,
},
EntityMerged {
source_a: EntityId,
source_b: EntityId,
into: EntityId,
},
EntitySplit {
source: EntityId,
into: Vec<EntityId>,
},
JudgeApplied {
entity_id: EntityId,
pair: (RecordId, RecordId),
verdict: String,
},
}
pub fn append_event(conn: &Connection, event: &ResolutionEvent) -> Result<(), ZerError> {
let (event_type, entity_id, record_ids, score, judge_verdict) = match event {
ResolutionEvent::EntityCreated {
entity_id,
record_ids,
} => (
"EntityCreated",
*entity_id,
record_ids.clone(),
None::<f32>,
None::<String>,
),
ResolutionEvent::RecordsAdded {
entity_id,
record_ids,
..
} => ("RecordsAdded", *entity_id, record_ids.clone(), None, None),
ResolutionEvent::EntityMerged {
into,
source_a,
source_b,
} => (
"EntityMerged",
*into,
vec![*source_a, *source_b],
None,
None,
),
ResolutionEvent::EntitySplit { source, into } => {
("EntitySplit", *source, into.clone(), None, None)
}
ResolutionEvent::JudgeApplied {
entity_id,
pair,
verdict,
} => (
"JudgeApplied",
*entity_id,
vec![pair.0, pair.1],
None,
Some(verdict.clone()),
),
};
let ids_json =
serde_json::to_string(&record_ids).map_err(|e| ZerError::Serialization(e.to_string()))?;
let now = unix_now();
conn.execute(
"INSERT INTO resolution_events
(event_type, entity_id, record_ids, score, judge_verdict, occurred_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
rusqlite::params![
event_type,
entity_id as i64,
ids_json,
score,
judge_verdict,
now
],
)
.map_err(|e| ZerError::Store(e.to_string()))?;
Ok(())
}
pub(crate) fn unix_now() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0)
}