1use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate::store_commit::{
8 AcceptedStoreSnapshotRef, StoreBatchCommitRef, StoreCommitCoord, StoreDeviceRegistrationRef,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct WriteId(String);
15
16impl WriteId {
17 pub fn from_generated(value: String) -> Self {
18 Self(value)
19 }
20
21 pub fn as_str(&self) -> &str {
22 &self.0
23 }
24}
25
26impl fmt::Display for WriteId {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 formatter.write_str(&self.0)
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(deny_unknown_fields)]
35pub struct PublishedPosition {
36 pub device_id: String,
37 pub commit: StoreBatchCommitRef,
38}
39
40impl PublishedPosition {
41 pub fn commit(&self) -> &StoreBatchCommitRef {
42 &self.commit
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49#[serde(deny_unknown_fields)]
50pub struct SnapshotCoveredPosition {
51 pub author_registration: StoreDeviceRegistrationRef,
52 pub coord: StoreCommitCoord,
53 pub snapshot: AcceptedStoreSnapshotRef,
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58#[serde(rename_all = "snake_case", deny_unknown_fields)]
59pub enum PublishedWrite {
60 Commit(PublishedPosition),
61 Snapshot(SnapshotCoveredPosition),
62}
63
64impl PublishedWrite {
65 pub fn coord(&self) -> &StoreCommitCoord {
66 match self {
67 Self::Commit(position) => &position.commit.coord,
68 Self::Snapshot(position) => &position.coord,
69 }
70 }
71
72 pub fn exact_commit(&self) -> Option<&StoreBatchCommitRef> {
73 match self {
74 Self::Commit(position) => Some(position.commit()),
75 Self::Snapshot(_) => None,
76 }
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case", deny_unknown_fields)]
83pub enum WriteBlock {
84 RebaseConflict(WriteRebaseConflict),
85 InvalidPackage {
86 reason: String,
87 },
88 InvalidProtocolState {
89 reason: String,
90 },
91 MissingBlob {
92 namespace: String,
93 id: String,
94 },
95 LocalUserBlob {
96 namespace: String,
97 id: String,
98 },
99 RotationRequired {
100 circle_id: crate::circle::CircleId,
101 removed_members: Vec<String>,
102 },
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[serde(rename_all = "snake_case", deny_unknown_fields)]
108pub enum WriteStatus {
109 LocalOnly,
110 LocalOnlyBlocked(WriteBlock),
112 Pending,
113 Publishing,
114 Published(Box<PublishedWrite>),
115 Blocked(WriteBlock),
116 Resolved(WriteResolution),
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "snake_case", deny_unknown_fields)]
121pub enum WriteResolution {
122 Discarded,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
127#[serde(deny_unknown_fields)]
128pub struct AffectedRow {
129 pub table: String,
130 pub primary_key: String,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, thiserror::Error)]
135#[serde(deny_unknown_fields)]
136#[error("write {write_id} cannot rebase rows {affected_rows:?}: {reason}")]
137pub struct WriteRebaseConflict {
138 pub write_id: WriteId,
139 pub affected_rows: Vec<AffectedRow>,
142 pub reason: WriteRebaseConflictReason,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, thiserror::Error)]
146#[serde(rename_all = "snake_case", deny_unknown_fields)]
147pub enum WriteRebaseConflictReason {
148 #[error("the private edit conflicts with an accepted shared row")]
149 PrivateShared,
150 #[error("Circle {circle_id} no longer authorizes the captured edit")]
151 InvalidCircleContext { circle_id: crate::circle::CircleId },
152 #[error("the edit violates a constraint: {message}")]
153 Constraint { message: String },
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct PendingWrite {
159 pub write_id: WriteId,
160 pub status: WriteStatus,
161 pub affected_rows: Vec<AffectedRow>,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct WriteReceipt<R> {
167 pub value: R,
168 pub write_id: WriteId,
169 pub status: WriteStatus,
170}