Skip to main content

reifydb_core/encoded/
value.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_value::value::{Value, ordered_f32::OrderedF32, ordered_f64::OrderedF64, value_type::ValueType};
5
6use super::shape::RowShape;
7use crate::encoded::row::EncodedRow;
8
9impl RowShape {
10	pub fn set_values(&self, row: &mut EncodedRow, values: &[Value]) {
11		debug_assert!(values.len() == self.fields().len());
12		for (idx, value) in values.iter().enumerate() {
13			self.set_value(row, idx, value)
14		}
15	}
16
17	pub fn set_value(&self, row: &mut EncodedRow, index: usize, val: &Value) {
18		let field = &self.fields()[index];
19		debug_assert!(row.len() >= self.total_static_size());
20
21		let field_type = match field.constraint.get_type() {
22			ValueType::Option(inner) => *inner,
23			other => other,
24		};
25
26		match (field_type, val) {
27			(ValueType::Boolean, Value::Boolean(v)) => self.set_bool(row, index, *v),
28			(
29				ValueType::Boolean,
30				Value::None {
31					..
32				},
33			) => self.set_none(row, index),
34
35			(ValueType::Float4, Value::Float4(v)) => self.set_f32(row, index, v.value()),
36			(
37				ValueType::Float4,
38				Value::None {
39					..
40				},
41			) => self.set_none(row, index),
42
43			(ValueType::Float8, Value::Float8(v)) => self.set_f64(row, index, v.value()),
44			(
45				ValueType::Float8,
46				Value::None {
47					..
48				},
49			) => self.set_none(row, index),
50
51			(ValueType::Int1, Value::Int1(v)) => self.set_i8(row, index, *v),
52			(
53				ValueType::Int1,
54				Value::None {
55					..
56				},
57			) => self.set_none(row, index),
58
59			(ValueType::Int2, Value::Int2(v)) => self.set_i16(row, index, *v),
60			(
61				ValueType::Int2,
62				Value::None {
63					..
64				},
65			) => self.set_none(row, index),
66
67			(ValueType::Int4, Value::Int4(v)) => self.set_i32(row, index, *v),
68			(
69				ValueType::Int4,
70				Value::None {
71					..
72				},
73			) => self.set_none(row, index),
74
75			(ValueType::Int8, Value::Int8(v)) => self.set_i64(row, index, *v),
76			(
77				ValueType::Int8,
78				Value::None {
79					..
80				},
81			) => self.set_none(row, index),
82
83			(ValueType::Int16, Value::Int16(v)) => self.set_i128(row, index, *v),
84			(
85				ValueType::Int16,
86				Value::None {
87					..
88				},
89			) => self.set_none(row, index),
90
91			(ValueType::Utf8, Value::Utf8(v)) => self.set_utf8(row, index, v),
92			(
93				ValueType::Utf8,
94				Value::None {
95					..
96				},
97			) => self.set_none(row, index),
98
99			(ValueType::Uint1, Value::Uint1(v)) => self.set_u8(row, index, *v),
100			(
101				ValueType::Uint1,
102				Value::None {
103					..
104				},
105			) => self.set_none(row, index),
106
107			(ValueType::Uint2, Value::Uint2(v)) => self.set_u16(row, index, *v),
108			(
109				ValueType::Uint2,
110				Value::None {
111					..
112				},
113			) => self.set_none(row, index),
114
115			(ValueType::Uint4, Value::Uint4(v)) => self.set_u32(row, index, *v),
116			(
117				ValueType::Uint4,
118				Value::None {
119					..
120				},
121			) => self.set_none(row, index),
122
123			(ValueType::Uint8, Value::Uint8(v)) => self.set_u64(row, index, *v),
124			(
125				ValueType::Uint8,
126				Value::None {
127					..
128				},
129			) => self.set_none(row, index),
130
131			(ValueType::Uint16, Value::Uint16(v)) => self.set_u128(row, index, *v),
132			(
133				ValueType::Uint16,
134				Value::None {
135					..
136				},
137			) => self.set_none(row, index),
138
139			(ValueType::Date, Value::Date(v)) => self.set_date(row, index, *v),
140			(
141				ValueType::Date,
142				Value::None {
143					..
144				},
145			) => self.set_none(row, index),
146
147			(ValueType::DateTime, Value::DateTime(v)) => self.set_datetime(row, index, *v),
148			(
149				ValueType::DateTime,
150				Value::None {
151					..
152				},
153			) => self.set_none(row, index),
154
155			(ValueType::Time, Value::Time(v)) => self.set_time(row, index, *v),
156			(
157				ValueType::Time,
158				Value::None {
159					..
160				},
161			) => self.set_none(row, index),
162
163			(ValueType::Duration, Value::Duration(v)) => self.set_duration(row, index, *v),
164			(
165				ValueType::Duration,
166				Value::None {
167					..
168				},
169			) => self.set_none(row, index),
170
171			(ValueType::Uuid4, Value::Uuid4(v)) => self.set_uuid4(row, index, *v),
172			(
173				ValueType::Uuid4,
174				Value::None {
175					..
176				},
177			) => self.set_none(row, index),
178
179			(ValueType::Uuid7, Value::Uuid7(v)) => self.set_uuid7(row, index, *v),
180			(
181				ValueType::Uuid7,
182				Value::None {
183					..
184				},
185			) => self.set_none(row, index),
186
187			(ValueType::Blob, Value::Blob(v)) => self.set_blob(row, index, v),
188			(
189				ValueType::Blob,
190				Value::None {
191					..
192				},
193			) => self.set_none(row, index),
194
195			(ValueType::Int, Value::Int(v)) => self.set_int(row, index, v),
196			(ValueType::Uint, Value::Uint(v)) => self.set_uint(row, index, v),
197			(
198				ValueType::Int,
199				Value::None {
200					..
201				},
202			) => self.set_none(row, index),
203			(
204				ValueType::Uint,
205				Value::None {
206					..
207				},
208			) => self.set_none(row, index),
209
210			(ValueType::Decimal, Value::Decimal(v)) => self.set_decimal(row, index, v),
211			(
212				ValueType::Decimal,
213				Value::None {
214					..
215				},
216			) => self.set_none(row, index),
217			(ValueType::DictionaryId, Value::DictionaryId(id)) => self.set_dictionary_id(row, index, id),
218
219			(
220				ValueType::DictionaryId,
221				Value::None {
222					..
223				},
224			) => self.set_none(row, index),
225
226			(ValueType::IdentityId, Value::IdentityId(id)) => self.set_identity_id(row, index, *id),
227			(
228				ValueType::IdentityId,
229				Value::None {
230					..
231				},
232			) => self.set_none(row, index),
233
234			(
235				ValueType::Any,
236				Value::None {
237					..
238				},
239			) => self.set_none(row, index),
240			(ValueType::Any, Value::Any(inner)) => self.set_any(row, index, inner),
241			(ty, val) => unreachable!(
242				"set_value type mismatch at index {index}: column name={:?} declared_type={ty:?}, value={val:?}",
243				field.name,
244			),
245		}
246	}
247
248	pub fn get_value(&self, row: &EncodedRow, index: usize) -> Value {
249		let field = &self.fields()[index];
250		if !row.is_defined(index) {
251			return Value::none();
252		}
253		let field_type = match field.constraint.get_type() {
254			ValueType::Option(inner) => *inner,
255			other => other,
256		};
257
258		match field_type {
259			ValueType::Boolean => Value::Boolean(self.get_bool(row, index)),
260			ValueType::Float4 => OrderedF32::try_from(self.get_f32(row, index))
261				.map(Value::Float4)
262				.unwrap_or(Value::none()),
263			ValueType::Float8 => OrderedF64::try_from(self.get_f64(row, index))
264				.map(Value::Float8)
265				.unwrap_or(Value::none()),
266			ValueType::Int1 => Value::Int1(self.get_i8(row, index)),
267			ValueType::Int2 => Value::Int2(self.get_i16(row, index)),
268			ValueType::Int4 => Value::Int4(self.get_i32(row, index)),
269			ValueType::Int8 => Value::Int8(self.get_i64(row, index)),
270			ValueType::Int16 => Value::Int16(self.get_i128(row, index)),
271			ValueType::Utf8 => Value::Utf8(self.get_utf8(row, index).to_string()),
272			ValueType::Uint1 => Value::Uint1(self.get_u8(row, index)),
273			ValueType::Uint2 => Value::Uint2(self.get_u16(row, index)),
274			ValueType::Uint4 => Value::Uint4(self.get_u32(row, index)),
275			ValueType::Uint8 => Value::Uint8(self.get_u64(row, index)),
276			ValueType::Uint16 => Value::Uint16(self.get_u128(row, index)),
277			ValueType::Date => Value::Date(self.get_date(row, index)),
278			ValueType::DateTime => Value::DateTime(self.get_datetime(row, index)),
279			ValueType::Time => Value::Time(self.get_time(row, index)),
280			ValueType::Duration => Value::Duration(self.get_duration(row, index)),
281			ValueType::IdentityId => Value::IdentityId(self.get_identity_id(row, index)),
282			ValueType::Uuid4 => Value::Uuid4(self.get_uuid4(row, index)),
283			ValueType::Uuid7 => Value::Uuid7(self.get_uuid7(row, index)),
284			ValueType::Blob => Value::Blob(self.get_blob(row, index)),
285			ValueType::Int => Value::Int(self.get_int(row, index)),
286			ValueType::Uint => Value::Uint(self.get_uint(row, index)),
287			ValueType::Decimal => Value::Decimal(self.get_decimal(row, index)),
288			ValueType::DictionaryId => Value::DictionaryId(self.get_dictionary_id(row, index)),
289			ValueType::Option(_) => unreachable!("Option type already unwrapped"),
290			ValueType::Any => Value::Any(Box::new(self.get_any(row, index))),
291			ValueType::List(_) => unreachable!("List type cannot be stored in database"),
292			ValueType::Record(_) => unreachable!("Record type cannot be stored in database"),
293			ValueType::Tuple(_) => unreachable!("Tuple type cannot be stored in database"),
294		}
295	}
296}
297
298#[cfg(test)]
299#[allow(clippy::approx_constant)]
300pub mod tests {
301	use std::f64::consts::E;
302
303	use reifydb_runtime::context::{
304		clock::{Clock, MockClock},
305		rng::Rng,
306	};
307	use reifydb_value::value::{
308		Value,
309		blob::Blob,
310		constraint::TypeConstraint,
311		date::Date,
312		datetime::DateTime,
313		dictionary::{DictionaryEntryId, DictionaryId},
314		duration::Duration,
315		ordered_f32::OrderedF32,
316		ordered_f64::OrderedF64,
317		time::Time,
318		uuid::{Uuid4, Uuid7},
319		value_type::ValueType,
320	};
321
322	use crate::encoded::shape::{RowShape, RowShapeField};
323
324	fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
325		let mock = MockClock::from_millis(1000);
326		let clock = Clock::Mock(mock.clone());
327		let rng = Rng::seeded(42);
328		(mock, clock, rng)
329	}
330
331	#[test]
332	fn test_set_utf8_with_dynamic_content() {
333		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Int4, ValueType::Utf8]);
334		let mut row = shape.allocate();
335
336		let value1 = Value::Utf8("hello".to_string());
337		let value2 = Value::Int4(42);
338		let value3 = Value::Utf8("world".to_string());
339
340		shape.set_value(&mut row, 0, &value1);
341		shape.set_value(&mut row, 1, &value2);
342		shape.set_value(&mut row, 2, &value3);
343
344		assert_eq!(shape.get_utf8(&row, 0), "hello");
345		assert_eq!(shape.get_i32(&row, 1), 42);
346		assert_eq!(shape.get_utf8(&row, 2), "world");
347	}
348
349	#[test]
350	fn test_set_values_with_mixed_dynamic_content() {
351		let shape = RowShape::testing(&[
352			ValueType::Boolean,
353			ValueType::Utf8,
354			ValueType::Float4,
355			ValueType::Utf8,
356			ValueType::Int2,
357		]);
358		let mut row = shape.allocate();
359
360		let values = vec![
361			Value::Boolean(true),
362			Value::Utf8("first_string".to_string()),
363			Value::Float4(OrderedF32::try_from(3.14f32).unwrap()),
364			Value::Utf8("second_string".to_string()),
365			Value::Int2(-100),
366		];
367
368		shape.set_values(&mut row, &values);
369
370		assert_eq!(shape.get_bool(&row, 0), true);
371		assert_eq!(shape.get_utf8(&row, 1), "first_string");
372		assert_eq!(shape.get_f32(&row, 2), 3.14f32);
373		assert_eq!(shape.get_utf8(&row, 3), "second_string");
374		assert_eq!(shape.get_i16(&row, 4), -100);
375	}
376
377	#[test]
378	fn test_set_with_empty_and_large_utf8() {
379		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Utf8, ValueType::Utf8]);
380		let mut row = shape.allocate();
381
382		let large_string = "X".repeat(2000);
383		let values = vec![
384			Value::Utf8("".to_string()),
385			Value::Utf8(large_string.clone()),
386			Value::Utf8("small".to_string()),
387		];
388
389		shape.set_values(&mut row, &values);
390
391		assert_eq!(shape.get_utf8(&row, 0), "");
392		assert_eq!(shape.get_utf8(&row, 1), large_string);
393		assert_eq!(shape.get_utf8(&row, 2), "small");
394		assert_eq!(shape.dynamic_section_size(&row), 2005); // 0 + 2000 + 5
395	}
396
397	#[test]
398	fn test_get_from_dynamic_content() {
399		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Int8, ValueType::Utf8]);
400		let mut row = shape.allocate();
401
402		shape.set_utf8(&mut row, 0, "test_string");
403		shape.set_i64(&mut row, 1, 9876543210i64);
404		shape.set_utf8(&mut row, 2, "another_string");
405
406		let value0 = shape.get_value(&row, 0);
407		let value1 = shape.get_value(&row, 1);
408		let value2 = shape.get_value(&row, 2);
409
410		match value0 {
411			Value::Utf8(s) => assert_eq!(s, "test_string"),
412			_ => panic!("Expected UTF8 value"),
413		}
414
415		match value1 {
416			Value::Int8(i) => assert_eq!(i, 9876543210),
417			_ => panic!("Expected Int8 value"),
418		}
419
420		match value2 {
421			Value::Utf8(s) => assert_eq!(s, "another_string"),
422			_ => panic!("Expected UTF8 value"),
423		}
424	}
425
426	#[test]
427	fn test_set_none_with_utf8_fields() {
428		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Boolean, ValueType::Utf8]);
429		let mut row = shape.allocate();
430
431		// Set some values
432		shape.set_value(&mut row, 0, &Value::Utf8("hello".to_string()));
433		shape.set_value(&mut row, 1, &Value::Boolean(true));
434		shape.set_value(&mut row, 2, &Value::Utf8("world".to_string()));
435
436		assert!(row.is_defined(0));
437		assert!(row.is_defined(1));
438		assert!(row.is_defined(2));
439
440		// Set some as undefined
441		shape.set_value(&mut row, 0, &Value::none());
442		shape.set_value(&mut row, 2, &Value::none());
443
444		assert!(!row.is_defined(0));
445		assert!(row.is_defined(1));
446		assert!(!row.is_defined(2));
447
448		assert_eq!(shape.get_bool(&row, 1), true);
449	}
450
451	#[test]
452	fn test_get_all_types_including_utf8() {
453		let shape = RowShape::testing(&[
454			ValueType::Boolean,
455			ValueType::Int1,
456			ValueType::Int2,
457			ValueType::Int4,
458			ValueType::Int8,
459			ValueType::Uint1,
460			ValueType::Uint2,
461			ValueType::Uint4,
462			ValueType::Uint8,
463			ValueType::Float4,
464			ValueType::Float8,
465			ValueType::Utf8,
466		]);
467		let mut row = shape.allocate();
468
469		shape.set_bool(&mut row, 0, true);
470		shape.set_i8(&mut row, 1, -42);
471		shape.set_i16(&mut row, 2, -1000i16);
472		shape.set_i32(&mut row, 3, -50000i32);
473		shape.set_i64(&mut row, 4, -3000000000i64);
474		shape.set_u8(&mut row, 5, 200u8);
475		shape.set_u16(&mut row, 6, 50000u16);
476		shape.set_u32(&mut row, 7, 3000000000u32);
477		shape.set_u64(&mut row, 8, 15000000000000000000u64);
478		shape.set_f32(&mut row, 9, 2.5);
479		shape.set_f64(&mut row, 10, 123.456789);
480		shape.set_utf8(&mut row, 11, "dynamic_string");
481
482		let values: Vec<Value> = (0..12).map(|i| shape.get_value(&row, i)).collect();
483
484		assert_eq!(values[0], Value::Boolean(true));
485		assert_eq!(values[1], Value::Int1(-42));
486		assert_eq!(values[2], Value::Int2(-1000));
487		assert_eq!(values[3], Value::Int4(-50000));
488		assert_eq!(values[4], Value::Int8(-3000000000));
489		assert_eq!(values[5], Value::Uint1(200));
490		assert_eq!(values[6], Value::Uint2(50000));
491		assert_eq!(values[7], Value::Uint4(3000000000));
492		assert_eq!(values[8], Value::Uint8(15000000000000000000));
493		assert_eq!(values[9], Value::Float4(OrderedF32::try_from(2.5f32).unwrap()));
494		assert_eq!(values[10], Value::Float8(OrderedF64::try_from(123.456789f64).unwrap()));
495		assert_eq!(values[11], Value::Utf8("dynamic_string".to_string()));
496	}
497
498	#[test]
499	fn test_set_values_sparse_with_utf8() {
500		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Utf8, ValueType::Utf8, ValueType::Utf8]);
501		let mut row = shape.allocate();
502
503		// Only set some values
504		let values = vec![
505			Value::Utf8("first".to_string()),
506			Value::none(),
507			Value::Utf8("third".to_string()),
508			Value::none(),
509		];
510
511		shape.set_values(&mut row, &values);
512
513		assert!(row.is_defined(0));
514		assert!(!row.is_defined(1));
515		assert!(row.is_defined(2));
516		assert!(!row.is_defined(3));
517
518		assert_eq!(shape.get_utf8(&row, 0), "first");
519		assert_eq!(shape.get_utf8(&row, 2), "third");
520	}
521
522	#[test]
523	fn test_set_values_unicode_strings() {
524		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Int4, ValueType::Utf8]);
525		let mut row = shape.allocate();
526
527		let values = vec![
528			Value::Utf8("πŸŽ‰πŸš€βœ¨".to_string()),
529			Value::Int4(123),
530			Value::Utf8("Hello δΈ–η•Œ".to_string()),
531		];
532
533		shape.set_values(&mut row, &values);
534
535		assert_eq!(shape.get_utf8(&row, 0), "πŸŽ‰πŸš€βœ¨");
536		assert_eq!(shape.get_i32(&row, 1), 123);
537		assert_eq!(shape.get_utf8(&row, 2), "Hello δΈ–η•Œ");
538	}
539
540	#[test]
541	fn test_static_fields_only_no_dynamic_with_values() {
542		let shape = RowShape::testing(&[ValueType::Boolean, ValueType::Int4, ValueType::Float8]);
543		let mut row = shape.allocate();
544
545		let values =
546			vec![Value::Boolean(false), Value::Int4(999), Value::Float8(OrderedF64::try_from(E).unwrap())];
547
548		shape.set_values(&mut row, &values);
549
550		// Verify no dynamic section
551		assert_eq!(shape.dynamic_section_size(&row), 0);
552		assert_eq!(row.len(), shape.total_static_size());
553
554		assert_eq!(shape.get_bool(&row, 0), false);
555		assert_eq!(shape.get_i32(&row, 1), 999);
556		assert_eq!(shape.get_f64(&row, 2), E);
557	}
558
559	#[test]
560	fn test_temporal_types_roundtrip() {
561		let shape = RowShape::testing(&[
562			ValueType::Date,
563			ValueType::DateTime,
564			ValueType::Time,
565			ValueType::Duration,
566		]);
567		let mut row = shape.allocate();
568
569		let original_values = vec![
570			Value::Date(Date::new(2025, 7, 15).unwrap()),
571			Value::DateTime(DateTime::from_ymd_hms(2025, 7, 15, 14, 30, 45).unwrap()),
572			Value::Time(Time::new(14, 30, 45, 123456789).unwrap()),
573			Value::Duration(Duration::from_seconds(3600).unwrap()),
574		];
575
576		shape.set_values(&mut row, &original_values);
577
578		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
579
580		assert_eq!(retrieved_values, original_values);
581	}
582
583	#[test]
584	fn test_temporal_types_with_undefined() {
585		let shape = RowShape::testing(&[
586			ValueType::Date,
587			ValueType::DateTime,
588			ValueType::Time,
589			ValueType::Duration,
590		]);
591		let mut row = shape.allocate();
592
593		let values = vec![
594			Value::Date(Date::new(2000, 1, 1).unwrap()),
595			Value::none(),
596			Value::Time(Time::default()),
597			Value::none(),
598		];
599
600		shape.set_values(&mut row, &values);
601
602		assert!(row.is_defined(0));
603		assert!(!row.is_defined(1));
604		assert!(row.is_defined(2));
605		assert!(!row.is_defined(3));
606
607		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
608
609		assert_eq!(retrieved_values[0], values[0]);
610		assert_eq!(retrieved_values[1], Value::none());
611		assert_eq!(retrieved_values[2], values[2]);
612		assert_eq!(retrieved_values[3], Value::none());
613	}
614
615	#[test]
616	fn test_mixed_temporal_and_regular_types() {
617		let shape = RowShape::testing(&[
618			ValueType::Boolean,
619			ValueType::Date,
620			ValueType::Utf8,
621			ValueType::DateTime,
622			ValueType::Int4,
623			ValueType::Time,
624			ValueType::Duration,
625		]);
626		let mut row = shape.allocate();
627
628		let values = vec![
629			Value::Boolean(true),
630			Value::Date(Date::new(1985, 10, 26).unwrap()),
631			Value::Utf8("time travel".to_string()),
632			Value::DateTime(DateTime::new(2015, 10, 21, 16, 29, 0, 0).unwrap()),
633			Value::Int4(88),
634			Value::Time(Time::new(12, 0, 0, 0).unwrap()),
635			Value::Duration(Duration::from_minutes(30).unwrap()),
636		];
637
638		shape.set_values(&mut row, &values);
639
640		let retrieved_values: Vec<Value> = (0..7).map(|i| shape.get_value(&row, i)).collect();
641
642		assert_eq!(retrieved_values, values);
643	}
644
645	#[test]
646	fn test_roundtrip_with_dynamic_content() {
647		let shape = RowShape::testing(&[ValueType::Utf8, ValueType::Int2, ValueType::Utf8, ValueType::Float4]);
648		let mut row = shape.allocate();
649
650		let original_values = vec![
651			Value::Utf8("roundtrip_test".to_string()),
652			Value::Int2(32000),
653			Value::Utf8("".to_string()),
654			Value::Float4(OrderedF32::try_from(1.5f32).unwrap()),
655		];
656
657		// Set values
658		shape.set_values(&mut row, &original_values);
659
660		// Get values back
661		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
662
663		assert_eq!(retrieved_values, original_values);
664	}
665
666	#[test]
667	fn test_blob_roundtrip() {
668		let shape = RowShape::testing(&[ValueType::Blob, ValueType::Int4, ValueType::Blob]);
669		let mut row = shape.allocate();
670
671		let blob1 = Blob::new(vec![0xDE, 0xAD, 0xBE, 0xEF]);
672		let blob2 = Blob::new(vec![]);
673		let values = vec![Value::Blob(blob1.clone()), Value::Int4(42), Value::Blob(blob2.clone())];
674
675		shape.set_values(&mut row, &values);
676
677		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
678
679		assert_eq!(retrieved_values, values);
680
681		// Verify blob content directly
682		match &retrieved_values[0] {
683			Value::Blob(b) => assert_eq!(b.as_bytes(), &[0xDE, 0xAD, 0xBE, 0xEF]),
684			_ => panic!("Expected Blob value"),
685		}
686
687		match &retrieved_values[2] {
688			Value::Blob(b) => assert!(b.is_empty()),
689			_ => panic!("Expected Blob value"),
690		}
691	}
692
693	#[test]
694	fn test_blob_with_undefined() {
695		let shape = RowShape::testing(&[ValueType::Blob, ValueType::Blob, ValueType::Blob]);
696		let mut row = shape.allocate();
697
698		let values = vec![
699			Value::Blob(Blob::new(vec![0x00, 0x01, 0x02])),
700			Value::none(),
701			Value::Blob(Blob::new(vec![0xFF, 0xFE])),
702		];
703
704		shape.set_values(&mut row, &values);
705
706		assert!(row.is_defined(0));
707		assert!(!row.is_defined(1));
708		assert!(row.is_defined(2));
709
710		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
711
712		assert_eq!(retrieved_values[0], values[0]);
713		assert_eq!(retrieved_values[1], Value::none());
714		assert_eq!(retrieved_values[2], values[2]);
715	}
716
717	#[test]
718	fn test_uuid_roundtrip() {
719		let (_, clock, rng) = test_clock_and_rng();
720		let shape = RowShape::testing(&[ValueType::Uuid4, ValueType::Uuid7, ValueType::Int4]);
721		let mut row = shape.allocate();
722
723		let uuid4 = Uuid4::generate();
724		let uuid7 = Uuid7::generate(&clock, &rng);
725		let values = vec![Value::Uuid4(uuid4), Value::Uuid7(uuid7), Value::Int4(123)];
726
727		shape.set_values(&mut row, &values);
728
729		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
730
731		assert_eq!(retrieved_values, values);
732	}
733
734	#[test]
735	fn test_uuid_with_undefined() {
736		let (_, clock, rng) = test_clock_and_rng();
737		let shape = RowShape::testing(&[ValueType::Uuid4, ValueType::Uuid7]);
738		let mut row = shape.allocate();
739
740		let values = vec![Value::none(), Value::Uuid7(Uuid7::generate(&clock, &rng))];
741
742		shape.set_values(&mut row, &values);
743
744		assert!(!row.is_defined(0));
745		assert!(row.is_defined(1));
746
747		let retrieved_values: Vec<Value> = (0..2).map(|i| shape.get_value(&row, i)).collect();
748
749		assert_eq!(retrieved_values[0], Value::none());
750		assert_eq!(retrieved_values[1], values[1]);
751	}
752
753	#[test]
754	fn test_mixed_blob_row_number_uuid_types() {
755		let (_, clock, rng) = test_clock_and_rng();
756		let shape = RowShape::testing(&[
757			ValueType::Blob,
758			ValueType::Int16,
759			ValueType::Uuid4,
760			ValueType::Utf8,
761			ValueType::Uuid7,
762			ValueType::Int4,
763		]);
764		let mut row = shape.allocate();
765
766		let values = vec![
767			Value::Blob(Blob::new(vec![0xCA, 0xFE, 0xBA, 0xBE])),
768			Value::Int16(42424242i128),
769			Value::Uuid4(Uuid4::generate()),
770			Value::Utf8("mixed types test".to_string()),
771			Value::Uuid7(Uuid7::generate(&clock, &rng)),
772			Value::Int4(-999),
773		];
774
775		shape.set_values(&mut row, &values);
776
777		let retrieved_values: Vec<Value> = (0..6).map(|i| shape.get_value(&row, i)).collect();
778
779		assert_eq!(retrieved_values, values);
780
781		// Verify dynamic content exists (for blob and utf8)
782		assert!(shape.dynamic_section_size(&row) > 0);
783	}
784
785	#[test]
786	fn test_all_types_comprehensive() {
787		// except encoded id
788		let (_, clock, rng) = test_clock_and_rng();
789
790		let shape = RowShape::testing(&[
791			ValueType::Boolean,
792			ValueType::Int1,
793			ValueType::Int2,
794			ValueType::Int4,
795			ValueType::Int8,
796			ValueType::Int16,
797			ValueType::Uint1,
798			ValueType::Uint2,
799			ValueType::Uint4,
800			ValueType::Uint8,
801			ValueType::Uint16,
802			ValueType::Float4,
803			ValueType::Float8,
804			ValueType::Utf8,
805			ValueType::Date,
806			ValueType::DateTime,
807			ValueType::Time,
808			ValueType::Duration,
809			ValueType::Uuid4,
810			ValueType::Uuid7,
811			ValueType::Blob,
812		]);
813		let mut row = shape.allocate();
814
815		let values = vec![
816			Value::Boolean(true),
817			Value::Int1(-128),
818			Value::Int2(-32768),
819			Value::Int4(-2147483648),
820			Value::Int8(-9223372036854775808),
821			Value::Int16(-170141183460469231731687303715884105728),
822			Value::Uint1(255),
823			Value::Uint2(65535),
824			Value::Uint4(4294967295),
825			Value::Uint8(18446744073709551615),
826			Value::Uint16(340282366920938463463374607431768211455),
827			Value::Float4(OrderedF32::try_from(3.14159f32).unwrap()),
828			Value::Float8(OrderedF64::try_from(2.718281828459045).unwrap()),
829			Value::Utf8("comprehensive test".to_string()),
830			Value::Date(Date::new(2025, 12, 31).unwrap()),
831			Value::DateTime(DateTime::new(2025, 1, 1, 0, 0, 0, 0).unwrap()),
832			Value::Time(Time::new(23, 59, 59, 999999999).unwrap()),
833			Value::Duration(Duration::from_hours(24).unwrap()),
834			Value::Uuid4(Uuid4::generate()),
835			Value::Uuid7(Uuid7::generate(&clock, &rng)),
836			Value::Blob(Blob::new(vec![
837				0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
838				0xEE, 0xFF,
839			])),
840		];
841
842		shape.set_values(&mut row, &values);
843
844		let retrieved_values: Vec<Value> = (0..21).map(|i| shape.get_value(&row, i)).collect();
845
846		assert_eq!(retrieved_values, values);
847
848		// Verify all fields are defined
849		for i in 0..21 {
850			assert!(row.is_defined(i), "Field {} should be defined", i);
851		}
852	}
853
854	#[test]
855	fn test_dictionary_id_roundtrip_u4() {
856		let constraint = TypeConstraint::dictionary(DictionaryId::from(42u64), ValueType::Uint4);
857		let shape = RowShape::new(vec![RowShapeField::new("status", constraint)]);
858
859		let mut row = shape.allocate();
860		let entry = DictionaryEntryId::U4(7);
861		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
862
863		assert!(row.is_defined(0));
864		let retrieved = shape.get_value(&row, 0);
865		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U4(7)));
866	}
867
868	#[test]
869	fn test_dictionary_id_roundtrip_u2() {
870		let constraint = TypeConstraint::dictionary(DictionaryId::from(10u64), ValueType::Uint2);
871		let shape = RowShape::new(vec![RowShapeField::new("category", constraint)]);
872
873		let mut row = shape.allocate();
874		let entry = DictionaryEntryId::U2(500);
875		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
876
877		assert!(row.is_defined(0));
878		let retrieved = shape.get_value(&row, 0);
879		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U2(500)));
880	}
881
882	#[test]
883	fn test_dictionary_id_roundtrip_u8() {
884		let constraint = TypeConstraint::dictionary(DictionaryId::from(99u64), ValueType::Uint8);
885		let shape = RowShape::new(vec![RowShapeField::new("tag", constraint)]);
886
887		let mut row = shape.allocate();
888		let entry = DictionaryEntryId::U8(123456789);
889		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
890
891		assert!(row.is_defined(0));
892		let retrieved = shape.get_value(&row, 0);
893		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U8(123456789)));
894	}
895
896	#[test]
897	fn test_dictionary_id_with_undefined() {
898		let constraint = TypeConstraint::dictionary(DictionaryId::from(1u64), ValueType::Uint4);
899		let shape = RowShape::new(vec![
900			RowShapeField::new("dict_col", constraint),
901			RowShapeField::unconstrained("int_col", ValueType::Int4),
902		]);
903
904		let mut row = shape.allocate();
905		shape.set_value(&mut row, 0, &Value::none());
906		shape.set_value(&mut row, 1, &Value::Int4(42));
907
908		assert!(!row.is_defined(0));
909		assert!(row.is_defined(1));
910
911		assert_eq!(shape.get_value(&row, 0), Value::none());
912		assert_eq!(shape.get_value(&row, 1), Value::Int4(42));
913	}
914
915	#[test]
916	fn test_dictionary_id_mixed_with_other_types() {
917		let dict_constraint = TypeConstraint::dictionary(DictionaryId::from(5u64), ValueType::Uint4);
918		let shape = RowShape::new(vec![
919			RowShapeField::unconstrained("id", ValueType::Int4),
920			RowShapeField::new("status", dict_constraint),
921			RowShapeField::unconstrained("name", ValueType::Utf8),
922		]);
923
924		let mut row = shape.allocate();
925		let values = vec![
926			Value::Int4(100),
927			Value::DictionaryId(DictionaryEntryId::U4(3)),
928			Value::Utf8("test".to_string()),
929		];
930		shape.set_values(&mut row, &values);
931
932		let retrieved: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
933		assert_eq!(retrieved, values);
934	}
935}