Skip to main content

reifydb_transaction/multi/
types.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4// This file includes and modifies code from the skipdb project (https://github.com/al8n/skipdb),
5// originally licensed under the Apache License, Version 2.0.
6// Original copyright:
7//   Copyright (c) 2024 Al Liu
8//
9// The original Apache License can be found at:
10//   http://www.apache.org/licenses/LICENSE-2.0
11
12use std::{cmp, cmp::Reverse};
13
14use reifydb_core::{
15	common::CommitVersion,
16	delta::Delta,
17	encoded::{encoded::EncodedValues, key::EncodedKey},
18	interface::store::MultiVersionValues,
19};
20use reifydb_type::util::cowvec::CowVec;
21
22pub enum TransactionValue {
23	PendingIter {
24		version: CommitVersion,
25		key: EncodedKey,
26		values: EncodedValues,
27	},
28	Pending(Pending),
29	Committed(Committed),
30}
31
32impl From<MultiVersionValues> for TransactionValue {
33	fn from(value: MultiVersionValues) -> Self {
34		Self::Committed(Committed {
35			key: value.key,
36			values: value.values,
37			version: value.version,
38		})
39	}
40}
41
42impl core::fmt::Debug for TransactionValue {
43	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44		f.debug_struct("TransactionValue")
45			.field("key", self.key())
46			.field("version", &self.version())
47			.field("value", &self.values())
48			.finish()
49	}
50}
51
52impl Clone for TransactionValue {
53	fn clone(&self) -> Self {
54		match self {
55			Self::Committed(item) => Self::Committed(item.clone()),
56			Self::Pending(delta) => Self::Pending(delta.clone()),
57			Self::PendingIter {
58				version,
59				key,
60				values: value,
61			} => Self::PendingIter {
62				version: *version,
63				key: key.clone(),
64				values: value.clone(),
65			},
66		}
67	}
68}
69
70impl TransactionValue {
71	pub fn key(&self) -> &EncodedKey {
72		match self {
73			Self::PendingIter {
74				key,
75				..
76			} => key,
77			Self::Pending(item) => item.key(),
78			Self::Committed(item) => item.key(),
79		}
80	}
81
82	pub fn version(&self) -> CommitVersion {
83		match self {
84			Self::PendingIter {
85				version,
86				..
87			} => *version,
88			Self::Pending(item) => item.version(),
89			Self::Committed(item) => item.version(),
90		}
91	}
92
93	pub fn values(&self) -> &EncodedValues {
94		match self {
95			Self::PendingIter {
96				values,
97				..
98			} => values,
99			Self::Pending(item) => item.values().expect("encoded of pending cannot be `None`"),
100			Self::Committed(item) => &item.values,
101		}
102	}
103
104	pub fn is_committed(&self) -> bool {
105		matches!(self, Self::Committed(_))
106	}
107
108	pub fn into_multi_version_values(self) -> MultiVersionValues {
109		match self {
110			Self::PendingIter {
111				version,
112				key,
113				values,
114			} => MultiVersionValues {
115				key,
116				values,
117				version,
118			},
119			Self::Pending(item) => match item.delta {
120				Delta::Set {
121					key,
122					values,
123				} => MultiVersionValues {
124					key,
125					values,
126					version: item.version,
127				},
128				Delta::Unset {
129					key,
130					..
131				}
132				| Delta::Remove {
133					key,
134				}
135				| Delta::Drop {
136					key,
137					..
138				} => MultiVersionValues {
139					key,
140					values: EncodedValues(CowVec::default()),
141					version: item.version,
142				},
143			},
144			Self::Committed(item) => MultiVersionValues {
145				key: item.key,
146				values: item.values,
147				version: item.version,
148			},
149		}
150	}
151}
152
153impl From<(CommitVersion, EncodedKey, EncodedValues)> for TransactionValue {
154	fn from((version, k, b): (CommitVersion, EncodedKey, EncodedValues)) -> Self {
155		Self::PendingIter {
156			version,
157			key: k,
158			values: b,
159		}
160	}
161}
162
163impl From<(CommitVersion, &EncodedKey, &EncodedValues)> for TransactionValue {
164	fn from((version, k, b): (CommitVersion, &EncodedKey, &EncodedValues)) -> Self {
165		Self::PendingIter {
166			version,
167			key: k.clone(),
168			values: b.clone(),
169		}
170	}
171}
172
173impl From<Pending> for TransactionValue {
174	fn from(pending: Pending) -> Self {
175		Self::Pending(pending)
176	}
177}
178
179impl From<Committed> for TransactionValue {
180	fn from(item: Committed) -> Self {
181		Self::Committed(item)
182	}
183}
184
185#[derive(Clone, Debug)]
186pub struct Committed {
187	pub(crate) key: EncodedKey,
188	pub(crate) values: EncodedValues,
189	pub(crate) version: CommitVersion,
190}
191
192impl From<MultiVersionValues> for Committed {
193	fn from(value: MultiVersionValues) -> Self {
194		Self {
195			key: value.key,
196			values: value.values,
197			version: value.version,
198		}
199	}
200}
201
202impl Committed {
203	pub fn key(&self) -> &EncodedKey {
204		&self.key
205	}
206
207	pub fn values(&self) -> &EncodedValues {
208		&self.values
209	}
210
211	pub fn version(&self) -> CommitVersion {
212		self.version
213	}
214}
215
216#[derive(Debug, PartialEq, Eq)]
217pub struct Pending {
218	pub delta: Delta,
219	pub version: CommitVersion,
220}
221
222impl PartialOrd for Pending {
223	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
224		Some(self.cmp(other))
225	}
226}
227
228impl Ord for Pending {
229	fn cmp(&self, other: &Self) -> cmp::Ordering {
230		self.delta.key().cmp(other.delta.key()).then_with(|| Reverse(self.version).cmp(&Reverse(other.version)))
231	}
232}
233
234impl Clone for Pending {
235	fn clone(&self) -> Self {
236		Self {
237			version: self.version,
238			delta: self.delta.clone(),
239		}
240	}
241}
242
243impl Pending {
244	pub fn delta(&self) -> &Delta {
245		&self.delta
246	}
247
248	pub fn version(&self) -> CommitVersion {
249		self.version
250	}
251
252	pub fn into_components(self) -> (CommitVersion, Delta) {
253		(self.version, self.delta)
254	}
255
256	pub fn key(&self) -> &EncodedKey {
257		self.delta.key()
258	}
259
260	pub fn values(&self) -> Option<&EncodedValues> {
261		self.delta.values()
262	}
263
264	pub fn was_removed(&self) -> bool {
265		matches!(self.delta, Delta::Unset { .. } | Delta::Remove { .. })
266	}
267}