Skip to main content

faultline_diff/
model.rs

1use chrono::{DateTime, Utc};
2use faultline_core::{ChangeEvent, DatasetSnapshot};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7pub struct DiffRequest {
8    pub left: String,
9    pub right: String,
10    pub layer: Option<String>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct DiffSummary {
15    pub diff_id: Uuid,
16    pub added: u64,
17    pub removed: u64,
18    pub changed: u64,
19}
20
21impl DiffSummary {
22    pub fn empty() -> Self {
23        Self {
24            diff_id: Uuid::new_v4(),
25            added: 0,
26            removed: 0,
27            changed: 0,
28        }
29    }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
33pub enum DiffClassification {
34    Deterministic,
35    NoChanges,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
39pub struct SnapshotState {
40    pub snapshot: DatasetSnapshot,
41    pub features: Vec<faultline_core::FeatureRef>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
45pub struct DiffArtifact {
46    pub artifact_id: Uuid,
47    pub generated_at: DateTime<Utc>,
48    pub classification: DiffClassification,
49    pub left_snapshot_id: Uuid,
50    pub right_snapshot_id: Uuid,
51    pub summary: DiffSummary,
52    pub change_events: Vec<ChangeEvent>,
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn summary_empty_starts_at_zero() {
61        let summary = DiffSummary::empty();
62
63        assert_eq!(summary.added, 0);
64        assert_eq!(summary.removed, 0);
65        assert_eq!(summary.changed, 0);
66    }
67
68    #[test]
69    fn diff_artifact_round_trip_serialization() {
70        let snapshot = DatasetSnapshot::new("roads");
71        let summary = DiffSummary::empty();
72        let artifact = DiffArtifact {
73            artifact_id: Uuid::new_v4(),
74            generated_at: Utc::now(),
75            classification: DiffClassification::NoChanges,
76            left_snapshot_id: snapshot.snapshot_id,
77            right_snapshot_id: snapshot.snapshot_id,
78            summary,
79            change_events: Vec::new(),
80        };
81
82        let json = serde_json::to_string(&artifact).expect("serialize artifact");
83        let restored: DiffArtifact = serde_json::from_str(&json).expect("deserialize artifact");
84
85        assert_eq!(restored.classification, DiffClassification::NoChanges);
86        assert!(restored.change_events.is_empty());
87    }
88}