1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt;
3
4use crate::{DocumentKey, Lsn, ObservedState, Revision};
5
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub enum WriteIntent {
8 Put(Vec<u8>),
9 Delete,
10}
11
12#[derive(Clone, Debug, Eq, PartialEq)]
15pub enum TransactionCondition {
16 RevisionEquals {
17 key: DocumentKey,
18 expected_revision: Revision,
19 },
20 Exists {
21 key: DocumentKey,
22 },
23 NotExists {
24 key: DocumentKey,
25 },
26}
27
28impl TransactionCondition {
29 pub fn key(&self) -> &DocumentKey {
30 match self {
31 Self::RevisionEquals { key, .. } | Self::Exists { key } | Self::NotExists { key } => {
32 key
33 }
34 }
35 }
36
37 pub fn expectation(&self) -> ConditionExpectation {
38 match self {
39 Self::RevisionEquals {
40 expected_revision, ..
41 } => ConditionExpectation::RevisionEquals(*expected_revision),
42 Self::Exists { .. } => ConditionExpectation::Exists,
43 Self::NotExists { .. } => ConditionExpectation::NotExists,
44 }
45 }
46}
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub enum ConditionExpectation {
51 RevisionEquals(Revision),
52 Exists,
53 NotExists,
54}
55
56#[derive(Clone, Debug, Eq, PartialEq)]
58pub enum TransactionMutation {
59 Put { key: DocumentKey, value: Vec<u8> },
60 Delete { key: DocumentKey },
61}
62
63impl TransactionMutation {
64 pub fn key(&self) -> &DocumentKey {
65 match self {
66 Self::Put { key, .. } | Self::Delete { key } => key,
67 }
68 }
69}
70
71#[derive(Clone, Debug, Default, Eq, PartialEq)]
73pub struct TransactionRequest {
74 pub conditions: Vec<TransactionCondition>,
75 pub mutations: Vec<TransactionMutation>,
76}
77
78impl TransactionRequest {
79 pub fn new(conditions: Vec<TransactionCondition>, mutations: Vec<TransactionMutation>) -> Self {
80 Self {
81 conditions,
82 mutations,
83 }
84 }
85
86 pub fn validate(&self) -> crate::Result<()> {
88 if self.conditions.is_empty() && self.mutations.is_empty() {
89 return Err(crate::Error::invalid_request(
90 "a transaction must contain at least one condition or mutation",
91 ));
92 }
93
94 let mut mutation_keys = BTreeSet::new();
95 for mutation in &self.mutations {
96 if !mutation_keys.insert(mutation.key().clone()) {
97 return Err(crate::Error::invalid_request(
98 "a transaction contains multiple mutations for one key",
99 ));
100 }
101 }
102
103 let mut condition_keys = BTreeSet::new();
104 for condition in &self.conditions {
105 if !condition_keys.insert(condition.key().clone()) {
106 return Err(crate::Error::invalid_request(
107 "a transaction contains multiple conditions for one key",
108 ));
109 }
110 }
111 Ok(())
112 }
113}
114
115#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub struct TransactionResult {
121 pub commit_lsn: Option<Lsn>,
122}
123
124#[derive(Clone, Debug, Eq, PartialEq)]
126pub struct TransactionConflict {
127 pub key: DocumentKey,
128 pub expected: ConditionExpectation,
129 pub actual: ObservedState,
130}
131
132impl fmt::Display for TransactionConflict {
133 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(
135 formatter,
136 "key {:?}: expected {:?}, actual {:?}",
137 self.key, self.expected, self.actual
138 )
139 }
140}
141
142#[derive(Clone, Debug, Default, Eq, PartialEq)]
143pub struct ReadSet(BTreeMap<DocumentKey, Revision>);
144
145impl ReadSet {
146 pub fn record(&mut self, key: DocumentKey, revision: Revision) {
147 self.0.entry(key).or_insert(revision);
148 }
149
150 pub fn get(&self, key: &DocumentKey) -> Option<Revision> {
151 self.0.get(key).copied()
152 }
153
154 pub fn iter(&self) -> impl Iterator<Item = (&DocumentKey, &Revision)> {
155 self.0.iter()
156 }
157
158 pub fn len(&self) -> usize {
159 self.0.len()
160 }
161
162 pub fn is_empty(&self) -> bool {
163 self.0.is_empty()
164 }
165}
166
167#[derive(Clone, Debug, Default, Eq, PartialEq)]
168pub struct WriteSet(BTreeMap<DocumentKey, WriteIntent>);
169
170impl WriteSet {
171 pub fn put(&mut self, key: DocumentKey, value: impl Into<Vec<u8>>) {
172 self.0.insert(key, WriteIntent::Put(value.into()));
173 }
174
175 pub fn delete(&mut self, key: DocumentKey) {
176 self.0.insert(key, WriteIntent::Delete);
177 }
178
179 pub fn get(&self, key: &DocumentKey) -> Option<&WriteIntent> {
180 self.0.get(key)
181 }
182
183 pub fn iter(&self) -> impl Iterator<Item = (&DocumentKey, &WriteIntent)> {
184 self.0.iter()
185 }
186
187 pub fn len(&self) -> usize {
188 self.0.len()
189 }
190
191 pub fn is_empty(&self) -> bool {
192 self.0.is_empty()
193 }
194}