1use std::ops::Bound;
5
6use reifydb_codec::key::encoded::EncodedKey;
7use reifydb_macro::KeyCodec;
8use reifydb_runtime::version_epoch::EpochSeconds;
9use serde::{Deserialize, Serialize, de};
10
11use super::KeyTag;
12use crate::{
13 interface::catalog::id::{MigrationEventId, MigrationId, SequenceId},
14 key::{
15 any::{Field, KeyFields, Width},
16 bound::{TaggedKeyBound, TaggedKeyBoundRange},
17 },
18};
19
20#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
21#[key(tag = SystemSequence)]
22pub struct SystemSequenceKey {
23 pub sequence: SequenceId,
24}
25
26impl SystemSequenceKey {
27 pub fn new(sequence: impl Into<SequenceId>) -> Self {
28 Self {
29 sequence: sequence.into(),
30 }
31 }
32
33 pub fn encoded(sequence: impl Into<SequenceId>) -> EncodedKey {
34 Self {
35 sequence: sequence.into(),
36 }
37 .encode()
38 }
39
40 pub fn full_scan() -> TaggedKeyBoundRange {
41 TaggedKeyBoundRange::kind(Self::TAG)
42 }
43}
44
45#[cfg(test)]
46pub mod system_sequence_key_tests {
47 use super::SystemSequenceKey;
48 use crate::interface::catalog::id::SequenceId;
49
50 #[test]
51 fn test_encode_decode() {
52 let key = SystemSequenceKey {
53 sequence: SequenceId(0xABCD),
54 };
55 let encoded = key.encode();
56 let expected = vec![0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x32];
57 assert_eq!(encoded.as_slice(), expected);
58
59 let key = SystemSequenceKey::decode(&encoded).unwrap();
60 assert_eq!(key.sequence.0, 0xABCD);
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
65#[key(tag = SystemVersion)]
66pub struct SystemVersionKey {
67 #[key(repr = u8)]
68 pub version: SystemVersion,
69}
70
71#[repr(u8)]
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
73#[serde(try_from = "u8", into = "u8")]
74pub enum SystemVersion {
75 Storage = 0x01,
76}
77
78impl From<SystemVersion> for u8 {
79 fn from(version: SystemVersion) -> Self {
80 version as u8
81 }
82}
83impl TryFrom<u8> for SystemVersion {
84 type Error = de::value::Error;
85
86 fn try_from(value: u8) -> Result<Self, Self::Error> {
87 match value {
88 0x01 => Ok(Self::Storage),
89 _ => Err(de::Error::custom(format!("Invalid SystemVersion value: {value:#04x}"))),
90 }
91 }
92}
93
94impl SystemVersionKey {
95 pub fn new(version: SystemVersion) -> Self {
96 Self {
97 version,
98 }
99 }
100
101 pub fn encoded(version: SystemVersion) -> EncodedKey {
102 Self {
103 version,
104 }
105 .encode()
106 }
107}
108
109#[cfg(test)]
110pub mod system_version_key_tests {
111 use super::{SystemVersion, SystemVersionKey};
112
113 #[test]
114 fn test_encode_decode_storage_version() {
115 let key = SystemVersionKey {
116 version: SystemVersion::Storage,
117 };
118 let encoded = key.encode();
119 let expected = vec![0xF5, 0xFE];
120 assert_eq!(encoded.as_slice(), expected);
121
122 let key = SystemVersionKey::decode(&encoded).unwrap();
123 assert_eq!(key.version, SystemVersion::Storage);
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
128#[key(tag = TransactionVersion)]
129pub struct TransactionVersionKey {}
130
131impl TransactionVersionKey {
132 pub fn encoded() -> EncodedKey {
133 Self {}.encode()
134 }
135}
136
137#[cfg(test)]
138pub mod transaction_version_key_tests {
139 use super::TransactionVersionKey;
140
141 #[test]
142 fn test_encode_decode() {
143 let key = TransactionVersionKey {};
144 let encoded = key.encode();
145 let expected = vec![0xF4];
146 assert_eq!(encoded.as_slice(), expected);
147
148 TransactionVersionKey::decode(&encoded).unwrap();
149 }
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, KeyCodec, Hash)]
153#[key(tag = VersionEpoch)]
154pub struct VersionEpochKey {
155 pub bucket: EpochSeconds,
156}
157
158impl VersionEpochKey {
159 pub fn new(bucket: EpochSeconds) -> Self {
160 Self {
161 bucket,
162 }
163 }
164
165 pub fn encoded(bucket: EpochSeconds) -> EncodedKey {
166 Self::new(bucket).encode()
167 }
168
169 fn bucket_bound(bucket: EpochSeconds) -> TaggedKeyBound {
170 TaggedKeyBound::prefix(Self::TAG, [Field::UDesc(Width::U64, bucket.seconds() as u128)])
171 }
172
173 pub fn floor_scan(target: EpochSeconds) -> TaggedKeyBoundRange {
174 TaggedKeyBoundRange {
175 start: Bound::Included(Self::bucket_bound(target)),
176 end: Bound::Included(Self::bucket_bound(EpochSeconds::new(0))),
177 }
178 }
179
180 pub fn older_than(cutoff: EpochSeconds) -> TaggedKeyBoundRange {
181 TaggedKeyBoundRange {
182 start: Bound::Excluded(Self::bucket_bound(cutoff)),
183 end: Bound::Included(Self::bucket_bound(EpochSeconds::new(0))),
184 }
185 }
186}
187
188#[cfg(test)]
189mod version_epoch_key_tests {
190 use std::ops::Bound;
191
192 use super::{EpochSeconds, VersionEpochKey};
193
194 fn sec(seconds: u64) -> EpochSeconds {
195 EpochSeconds::new(seconds)
196 }
197
198 #[test]
199 fn test_encode_decode() {
200 let key = VersionEpochKey {
201 bucket: sec(0x0123456789ABCDEF),
202 };
203 let encoded = key.encode();
204 let decoded = VersionEpochKey::decode(&encoded).unwrap();
205 assert_eq!(decoded.bucket, sec(0x0123456789ABCDEF));
206 }
207
208 #[test]
209 fn test_descending_order_so_newer_bucket_sorts_first() {
210 let older = VersionEpochKey::encoded(sec(100));
211 let newer = VersionEpochKey::encoded(sec(200));
212 assert!(
213 newer < older,
214 "a newer (larger) bucket must encode to smaller key bytes so floor_scan can take the first entry at-or-after the target"
215 );
216 }
217
218 #[test]
219 fn test_floor_scan_lower_bound_is_target_bucket() {
220 let target = sec(150);
221 let range = VersionEpochKey::floor_scan(target).encode();
222 assert_eq!(range.start, Bound::Included(VersionEpochKey::encoded(target)));
223 assert_eq!(range.end, Bound::Included(VersionEpochKey::encoded(sec(0))));
224 assert!(VersionEpochKey::encoded(target) >= VersionEpochKey::encoded(target));
226 assert!(VersionEpochKey::encoded(sec(151)) < VersionEpochKey::encoded(target));
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
231#[key(tag = Migration)]
232pub struct MigrationKey {
233 pub migration: MigrationId,
234}
235
236impl MigrationKey {
237 pub fn new(migration: MigrationId) -> Self {
238 Self {
239 migration,
240 }
241 }
242
243 pub fn encoded(migration: impl Into<MigrationId>) -> EncodedKey {
244 Self::new(migration.into()).encode()
245 }
246
247 pub fn full_scan() -> TaggedKeyBoundRange {
248 TaggedKeyBoundRange::kind(Self::TAG)
249 }
250}
251
252#[cfg(test)]
253mod migration_key_tests {
254 use super::MigrationKey;
255 use crate::interface::catalog::id::MigrationId;
256
257 #[test]
258 fn test_encode_decode() {
259 let key = MigrationKey {
260 migration: MigrationId(0xABCD),
261 };
262 let encoded = key.encode();
263 let decoded = MigrationKey::decode(&encoded).unwrap();
264 assert_eq!(decoded.migration, MigrationId(0xABCD));
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
269#[key(tag = MigrationEvent)]
270pub struct MigrationEventKey {
271 pub event: MigrationEventId,
272}
273
274impl MigrationEventKey {
275 pub fn new(event: MigrationEventId) -> Self {
276 Self {
277 event,
278 }
279 }
280
281 pub fn encoded(event: impl Into<MigrationEventId>) -> EncodedKey {
282 Self::new(event.into()).encode()
283 }
284
285 pub fn full_scan() -> TaggedKeyBoundRange {
286 TaggedKeyBoundRange::kind(Self::TAG)
287 }
288}
289
290#[cfg(test)]
291mod migration_event_key_tests {
292 use super::MigrationEventKey;
293 use crate::interface::catalog::id::MigrationEventId;
294
295 #[test]
296 fn test_encode_decode() {
297 let key = MigrationEventKey {
298 event: MigrationEventId(0xABCD),
299 };
300 let encoded = key.encode();
301 let decoded = MigrationEventKey::decode(&encoded).unwrap();
302 assert_eq!(decoded.event, MigrationEventId(0xABCD));
303 }
304}