Skip to main content

reifydb_core/key/
catalog.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_codec::key::{
5	ByteSink, decode_u64_varint, deserializer::KeyDeserializer, encode_u64_varint, encoded::EncodedKeyBuilder,
6	serializer::KeySerializer,
7};
8use reifydb_value::{Result, value::dictionary::DictionaryId};
9
10use crate::{
11	interface::catalog::{
12		id::{IndexId, PrimaryKeyId, RingBufferId, SeriesId, TableId, ViewId},
13		shape::ShapeId,
14		vtable::VTableId,
15	},
16	return_internal_error,
17};
18
19pub fn serialize_shape_id<B: ByteSink>(shape: &ShapeId, out: &mut B) {
20	match shape {
21		ShapeId::Table(TableId(id)) => {
22			out.push(0x01);
23			encode_u64_varint(*id, out);
24		}
25		ShapeId::View(ViewId(id)) => {
26			out.push(0x02);
27			encode_u64_varint(*id, out);
28		}
29		ShapeId::TableVirtual(VTableId(id)) => {
30			out.push(0x03);
31			encode_u64_varint(*id, out);
32		}
33		ShapeId::RingBuffer(RingBufferId(id)) => {
34			out.push(0x04);
35			encode_u64_varint(*id, out);
36		}
37		ShapeId::Dictionary(DictionaryId(id)) => {
38			out.push(0x06);
39			encode_u64_varint(*id, out);
40		}
41		ShapeId::Series(SeriesId(id)) => {
42			out.push(0x07);
43			encode_u64_varint(*id, out);
44		}
45	}
46}
47
48pub fn deserialize_shape_id(input: &mut &[u8]) -> Result<ShapeId> {
49	if input.is_empty() {
50		return_internal_error!("Invalid ShapeId encoding: empty input");
51	}
52
53	let type_byte = input[0];
54	*input = &input[1..];
55	let id = decode_u64_varint(input)?;
56
57	match type_byte {
58		0x01 => Ok(ShapeId::Table(TableId(id))),
59		0x02 => Ok(ShapeId::View(ViewId(id))),
60		0x03 => Ok(ShapeId::TableVirtual(VTableId(id))),
61		0x04 => Ok(ShapeId::RingBuffer(RingBufferId(id))),
62		0x06 => Ok(ShapeId::Dictionary(DictionaryId(id))),
63		0x07 => Ok(ShapeId::Series(SeriesId(id))),
64		_ => return_internal_error!("Invalid ShapeId type byte: 0x{:02x}.", type_byte),
65	}
66}
67
68pub fn serialize_index_id<B: ByteSink>(index: &IndexId, out: &mut B) {
69	match index {
70		IndexId::Primary(PrimaryKeyId(id)) => {
71			out.push(0x01);
72			encode_u64_varint(*id, out);
73		}
74	}
75}
76
77pub fn deserialize_index_id(input: &mut &[u8]) -> Result<IndexId> {
78	if input.is_empty() {
79		return_internal_error!("Invalid IndexId encoding: empty input");
80	}
81
82	let type_byte = input[0];
83	*input = &input[1..];
84	let id = decode_u64_varint(input)?;
85
86	match type_byte {
87		0x01 => Ok(IndexId::Primary(PrimaryKeyId(id))),
88
89		_ => return_internal_error!("Invalid IndexId type byte: 0x{:02x}.", type_byte),
90	}
91}
92
93pub trait KeySerializerCatalogExt {
94	fn extend_shape_id(&mut self, shape: impl Into<ShapeId>) -> &mut Self;
95	fn extend_index_id(&mut self, index: impl Into<IndexId>) -> &mut Self;
96}
97
98impl KeySerializerCatalogExt for KeySerializer {
99	fn extend_shape_id(&mut self, shape: impl Into<ShapeId>) -> &mut Self {
100		let mut buf = Vec::new();
101		serialize_shape_id(&shape.into(), &mut buf);
102		self.extend_raw(&buf);
103		self
104	}
105
106	fn extend_index_id(&mut self, index: impl Into<IndexId>) -> &mut Self {
107		let mut buf = Vec::new();
108		serialize_index_id(&index.into(), &mut buf);
109		self.extend_raw(&buf);
110		self
111	}
112}
113
114pub trait KeyDeserializerCatalogExt {
115	fn read_shape_id(&mut self) -> Result<ShapeId>;
116	fn read_index_id(&mut self) -> Result<IndexId>;
117}
118
119impl KeyDeserializerCatalogExt for KeyDeserializer<'_> {
120	fn read_shape_id(&mut self) -> Result<ShapeId> {
121		let mut slice = self.remaining_bytes();
122		let before = slice.len();
123		let shape_id = deserialize_shape_id(&mut slice)?;
124		self.read_raw(before - slice.len())?;
125		Ok(shape_id)
126	}
127
128	fn read_index_id(&mut self) -> Result<IndexId> {
129		let mut slice = self.remaining_bytes();
130		let before = slice.len();
131		let index_id = deserialize_index_id(&mut slice)?;
132		self.read_raw(before - slice.len())?;
133		Ok(index_id)
134	}
135}
136
137pub trait EncodedKeyBuilderCatalogExt {
138	fn shape_id(self, shape: impl Into<ShapeId>) -> Self;
139	fn index_id(self, index: impl Into<IndexId>) -> Self;
140}
141
142impl EncodedKeyBuilderCatalogExt for EncodedKeyBuilder {
143	fn shape_id(self, shape: impl Into<ShapeId>) -> Self {
144		let mut buf = Vec::new();
145		serialize_shape_id(&shape.into(), &mut buf);
146		self.raw(&buf)
147	}
148
149	fn index_id(self, index: impl Into<IndexId>) -> Self {
150		let mut buf = Vec::new();
151		serialize_index_id(&index.into(), &mut buf);
152		self.raw(&buf)
153	}
154}
155
156#[cfg(test)]
157pub mod tests {
158	use reifydb_codec::key::serialize;
159
160	use super::{
161		serialize_index_id as serialize_index_id_inner, serialize_shape_id as serialize_shape_id_inner, *,
162	};
163
164	fn serialize_shape_id(shape: &ShapeId) -> Vec<u8> {
165		let mut out = Vec::new();
166		serialize_shape_id_inner(shape, &mut out);
167		out
168	}
169
170	fn serialize_index_id(index: &IndexId) -> Vec<u8> {
171		let mut out = Vec::new();
172		serialize_index_id_inner(index, &mut out);
173		out
174	}
175
176	#[test]
177	fn test_shape_id_ordering() {
178		let primitive1 = ShapeId::table(1);
179		let primitive2 = ShapeId::table(2);
180		let primitive100 = ShapeId::table(100);
181		let primitive200 = ShapeId::table(200);
182
183		let bytes1 = serialize_shape_id(&primitive1);
184		let bytes2 = serialize_shape_id(&primitive2);
185		let bytes100 = serialize_shape_id(&primitive100);
186		let bytes200 = serialize_shape_id(&primitive200);
187
188		assert!(bytes2 < bytes1, "shape(2) should be < shape(1) in bytes");
189		assert!(bytes200 < bytes100, "shape(200) should be < shape(100) in bytes");
190		assert!(bytes100 < bytes2, "shape(100) should be < shape(2) in bytes");
191	}
192
193	#[test]
194	fn test_range_boundaries() {
195		let primitive10 = ShapeId::table(10);
196		let primitive9 = primitive10.prev();
197
198		let bytes10 = serialize_shape_id(&primitive10);
199		let bytes9 = serialize_shape_id(&primitive9);
200
201		assert!(bytes9 > bytes10, "shape(9) should be > shape(10) in bytes");
202
203		let view10 = ShapeId::view(10);
204		let view9 = view10.prev();
205
206		let vbytes10 = serialize_shape_id(&view10);
207		let vbytes9 = serialize_shape_id(&view9);
208
209		assert!(vbytes9 > vbytes10, "view(9) should be > view(10) in bytes");
210
211		let virtual10 = ShapeId::vtable(10);
212		let virtual9 = virtual10.prev();
213
214		let tvbytes10 = serialize_shape_id(&virtual10);
215		let tvbytes9 = serialize_shape_id(&virtual9);
216
217		assert!(tvbytes9 > tvbytes10, "vtable(9) should be > vtable(10) in bytes");
218
219		assert_ne!(bytes10, vbytes10, "table(10) should != view(10)");
220		assert_ne!(bytes10, tvbytes10, "table(10) should != vtable(10)");
221		assert_ne!(vbytes10, tvbytes10, "view(10) should != vtable(10)");
222		assert_eq!(bytes10[0], 0x01, "table type byte should be 0x01");
223		assert_eq!(vbytes10[0], 0x02, "view type byte should be 0x02");
224		assert_eq!(tvbytes10[0], 0x03, "vtable type byte should be 0x03");
225
226		let row_key_10_100 = vec![0xFC];
227		let mut key1 = row_key_10_100.clone();
228		key1.extend(&bytes10);
229		key1.extend(&serialize(&100u64));
230
231		let mut key2 = row_key_10_100.clone();
232		key2.extend(&bytes10);
233		key2.extend(&serialize(&200u64));
234
235		let mut end_key = vec![0xFC];
236		end_key.extend(&bytes9);
237
238		assert!(key1 >= bytes10, "key1 should be >= start(primitive10)");
239		assert!(key1 < end_key, "key1 should be < end(primitive9)");
240		assert!(key2 >= bytes10, "key2 should be >= start(primitive10)");
241		assert!(key2 < end_key, "key2 should be < end(primitive9)");
242	}
243
244	#[test]
245	fn test_vtable_serialization() {
246		let virtual_primitive = ShapeId::vtable(42);
247		let bytes = serialize_shape_id(&virtual_primitive);
248		let mut slice = &bytes[..];
249		let deserialized = deserialize_shape_id(&mut slice).unwrap();
250		assert_eq!(virtual_primitive, deserialized);
251		assert!(slice.is_empty());
252
253		assert_eq!(bytes[0], 0x03);
254
255		let virtual_id = VTableId(123);
256		let primitive_from_id = ShapeId::from(virtual_id);
257		let bytes_from_id = serialize_shape_id(&primitive_from_id);
258		let mut slice = &bytes_from_id[..];
259		let deserialized_id = deserialize_shape_id(&mut slice).unwrap();
260		assert_eq!(primitive_from_id, deserialized_id);
261		assert!(slice.is_empty());
262
263		let virtual1 = ShapeId::vtable(1);
264		let virtual2 = ShapeId::vtable(2);
265		let bytes1 = serialize_shape_id(&virtual1);
266		let bytes2 = serialize_shape_id(&virtual2);
267
268		assert!(bytes2 < bytes1, "vtable(2) should be < vtable(1) in bytes");
269	}
270
271	#[test]
272	fn test_index_id_serialization() {
273		let index = IndexId::primary(42);
274		let bytes = serialize_index_id(&index);
275		let mut slice = &bytes[..];
276		let deserialized = deserialize_index_id(&mut slice).unwrap();
277		assert_eq!(index.as_u64(), deserialized.as_u64());
278		assert!(slice.is_empty());
279
280		assert_eq!(bytes[0], 0x01);
281
282		let primary_id = PrimaryKeyId(123);
283		let index_from_id = IndexId::Primary(primary_id);
284		let bytes_from_id = serialize_index_id(&index_from_id);
285		let mut slice = &bytes_from_id[..];
286		let deserialized_id = deserialize_index_id(&mut slice).unwrap();
287		assert_eq!(index_from_id.as_u64(), deserialized_id.as_u64());
288		assert!(slice.is_empty());
289	}
290
291	#[test]
292	fn test_index_id_ordering() {
293		let index1 = IndexId::primary(1);
294		let index2 = IndexId::primary(2);
295		let index100 = IndexId::primary(100);
296		let index200 = IndexId::primary(200);
297
298		let bytes1 = serialize_index_id(&index1);
299		let bytes2 = serialize_index_id(&index2);
300		let bytes100 = serialize_index_id(&index100);
301		let bytes200 = serialize_index_id(&index200);
302
303		assert!(bytes2 < bytes1, "index(2) should be < index(1) in bytes");
304		assert!(bytes200 < bytes100, "index(200) should be < index(100) in bytes");
305		assert!(bytes100 < bytes2, "index(100) should be < index(2) in bytes");
306	}
307
308	#[test]
309	fn test_index_id_range_boundaries() {
310		let index10 = IndexId::primary(10);
311		let index11 = IndexId::primary(11);
312
313		let bytes10 = serialize_index_id(&index10);
314		let bytes11 = serialize_index_id(&index11);
315
316		assert!(bytes11 < bytes10, "index(11) should be < index(10) in bytes");
317
318		assert_eq!(bytes10.len(), 2, "IndexId(10) should be 2 bytes");
319		assert_eq!(bytes10[0], 0x01, "Primary variant should have type byte 0x01");
320
321		let next_index = IndexId::primary(11);
322		let next_bytes = serialize_index_id(&next_index);
323
324		assert!(next_bytes < bytes10, "index(11) should be < index(10) for proper range boundaries");
325	}
326
327	#[test]
328	fn test_index_entry_key_encoding_with_discriminator() {
329		let shape = ShapeId::table(42);
330		let index = IndexId::primary(7);
331
332		let primitive_bytes = serialize_shape_id(&shape);
333		let index_bytes = serialize_index_id(&index);
334
335		assert_eq!(primitive_bytes.len(), 2, "ShapeId(42) should be 2 bytes");
336		assert_eq!(index_bytes.len(), 2, "IndexId(7) should be 2 bytes");
337
338		assert_eq!(primitive_bytes[0], 0x01, "Table shape should have type byte 0x01");
339		assert_eq!(index_bytes[0], 0x01, "Primary index should have type byte 0x01");
340
341		let total_prefix_size = 1 + 1 + primitive_bytes.len() + index_bytes.len();
342		assert_eq!(total_prefix_size, 6, "Total IndexEntryKey prefix should be 6 bytes");
343	}
344}
345
346#[cfg(test)]
347mod moved_catalog_key_tests {
348	use reifydb_codec::key::{deserializer::KeyDeserializer, serializer::KeySerializer};
349
350	use super::{KeyDeserializerCatalogExt, KeySerializerCatalogExt};
351	use crate::interface::catalog::{
352		id::{IndexId, PrimaryKeyId, TableId},
353		shape::ShapeId,
354	};
355
356	#[test]
357	fn test_index_id() {
358		let mut serializer = KeySerializer::new();
359		serializer.extend_index_id(IndexId::Primary(PrimaryKeyId(123456789)));
360		let result = serializer.finish();
361
362		// IndexId Primary uses 1 byte prefix + u64 varint
363		assert_eq!(result.len(), 5);
364		assert_eq!(result[0], 0x01); // Primary variant prefix
365
366		// Verify it's using bitwise NOT (smaller values produce larger encoded values)
367		let mut serializer2 = KeySerializer::new();
368		serializer2.extend_index_id(IndexId::Primary(PrimaryKeyId(1)));
369		let result2 = serializer2.finish();
370
371		// result2 (for IndexId(1)) should be > result (for IndexId(123456789))
372		// Compare from byte 1 onwards (after the variant prefix)
373		assert!(result2[1..] > result[1..]);
374	}
375
376	#[test]
377	fn test_object_id() {
378		let mut serializer = KeySerializer::new();
379		serializer.extend_shape_id(ShapeId::Table(TableId(987654321)));
380		let result = serializer.finish();
381
382		// ShapeId Table uses 1 byte prefix + u64 varint
383		assert_eq!(result.len(), 6);
384		assert_eq!(result[0], 0x01); // Table variant prefix
385
386		// Verify ordering
387		let mut serializer2 = KeySerializer::new();
388		serializer2.extend_shape_id(ShapeId::Table(TableId(987654322)));
389		let result2 = serializer2.finish();
390
391		// result2 (for larger ShapeId) should be < result (inverted ordering)
392		// Compare from byte 1 onwards (after the variant prefix)
393		assert!(result2[1..] < result[1..]);
394	}
395
396	#[test]
397	fn test_read_shape_id() {
398		let mut ser = KeySerializer::new();
399		let primitive = ShapeId::table(42);
400		ser.extend_shape_id(primitive);
401		let bytes = ser.finish();
402
403		let mut de = KeyDeserializer::from_bytes(&bytes);
404		assert_eq!(de.read_shape_id().unwrap(), primitive);
405		assert!(de.is_empty());
406	}
407
408	#[test]
409	fn test_read_index_id() {
410		let mut ser = KeySerializer::new();
411		let index = IndexId::primary(999);
412		ser.extend_index_id(index);
413		let bytes = ser.finish();
414
415		let mut de = KeyDeserializer::from_bytes(&bytes);
416		assert_eq!(de.read_index_id().unwrap(), index);
417		assert!(de.is_empty());
418	}
419}