1use contextdb_core::Value;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use uuid::Uuid;
10
11#[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 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}