reifydb_core/key/
ringbuffer.rs1use std::borrow::Cow;
5
6use reifydb_codec::key::{deserializer::KeyDeserializer, encoded::EncodedKey, serializer::KeySerializer};
7use reifydb_macro::KeyCodec;
8use reifydb_value::value::Value;
9use smallvec::{SmallVec, smallvec};
10
11use super::KeyTag;
12use crate::{
13 interface::catalog::{id::RingBufferId, object::ObjectId, storage::StorageId},
14 key::{
15 any::{Field, KeyFields, RawEncoding, Width, encode_values},
16 bound::{TaggedKeyBoundRange, object_fields},
17 catalog::{KeyDeserializerCatalogExt, KeySerializerCatalogExt},
18 },
19};
20
21#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
22#[key(tag = RingBuffer)]
23pub struct RingBufferKey {
24 pub ringbuffer: RingBufferId,
25}
26
27impl RingBufferKey {
28 pub fn new(ringbuffer: RingBufferId) -> Self {
29 Self {
30 ringbuffer,
31 }
32 }
33
34 pub fn encoded(ringbuffer: impl Into<RingBufferId>) -> EncodedKey {
35 Self::new(ringbuffer.into()).encode()
36 }
37
38 pub fn full_scan() -> TaggedKeyBoundRange {
39 TaggedKeyBoundRange::kind(Self::TAG)
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Hash)]
44pub struct RingBufferMetadataKey {
45 pub storage: StorageId,
46 pub partition_values: Vec<Value>,
47}
48
49impl RingBufferMetadataKey {
50 pub fn new(storage: impl Into<StorageId>) -> Self {
51 Self {
52 storage: storage.into(),
53 partition_values: vec![],
54 }
55 }
56
57 pub fn encoded(storage: impl Into<StorageId>) -> EncodedKey {
58 Self::new(storage).encode()
59 }
60
61 pub fn partition(storage: impl Into<StorageId>, partition_values: Vec<Value>) -> Self {
62 Self {
63 storage: storage.into(),
64 partition_values,
65 }
66 }
67
68 pub fn encoded_partition(storage: impl Into<StorageId>, partition_values: Vec<Value>) -> EncodedKey {
69 Self::partition(storage, partition_values).encode()
70 }
71
72 pub fn full_scan_for_storage(storage: impl Into<StorageId>) -> TaggedKeyBoundRange {
73 TaggedKeyBoundRange::prefix(Self::TAG, object_fields(ObjectId::from(storage.into())))
74 }
75}
76
77impl RingBufferMetadataKey {
78 pub const TAG: KeyTag = KeyTag::RingBufferMetadata;
79
80 pub fn encode(&self) -> EncodedKey {
81 let mut serializer = KeySerializer::with_capacity(32);
82 serializer.extend_u8(Self::TAG as u8).extend_object_id(self.storage);
83 for value in &self.partition_values {
84 serializer.extend_value(value);
85 }
86 serializer.to_encoded_key()
87 }
88
89 pub fn decode(key: &EncodedKey) -> Option<Self> {
90 let mut de = KeyDeserializer::from_bytes(key.as_slice());
91
92 let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
93 if kind != Self::TAG {
94 return None;
95 }
96
97 let storage = StorageId::from_object(de.read_object_id().ok()?)?;
98
99 let mut partition_values = Vec::new();
100 while !de.is_empty() {
101 partition_values.push(de.read_value().ok()?);
102 }
103
104 Some(Self {
105 storage,
106 partition_values,
107 })
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use std::ops::RangeBounds;
114
115 use super::*;
116 use crate::interface::catalog::id::ViewId;
117
118 #[test]
119 fn test_metadata_key_encode_decode_roundtrip() {
120 let key = RingBufferMetadataKey::encoded_partition(
121 RingBufferId(42),
122 vec![Value::Utf8("east".to_string())],
123 );
124 let mut de = KeyDeserializer::from_bytes(key.as_slice());
125 let _ = (de.read_u8(), de.read_object_id());
126 let value = de.read_value().unwrap();
127 assert_eq!(value, Value::Utf8("east".to_string()));
128 }
129
130 #[test]
131 fn test_metadata_key_encode_decode_multiple() {
132 let key = RingBufferMetadataKey::encoded_partition(
133 RingBufferId(7),
134 vec![Value::Utf8("us".to_string()), Value::Uint8(42)],
135 );
136 let mut de = KeyDeserializer::from_bytes(key.as_slice());
137 let _ = (de.read_u8(), de.read_object_id());
138 assert_eq!(de.read_value().unwrap(), Value::Utf8("us".to_string()));
139 assert_eq!(de.read_value().unwrap(), Value::Uint8(42));
140 }
141
142 #[test]
143 fn test_metadata_key_roundtrip_ringbuffer() {
144 let key = RingBufferMetadataKey {
146 storage: StorageId::RingBuffer(RingBufferId(42)),
147 partition_values: vec![Value::Utf8("east".to_string())],
148 };
149 assert_eq!(RingBufferMetadataKey::decode(&key.encode()).unwrap(), key);
150 }
151
152 #[test]
153 fn test_metadata_key_roundtrip_view() {
154 let key = RingBufferMetadataKey {
156 storage: StorageId::View(ViewId(42)),
157 partition_values: vec![Value::Utf8("east".to_string())],
158 };
159 assert_eq!(RingBufferMetadataKey::decode(&key.encode()).unwrap(), key);
160 }
161
162 #[test]
163 fn test_full_scan_for_storage_excludes_a_view_with_the_same_id() {
164 let range = RingBufferMetadataKey::full_scan_for_storage(RingBufferId(42)).encode();
166 let ringbuffer = RingBufferMetadataKey::encoded(RingBufferId(42));
167 let view = RingBufferMetadataKey::encoded(ViewId(42));
168 assert!(range.contains(&ringbuffer));
169 assert!(!range.contains(&view));
170 }
171
172 #[test]
173 fn test_ring_buffer_key_matches_legacy_byte_layout() {
174 for id in [RingBufferId(0), RingBufferId(1), RingBufferId(u64::MAX)] {
175 let mut legacy = KeySerializer::with_capacity(9);
176 legacy.extend_u8(KeyTag::RingBuffer as u8).extend_u64(id);
177 assert_eq!(legacy.to_encoded_key().as_slice(), RingBufferKey::encoded(id).as_slice());
178 }
179 }
180}
181
182impl KeyFields for RingBufferMetadataKey {
183 fn fields(&self) -> SmallVec<[Field<'_>; 6]> {
184 smallvec![
185 Field::UAsc(Width::U8, ObjectId::from(self.storage).type_tag() as u128),
186 Field::UDesc(Width::U64, ObjectId::from(self.storage).as_u64() as u128),
187 Field::RawAsc(
188 RawEncoding::Verbatim,
189 Cow::Owned(encode_values(&self.partition_values).as_slice().to_vec())
190 ),
191 ]
192 }
193}