Skip to main content

reifydb_core/interface/
store.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_codec::{
5	key::encoded::{EncodedKey, EncodedKeyRange},
6	row::bytes::EncodedBytes,
7};
8use reifydb_value::{Result, util::cowvec::CowVec};
9
10use crate::{
11	common::CommitVersion,
12	delta::Delta,
13	interface::catalog::{object::ObjectId, storage::StorageId},
14	key::{EncodableKeyRange, Key, partitioned_row::PartitionedRowKeyRange, row::RowKeyRange},
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum Tier {
19	Buffer,
20	Persistent,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum EntryKind {
25	Multi,
26
27	Source(StorageId),
28
29	PartitionedSource(ObjectId),
30}
31
32pub fn classify_key(key: &EncodedKey) -> EntryKind {
33	match Key::decode(key) {
34		Some(Key::Row(row_key)) => EntryKind::Source(row_key.storage),
35		Some(Key::PartitionedRow(partitioned_key)) => EntryKind::PartitionedSource(partitioned_key.object),
36		_ => EntryKind::Multi,
37	}
38}
39
40pub fn classify_range(range: &EncodedKeyRange) -> Option<EntryKind> {
41	if let (Some(start), Some(_end)) = RowKeyRange::decode(range) {
42		return Some(EntryKind::Source(start.storage));
43	}
44
45	if let (Some(start), Some(_end)) = PartitionedRowKeyRange::decode(range) {
46		return Some(EntryKind::PartitionedSource(start.object));
47	}
48
49	None
50}
51
52#[derive(Debug, Clone)]
53pub struct MultiVersionRow {
54	pub key: EncodedKey,
55	pub bytes: EncodedBytes,
56	pub version: CommitVersion,
57}
58
59#[derive(Debug, Clone)]
60pub struct SingleVersionRow {
61	pub key: EncodedKey,
62	pub bytes: EncodedBytes,
63}
64
65#[derive(Debug, Clone)]
66pub struct MultiVersionBatch {
67	pub items: Vec<MultiVersionRow>,
68
69	pub has_more: bool,
70}
71
72impl MultiVersionBatch {
73	pub fn empty() -> Self {
74		Self {
75			items: Vec::new(),
76			has_more: false,
77		}
78	}
79
80	pub fn is_empty(&self) -> bool {
81		self.items.is_empty()
82	}
83}
84
85pub trait MultiVersionCommit: Send + Sync {
86	fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()>;
87}
88
89pub trait MultiVersionGet: Send + Sync {
90	fn get(&self, key: &EncodedKey, version: CommitVersion) -> Result<Option<MultiVersionRow>>;
91}
92
93pub trait MultiVersionContains: Send + Sync {
94	fn contains(&self, key: &EncodedKey, version: CommitVersion) -> Result<bool>;
95}
96
97pub trait MultiVersionGetPrevious: Send + Sync {
98	fn get_previous_version(
99		&self,
100		key: &EncodedKey,
101		before_version: CommitVersion,
102	) -> Result<Option<MultiVersionRow>>;
103}
104
105pub trait MultiVersionStore:
106	Send + Sync + Clone + MultiVersionCommit + MultiVersionGet + MultiVersionGetPrevious + MultiVersionContains + 'static
107{
108}
109
110#[derive(Debug, Clone)]
111pub struct SingleVersionBatch {
112	pub items: Vec<SingleVersionRow>,
113
114	pub has_more: bool,
115}
116
117impl SingleVersionBatch {
118	pub fn empty() -> Self {
119		Self {
120			items: Vec::new(),
121			has_more: false,
122		}
123	}
124
125	pub fn is_empty(&self) -> bool {
126		self.items.is_empty()
127	}
128}
129
130pub trait SingleVersionCommit: Send + Sync {
131	fn commit(&mut self, deltas: CowVec<Delta>) -> Result<()>;
132}
133
134pub trait SingleVersionGet: Send + Sync {
135	fn get(&self, key: &EncodedKey) -> Result<Option<SingleVersionRow>>;
136}
137
138pub trait SingleVersionContains: Send + Sync {
139	fn contains(&self, key: &EncodedKey) -> Result<bool>;
140}
141
142pub trait SingleVersionSet: SingleVersionCommit {
143	fn set(&mut self, key: &EncodedKey, bytes: EncodedBytes) -> Result<()> {
144		Self::commit(
145			self,
146			CowVec::new(vec![Delta::Set {
147				key: key.clone(),
148				bytes: bytes.clone(),
149			}]),
150		)
151	}
152}
153
154pub trait SingleVersionRemove: SingleVersionCommit {
155	fn remove(&mut self, key: &EncodedKey) -> Result<()> {
156		Self::commit(self, CowVec::new(vec![Delta::remove_silent(key.clone())]))
157	}
158}
159
160pub trait SingleVersionRange: Send + Sync {
161	fn range_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
162
163	fn range(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
164		self.range_batch(range, 1024)
165	}
166
167	fn prefix(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
168		self.range(EncodedKeyRange::prefix(prefix))
169	}
170}
171
172pub trait SingleVersionRangeRev: Send + Sync {
173	fn range_rev_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
174
175	fn range_rev(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
176		self.range_rev_batch(range, 1024)
177	}
178
179	fn prefix_rev(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
180		self.range_rev(EncodedKeyRange::prefix(prefix))
181	}
182}
183
184pub trait SingleVersionStore:
185	Send
186	+ Sync
187	+ Clone
188	+ SingleVersionCommit
189	+ SingleVersionGet
190	+ SingleVersionContains
191	+ SingleVersionSet
192	+ SingleVersionRemove
193	+ SingleVersionRange
194	+ SingleVersionRangeRev
195	+ 'static
196{
197}
198
199#[cfg(test)]
200mod tests {
201	use reifydb_value::value::{Value, partition::Partition, row_number::RowNumber};
202
203	use super::{EntryKind, classify_key, classify_range};
204	use crate::{
205		interface::catalog::{id::TableId, object::ObjectId, storage::StorageId},
206		key::{
207			partitioned_row::{PartitionedRowKey, RowLocator},
208			row::RowKey,
209		},
210	};
211
212	fn part(v: &str) -> Partition {
213		Partition::of(&[Value::Utf8(v.to_string())])
214	}
215
216	#[test]
217	fn classify_key_partitioned_row_is_partitioned_source() {
218		let object = ObjectId::Table(TableId(7));
219		let key = PartitionedRowKey::encoded(object, part("us"), RowLocator::Row(RowNumber(1)));
220		assert_eq!(classify_key(&key), EntryKind::PartitionedSource(object));
221	}
222
223	#[test]
224	fn classify_key_row_is_still_source() {
225		let storage = StorageId::Table(TableId(7));
226		let key = RowKey::encoded(storage, RowNumber(1));
227		assert_eq!(classify_key(&key), EntryKind::Source(storage));
228	}
229
230	#[test]
231	fn classify_range_all_partition_forms_are_partitioned_source() {
232		let object = ObjectId::Table(TableId(9));
233		let p = part("us");
234		let last = PartitionedRowKey::encoded(object, p, RowLocator::Row(RowNumber(5)));
235		assert_eq!(
236			classify_range(&PartitionedRowKey::partition_range(object, p)),
237			Some(EntryKind::PartitionedSource(object))
238		);
239		assert_eq!(
240			classify_range(&PartitionedRowKey::partition_scan_range(object, p, Some(&last))),
241			Some(EntryKind::PartitionedSource(object))
242		);
243		assert_eq!(
244			classify_range(&PartitionedRowKey::scan_range(object, None)),
245			Some(EntryKind::PartitionedSource(object))
246		);
247		assert_eq!(
248			classify_range(&PartitionedRowKey::full_scan(object)),
249			Some(EntryKind::PartitionedSource(object))
250		);
251	}
252
253	#[test]
254	fn classify_range_row_range_is_still_source() {
255		let storage = StorageId::Table(TableId(9));
256		assert_eq!(classify_range(&RowKey::full_scan(storage)), Some(EntryKind::Source(storage)));
257	}
258}