1use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate::sync::store_commit::{StoreBatchCommitRef, StoreSerialPredecessor};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum WritePolicy {
14 MergeConcurrent,
15 Serial,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20#[serde(transparent)]
21pub struct WriteId(String);
22
23impl WriteId {
24 pub(crate) fn from_generated(value: String) -> Self {
25 Self(value)
26 }
27
28 pub fn as_str(&self) -> &str {
29 &self.0
30 }
31}
32
33impl fmt::Display for WriteId {
34 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
35 formatter.write_str(&self.0)
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
41#[serde(rename_all = "snake_case", deny_unknown_fields)]
42pub enum PublishedPosition {
43 MergeConcurrent {
44 device_id: String,
45 commit: StoreBatchCommitRef,
46 },
47 Serial {
48 commit: StoreBatchCommitRef,
49 },
50}
51
52impl PublishedPosition {
53 pub fn commit(&self) -> &StoreBatchCommitRef {
54 match self {
55 Self::MergeConcurrent { commit, .. } | Self::Serial { commit } => commit,
56 }
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
62#[serde(transparent)]
63pub struct PendingBranchId(WriteId);
64
65impl PendingBranchId {
66 pub(crate) fn from_first_write(write_id: WriteId) -> Self {
67 Self(write_id)
68 }
69
70 pub fn first_write_id(&self) -> &WriteId {
71 &self.0
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(deny_unknown_fields)]
78pub struct SerializationConflict {
79 pub branch_id: PendingBranchId,
80 pub base: StoreSerialPredecessor,
81 pub current: StoreSerialPredecessor,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
86#[serde(rename_all = "snake_case", deny_unknown_fields)]
87pub enum WriteBlock {
88 InvalidPackage { reason: String },
89 InvalidProtocolState { reason: String },
90 MissingBlob { namespace: String, id: String },
91 LocalUserBlob { namespace: String, id: String },
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96#[serde(rename_all = "snake_case", deny_unknown_fields)]
97pub enum WriteStatus {
98 LocalOnly,
99 Pending,
100 Publishing,
101 Published(Box<PublishedPosition>),
102 Conflict(Box<SerializationConflict>),
103 Blocked(WriteBlock),
104 Resolved(WriteResolution),
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108#[serde(rename_all = "snake_case", deny_unknown_fields)]
109pub enum WriteResolution {
110 Discarded,
111 Replaced { replacement: WriteId },
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
116#[serde(deny_unknown_fields)]
117pub struct AffectedRow {
118 pub table: String,
119 pub primary_key: String,
120}
121
122#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct PendingWrite {
125 pub write_id: WriteId,
126 pub status: WriteStatus,
127 pub affected_rows: Vec<AffectedRow>,
128}
129
130#[derive(Debug, Clone, PartialEq, Eq)]
131pub struct PendingBranch {
132 pub branch_id: PendingBranchId,
133 pub base: StoreSerialPredecessor,
134 pub current: StoreSerialPredecessor,
135 pub writes: Vec<PendingWrite>,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct WriteReceipt<R> {
141 pub value: R,
142 pub write_id: WriteId,
143 pub status: WriteStatus,
144 pub pending_branch_id: Option<PendingBranchId>,
147}