Skip to main content

reifydb_core/encoded/
value.rs

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