1use reifydb_codec::key::encoded::EncodedKey;
5use reifydb_macro::KeyCodec;
6use reifydb_value::value::partition::Partition;
7
8use super::KeyTag;
9use crate::{
10 interface::catalog::{
11 id::{ColumnBlockId, ColumnId, SeriesId, TableId},
12 object::ObjectId,
13 },
14 key::{
15 any::{Field, KeyFields, Width},
16 bound::{TaggedKeyBoundRange, object_fields},
17 catalog::{KeyDeserializerCatalogExt, KeySerializerCatalogExt},
18 },
19};
20
21#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
22#[key(tag = Column)]
23pub struct ColumnKey {
24 pub object: ObjectId,
25 pub column: ColumnId,
26}
27
28impl ColumnKey {
29 pub fn new(object: impl Into<ObjectId>, column: impl Into<ColumnId>) -> Self {
30 Self {
31 object: object.into(),
32 column: column.into(),
33 }
34 }
35
36 pub fn encoded(object: impl Into<ObjectId>, column: impl Into<ColumnId>) -> EncodedKey {
37 Self::new(object, column).encode()
38 }
39
40 pub fn full_scan(object: impl Into<ObjectId>) -> TaggedKeyBoundRange {
41 TaggedKeyBoundRange::prefix(Self::TAG, object_fields(object.into()))
42 }
43}
44
45#[cfg(test)]
46pub mod column_key_tests {
47 use crate::{
48 interface::catalog::{id::ColumnId, object::ObjectId},
49 key::column::ColumnKey,
50 };
51
52 #[test]
53 fn test_encode_decode() {
54 let key = ColumnKey {
55 object: ObjectId::table(0xABCD),
56 column: ColumnId(0x123456789ABCDEF0),
57 };
58 let encoded = key.encode();
59
60 let expected: Vec<u8> = vec![
61 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x32, 0xED, 0xCB, 0xA9, 0x87, 0x65, 0x43,
62 0x21, 0x0F,
63 ];
64
65 assert_eq!(encoded.as_slice(), expected);
66
67 let key = ColumnKey::decode(&encoded).unwrap();
68 assert_eq!(key.object, 0xABCD);
69 assert_eq!(key.column, 0x123456789ABCDEF0);
70 }
71
72 #[test]
73 fn test_order_preserving() {
74 let key1 = ColumnKey {
75 object: ObjectId::table(1),
76 column: ColumnId(100),
77 };
78 let key2 = ColumnKey {
79 object: ObjectId::table(1),
80 column: ColumnId(200),
81 };
82 let key3 = ColumnKey {
83 object: ObjectId::table(2),
84 column: ColumnId(0),
85 };
86
87 let encoded1 = key1.encode();
88 let encoded2 = key2.encode();
89 let encoded3 = key3.encode();
90
91 assert!(encoded3 < encoded2, "ordering not preserved");
92 assert!(encoded2 < encoded1, "ordering not preserved");
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, KeyCodec, Hash)]
97#[key(tag = ColumnSequence)]
98pub struct ColumnSequenceKey {
99 pub object: ObjectId,
100 pub column: ColumnId,
101}
102
103impl ColumnSequenceKey {
104 pub fn new(object: impl Into<ObjectId>, column: impl Into<ColumnId>) -> Self {
105 Self {
106 object: object.into(),
107 column: column.into(),
108 }
109 }
110
111 pub fn encoded(object: impl Into<ObjectId>, column: impl Into<ColumnId>) -> EncodedKey {
112 Self::new(object, column).encode()
113 }
114}
115
116#[cfg(test)]
117pub mod column_sequence_key_tests {
118 use reifydb_codec::key::encoded::EncodedKey;
119
120 use super::ColumnSequenceKey;
121 use crate::interface::catalog::{id::ColumnId, object::ObjectId};
122
123 #[test]
124 fn test_encode_decode() {
125 let key = ColumnSequenceKey {
126 object: ObjectId::table(0x1234),
127 column: ColumnId(0x5678),
128 };
129 let encoded = key.encode();
130
131 assert_eq!(encoded[0], 0xF1);
132
133 let decoded = ColumnSequenceKey::decode(&encoded).unwrap();
134 assert_eq!(decoded.object, ObjectId::table(0x1234));
135 assert_eq!(decoded.column, ColumnId(0x5678));
136 }
137
138 #[test]
139 fn test_decode_invalid_version() {
140 let mut encoded = vec![0xFF];
141 encoded.push(0x0E);
142 encoded.extend(&[0; 16]);
143
144 let decoded = ColumnSequenceKey::decode(&EncodedKey::new(encoded));
145 assert!(decoded.is_none());
146 }
147
148 #[test]
149 fn test_decode_invalid_kind() {
150 let mut encoded = vec![0x01];
151 encoded.push(0xFF);
152 encoded.extend(&[0; 16]);
153
154 let decoded = ColumnSequenceKey::decode(&EncodedKey::new(encoded));
155 assert!(decoded.is_none());
156 }
157
158 #[test]
159 fn test_decode_invalid_length() {
160 let encoded = vec![0x01, 0x0E];
161 let decoded = ColumnSequenceKey::decode(&EncodedKey::new(encoded));
162 assert!(decoded.is_none());
163 }
164}
165
166#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
167#[key(tag = ColumnBlock)]
168pub struct ColumnBlockKey {
169 pub block: ColumnBlockId,
170}
171
172impl ColumnBlockKey {
173 pub fn new(block: ColumnBlockId) -> Self {
174 Self {
175 block,
176 }
177 }
178
179 pub fn encoded(block: impl Into<ColumnBlockId>) -> EncodedKey {
180 Self::new(block.into()).encode()
181 }
182
183 pub fn full_scan() -> TaggedKeyBoundRange {
184 TaggedKeyBoundRange::kind(Self::TAG)
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
189#[key(tag = SeriesColumnBlock)]
190pub struct SeriesColumnBlockKey {
191 pub series: SeriesId,
192 pub partition: Partition,
193 pub block: ColumnBlockId,
194}
195
196impl SeriesColumnBlockKey {
197 pub fn new(series: SeriesId, partition: Partition, block: ColumnBlockId) -> Self {
198 Self {
199 series,
200 partition,
201 block,
202 }
203 }
204
205 pub fn encoded(
206 series: impl Into<SeriesId>,
207 partition: Partition,
208 block: impl Into<ColumnBlockId>,
209 ) -> EncodedKey {
210 Self::new(series.into(), partition, block.into()).encode()
211 }
212
213 pub fn full_scan(series: SeriesId) -> TaggedKeyBoundRange {
214 TaggedKeyBoundRange::prefix(Self::TAG, [Field::UDesc(Width::U64, series.0 as u128)])
215 }
216
217 pub fn partition_scan(series: SeriesId, partition: Partition) -> TaggedKeyBoundRange {
218 TaggedKeyBoundRange::prefix(
219 Self::TAG,
220 [Field::UDesc(Width::U64, series.0 as u128), Field::UDesc(Width::U128, partition.0)],
221 )
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
226#[key(tag = TableColumnBlock)]
227pub struct TableColumnBlockKey {
228 pub table: TableId,
229 pub block: ColumnBlockId,
230}
231
232impl TableColumnBlockKey {
233 pub fn new(table: TableId, block: ColumnBlockId) -> Self {
234 Self {
235 table,
236 block,
237 }
238 }
239
240 pub fn encoded(table: impl Into<TableId>, block: impl Into<ColumnBlockId>) -> EncodedKey {
241 Self::new(table.into(), block.into()).encode()
242 }
243
244 pub fn full_scan(table: TableId) -> TaggedKeyBoundRange {
245 TaggedKeyBoundRange::prefix(Self::TAG, [Field::UDesc(Width::U64, table.0 as u128)])
246 }
247}
248
249#[cfg(test)]
250pub mod column_block_key_tests {
251 use std::ops::Bound;
252
253 use reifydb_codec::key::encoded::EncodedKey;
254
255 use super::*;
256
257 fn contains(range: &TaggedKeyBoundRange, key: &EncodedKey) -> bool {
258 let start = match &range.start {
259 Bound::Included(b) => *key >= b.encode(),
260 Bound::Excluded(b) => *key > b.encode(),
261 Bound::Unbounded => true,
262 };
263 let end = match &range.end {
264 Bound::Included(b) => *key <= b.encode(),
265 Bound::Excluded(b) => *key < b.encode(),
266 Bound::Unbounded => true,
267 };
268 start && end
269 }
270
271 #[test]
272 fn a_block_key_reports_its_own_kind_from_its_first_byte() {
273 assert_eq!(KeyTag::of(ColumnBlockKey::encoded(ColumnBlockId(1))), Some(KeyTag::ColumnBlock));
276 assert_eq!(
277 KeyTag::of(SeriesColumnBlockKey::encoded(SeriesId(1), Partition(3), ColumnBlockId(2))),
278 Some(KeyTag::SeriesColumnBlock)
279 );
280 assert_eq!(
281 KeyTag::of(TableColumnBlockKey::encoded(TableId(1), ColumnBlockId(2))),
282 Some(KeyTag::TableColumnBlock)
283 );
284 }
285
286 #[test]
287 fn test_column_block_key_encode_decode() {
288 let key = ColumnBlockKey {
289 block: ColumnBlockId(0x1234),
290 };
291 let encoded = key.encode();
292 let decoded = ColumnBlockKey::decode(&encoded).unwrap();
293 assert_eq!(decoded.block, key.block);
294 }
295
296 #[test]
297 fn test_column_block_key_full_scan() {
298 let range = ColumnBlockKey::full_scan();
299 assert!(matches!(range.start, Bound::Included(_) | Bound::Excluded(_)));
300 assert!(matches!(range.end, Bound::Included(_) | Bound::Excluded(_)));
301 }
302
303 #[test]
304 fn test_series_column_block_key_encode_decode() {
305 let key = SeriesColumnBlockKey {
306 series: SeriesId(42),
307 partition: Partition(0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210),
308 block: ColumnBlockId(99),
309 };
310 let encoded = key.encode();
311 let decoded = SeriesColumnBlockKey::decode(&encoded).unwrap();
312 assert_eq!(decoded.series, key.series);
313 assert_eq!(decoded.partition, key.partition);
314 assert_eq!(decoded.block, key.block);
315 }
316
317 #[test]
318 fn test_series_column_block_partition_scan_excludes_other_partitions() {
319 let range = SeriesColumnBlockKey::partition_scan(SeriesId(42), Partition(7));
322 let inside = SeriesColumnBlockKey::encoded(SeriesId(42), Partition(7), ColumnBlockId(1));
323 let other_partition = SeriesColumnBlockKey::encoded(SeriesId(42), Partition(8), ColumnBlockId(1));
324 let other_series = SeriesColumnBlockKey::encoded(SeriesId(43), Partition(7), ColumnBlockId(1));
325
326 assert!(contains(&range, &inside), "the scanned partition must be inside its own range");
327 assert!(!contains(&range, &other_partition), "a different partition must fall outside");
328 assert!(!contains(&range, &other_series), "a different series must fall outside");
329 }
330
331 #[test]
332 fn test_series_column_block_full_scan_spans_every_partition() {
333 let range = SeriesColumnBlockKey::full_scan(SeriesId(42));
335 for partition in [Partition(0), Partition(7), Partition(u128::MAX)] {
336 let key = SeriesColumnBlockKey::encoded(SeriesId(42), partition, ColumnBlockId(1));
337 assert!(contains(&range, &key), "partition {:?} must be inside the full scan", partition);
338 }
339 let other_series = SeriesColumnBlockKey::encoded(SeriesId(43), Partition(7), ColumnBlockId(1));
340 assert!(!contains(&range, &other_series), "a different series must fall outside");
341 }
342
343 #[test]
344 fn test_table_column_block_key_encode_decode() {
345 let key = TableColumnBlockKey {
346 table: TableId(42),
347 block: ColumnBlockId(99),
348 };
349 let encoded = key.encode();
350 let decoded = TableColumnBlockKey::decode(&encoded).unwrap();
351 assert_eq!(decoded.table, key.table);
352 assert_eq!(decoded.block, key.block);
353 }
354}
355
356#[derive(Debug, Clone, PartialEq, KeyCodec, Hash)]
357#[key(tag = Columns)]
358pub struct ColumnsKey {
359 pub column: ColumnId,
360}
361
362impl ColumnsKey {
363 pub fn new(column: impl Into<ColumnId>) -> Self {
364 Self {
365 column: column.into(),
366 }
367 }
368
369 pub fn encoded(column: impl Into<ColumnId>) -> EncodedKey {
370 Self::new(column).encode()
371 }
372
373 pub fn full_scan() -> TaggedKeyBoundRange {
374 TaggedKeyBoundRange::kind(Self::TAG)
375 }
376}
377
378#[cfg(test)]
379pub mod columns_key_tests {
380 use super::ColumnsKey;
381 use crate::interface::catalog::id::ColumnId;
382
383 #[test]
384 fn test_encode_decode() {
385 let key = ColumnsKey {
386 column: ColumnId(0xABCD),
387 };
388 let encoded = key.encode();
389 let expected = vec![0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x32];
390 assert_eq!(encoded.as_slice(), expected);
391
392 let key = ColumnsKey::decode(&encoded).unwrap();
393 assert_eq!(key.column, 0xABCD);
394 }
395}