Skip to main content

oxide_mirror/
event.rs

1//! Delta + record shapes shared across the mirror.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// Whether a delta inserts/updates or deletes a record.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum DeltaOp {
10    /// Insert the record if it does not exist, or replace the payload.
11    Upsert,
12    /// Delete the record. `payload` is ignored.
13    Delete,
14}
15
16/// A single change-set emitted by a [`SyncSource`](crate::source::SyncSource).
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Delta {
19    /// Resource (table) the delta applies to, e.g. `"pets"`.
20    pub resource: String,
21    /// Stable id of the record within the resource.
22    pub record_id: String,
23    /// Operation kind.
24    pub op: DeltaOp,
25    /// Record payload (JSON object). For `Delete` this is typically
26    /// [`serde_json::Value::Null`].
27    pub payload: serde_json::Value,
28    /// When the source observed the change.
29    pub occurred_at: DateTime<Utc>,
30    /// Source + confidence metadata.
31    pub provenance: Provenance,
32}
33
34impl Delta {
35    /// Convenience: build an upsert delta.
36    pub fn upsert(
37        resource: impl Into<String>,
38        record_id: impl Into<String>,
39        payload: serde_json::Value,
40        source: impl Into<String>,
41    ) -> Self {
42        Self {
43            resource: resource.into(),
44            record_id: record_id.into(),
45            op: DeltaOp::Upsert,
46            payload,
47            occurred_at: Utc::now(),
48            provenance: Provenance::new(source),
49        }
50    }
51
52    /// Convenience: build a delete delta.
53    pub fn delete(
54        resource: impl Into<String>,
55        record_id: impl Into<String>,
56        source: impl Into<String>,
57    ) -> Self {
58        Self {
59            resource: resource.into(),
60            record_id: record_id.into(),
61            op: DeltaOp::Delete,
62            payload: serde_json::Value::Null,
63            occurred_at: Utc::now(),
64            provenance: Provenance::new(source),
65        }
66    }
67
68    /// Builder helper to override the default confidence.
69    #[must_use]
70    pub fn with_confidence(mut self, confidence: f32) -> Self {
71        self.provenance.confidence = confidence.clamp(0.0, 1.0);
72        self
73    }
74
75    /// Builder helper to set a specific occurrence time.
76    #[must_use]
77    pub fn at(mut self, ts: DateTime<Utc>) -> Self {
78        self.occurred_at = ts;
79        self
80    }
81}
82
83/// Source + confidence metadata attached to every delta and stored alongside
84/// every mirrored record.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct Provenance {
87    /// Stable id of the source that produced the delta.
88    pub source: String,
89    /// Confidence in the payload, in `[0.0, 1.0]`. Sources that have no
90    /// notion of confidence should report `1.0`.
91    pub confidence: f32,
92}
93
94impl Provenance {
95    /// Build a provenance with `confidence = 1.0`.
96    pub fn new(source: impl Into<String>) -> Self {
97        Self {
98            source: source.into(),
99            confidence: 1.0,
100        }
101    }
102}
103
104/// A materialised record in the local mirror.
105///
106/// Every column on this struct maps to a column in `mirror_records`.
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct MirroredRecord {
109    /// Resource the record belongs to.
110    pub resource: String,
111    /// Stable record id.
112    pub record_id: String,
113    /// Last successfully-applied payload.
114    pub payload: serde_json::Value,
115    /// Source that wrote the latest version.
116    pub source: String,
117    /// Wall-clock time of the latest successful apply.
118    pub last_synced_at: DateTime<Utc>,
119    /// Confidence of the latest payload.
120    pub confidence: f32,
121    /// Monotonic per-record version, incremented on every successful apply.
122    pub version: i64,
123}