Skip to main content

contextdb_engine/
sync_types.rs

1//! Sync contract types for contextDB change-tracking and replication.
2//!
3//! These types define the public API for sync operations. The actual
4//! implementations are pending (all methods currently `unimplemented!()`).
5
6use contextdb_core::Value;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use uuid::Uuid;
10
11/// A set of changes extracted from a database since a given LSN.
12#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13pub struct ChangeSet {
14    pub rows: Vec<RowChange>,
15    pub edges: Vec<EdgeChange>,
16    pub vectors: Vec<VectorChange>,
17    pub ddl: Vec<DdlChange>,
18}
19
20impl ChangeSet {
21    /// Filters this changeset to only include tables matching the given directions.
22    pub fn filter_by_direction(
23        &self,
24        directions: &HashMap<String, SyncDirection>,
25        include: &[SyncDirection],
26    ) -> ChangeSet {
27        let include_dir = |table: &str| {
28            let dir = directions
29                .get(table)
30                .copied()
31                .unwrap_or(SyncDirection::Both);
32            include.contains(&dir)
33        };
34
35        ChangeSet {
36            rows: self
37                .rows
38                .iter()
39                .filter(|r| include_dir(&r.table))
40                .cloned()
41                .collect(),
42            edges: self.edges.clone(),
43            vectors: self.vectors.clone(),
44            ddl: self
45                .ddl
46                .iter()
47                .filter(|d| match d {
48                    DdlChange::CreateTable { name, .. } => include_dir(name),
49                    DdlChange::DropTable { name } => include_dir(name),
50                    DdlChange::AlterTable { name, .. } => include_dir(name),
51                })
52                .cloned()
53                .collect(),
54        }
55    }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct RowChange {
60    pub table: String,
61    pub natural_key: NaturalKey,
62    pub values: HashMap<String, Value>,
63    pub deleted: bool,
64    pub lsn: u64,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct EdgeChange {
69    pub source: Uuid,
70    pub target: Uuid,
71    pub edge_type: String,
72    pub properties: HashMap<String, Value>,
73    pub lsn: u64,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct VectorChange {
78    pub row_id: u64,
79    pub vector: Vec<f32>,
80    pub lsn: u64,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum DdlChange {
85    CreateTable {
86        name: String,
87        columns: Vec<(String, String)>,
88        constraints: Vec<String>,
89    },
90    DropTable {
91        name: String,
92    },
93    AlterTable {
94        name: String,
95        columns: Vec<(String, String)>,
96        constraints: Vec<String>,
97    },
98}
99
100#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
101pub struct NaturalKey {
102    pub column: String,
103    pub value: Value,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
107pub enum ConflictPolicy {
108    InsertIfNotExists,
109    ServerWins,
110    EdgeWins,
111    LatestWins,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct ConflictPolicies {
116    pub per_table: HashMap<String, ConflictPolicy>,
117    pub default: ConflictPolicy,
118}
119
120impl ConflictPolicies {
121    pub fn uniform(policy: ConflictPolicy) -> Self {
122        Self {
123            per_table: HashMap::new(),
124            default: policy,
125        }
126    }
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct ApplyResult {
131    pub applied_rows: usize,
132    pub skipped_rows: usize,
133    pub conflicts: Vec<Conflict>,
134    pub new_lsn: u64,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct Conflict {
139    pub natural_key: NaturalKey,
140    pub resolution: ConflictPolicy,
141    pub reason: Option<String>,
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
145pub enum SyncDirection {
146    Push,
147    Pull,
148    Both,
149    None,
150}