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!("{ty:?}, {val:?}"),
242		}
243	}
244
245	pub fn get_value(&self, row: &EncodedRow, index: usize) -> Value {
246		let field = &self.fields()[index];
247		if !row.is_defined(index) {
248			return Value::none();
249		}
250		let field_type = match field.constraint.get_type() {
251			Type::Option(inner) => *inner,
252			other => other,
253		};
254
255		match field_type {
256			Type::Boolean => Value::Boolean(self.get_bool(row, index)),
257			Type::Float4 => OrderedF32::try_from(self.get_f32(row, index))
258				.map(Value::Float4)
259				.unwrap_or(Value::none()),
260			Type::Float8 => OrderedF64::try_from(self.get_f64(row, index))
261				.map(Value::Float8)
262				.unwrap_or(Value::none()),
263			Type::Int1 => Value::Int1(self.get_i8(row, index)),
264			Type::Int2 => Value::Int2(self.get_i16(row, index)),
265			Type::Int4 => Value::Int4(self.get_i32(row, index)),
266			Type::Int8 => Value::Int8(self.get_i64(row, index)),
267			Type::Int16 => Value::Int16(self.get_i128(row, index)),
268			Type::Utf8 => Value::Utf8(self.get_utf8(row, index).to_string()),
269			Type::Uint1 => Value::Uint1(self.get_u8(row, index)),
270			Type::Uint2 => Value::Uint2(self.get_u16(row, index)),
271			Type::Uint4 => Value::Uint4(self.get_u32(row, index)),
272			Type::Uint8 => Value::Uint8(self.get_u64(row, index)),
273			Type::Uint16 => Value::Uint16(self.get_u128(row, index)),
274			Type::Date => Value::Date(self.get_date(row, index)),
275			Type::DateTime => Value::DateTime(self.get_datetime(row, index)),
276			Type::Time => Value::Time(self.get_time(row, index)),
277			Type::Duration => Value::Duration(self.get_duration(row, index)),
278			Type::IdentityId => Value::IdentityId(self.get_identity_id(row, index)),
279			Type::Uuid4 => Value::Uuid4(self.get_uuid4(row, index)),
280			Type::Uuid7 => Value::Uuid7(self.get_uuid7(row, index)),
281			Type::Blob => Value::Blob(self.get_blob(row, index)),
282			Type::Int => Value::Int(self.get_int(row, index)),
283			Type::Uint => Value::Uint(self.get_uint(row, index)),
284			Type::Decimal => Value::Decimal(self.get_decimal(row, index)),
285			Type::DictionaryId => Value::DictionaryId(self.get_dictionary_id(row, index)),
286			Type::Option(_) => unreachable!("Option type already unwrapped"),
287			Type::Any => Value::Any(Box::new(self.get_any(row, index))),
288			Type::List(_) => unreachable!("List type cannot be stored in database"),
289			Type::Record(_) => unreachable!("Record type cannot be stored in database"),
290			Type::Tuple(_) => unreachable!("Tuple type cannot be stored in database"),
291		}
292	}
293}
294
295#[cfg(test)]
296#[allow(clippy::approx_constant)]
297pub mod tests {
298	use std::f64::consts::E;
299
300	use reifydb_runtime::context::{
301		clock::{Clock, MockClock},
302		rng::Rng,
303	};
304	use reifydb_type::value::{
305		Value,
306		blob::Blob,
307		constraint::TypeConstraint,
308		date::Date,
309		datetime::DateTime,
310		dictionary::{DictionaryEntryId, DictionaryId},
311		duration::Duration,
312		ordered_f32::OrderedF32,
313		ordered_f64::OrderedF64,
314		time::Time,
315		r#type::Type,
316		uuid::{Uuid4, Uuid7},
317	};
318
319	use crate::encoded::shape::{RowShape, RowShapeField};
320
321	fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
322		let mock = MockClock::from_millis(1000);
323		let clock = Clock::Mock(mock.clone());
324		let rng = Rng::seeded(42);
325		(mock, clock, rng)
326	}
327
328	#[test]
329	fn test_set_utf8_with_dynamic_content() {
330		let shape = RowShape::testing(&[Type::Utf8, Type::Int4, Type::Utf8]);
331		let mut row = shape.allocate();
332
333		let value1 = Value::Utf8("hello".to_string());
334		let value2 = Value::Int4(42);
335		let value3 = Value::Utf8("world".to_string());
336
337		shape.set_value(&mut row, 0, &value1);
338		shape.set_value(&mut row, 1, &value2);
339		shape.set_value(&mut row, 2, &value3);
340
341		assert_eq!(shape.get_utf8(&row, 0), "hello");
342		assert_eq!(shape.get_i32(&row, 1), 42);
343		assert_eq!(shape.get_utf8(&row, 2), "world");
344	}
345
346	#[test]
347	fn test_set_values_with_mixed_dynamic_content() {
348		let shape = RowShape::testing(&[Type::Boolean, Type::Utf8, Type::Float4, Type::Utf8, Type::Int2]);
349		let mut row = shape.allocate();
350
351		let values = vec![
352			Value::Boolean(true),
353			Value::Utf8("first_string".to_string()),
354			Value::Float4(OrderedF32::try_from(3.14f32).unwrap()),
355			Value::Utf8("second_string".to_string()),
356			Value::Int2(-100),
357		];
358
359		shape.set_values(&mut row, &values);
360
361		assert_eq!(shape.get_bool(&row, 0), true);
362		assert_eq!(shape.get_utf8(&row, 1), "first_string");
363		assert_eq!(shape.get_f32(&row, 2), 3.14f32);
364		assert_eq!(shape.get_utf8(&row, 3), "second_string");
365		assert_eq!(shape.get_i16(&row, 4), -100);
366	}
367
368	#[test]
369	fn test_set_with_empty_and_large_utf8() {
370		let shape = RowShape::testing(&[Type::Utf8, Type::Utf8, Type::Utf8]);
371		let mut row = shape.allocate();
372
373		let large_string = "X".repeat(2000);
374		let values = vec![
375			Value::Utf8("".to_string()),
376			Value::Utf8(large_string.clone()),
377			Value::Utf8("small".to_string()),
378		];
379
380		shape.set_values(&mut row, &values);
381
382		assert_eq!(shape.get_utf8(&row, 0), "");
383		assert_eq!(shape.get_utf8(&row, 1), large_string);
384		assert_eq!(shape.get_utf8(&row, 2), "small");
385		assert_eq!(shape.dynamic_section_size(&row), 2005); // 0 + 2000 + 5
386	}
387
388	#[test]
389	fn test_get_from_dynamic_content() {
390		let shape = RowShape::testing(&[Type::Utf8, Type::Int8, Type::Utf8]);
391		let mut row = shape.allocate();
392
393		shape.set_utf8(&mut row, 0, "test_string");
394		shape.set_i64(&mut row, 1, 9876543210i64);
395		shape.set_utf8(&mut row, 2, "another_string");
396
397		let value0 = shape.get_value(&row, 0);
398		let value1 = shape.get_value(&row, 1);
399		let value2 = shape.get_value(&row, 2);
400
401		match value0 {
402			Value::Utf8(s) => assert_eq!(s, "test_string"),
403			_ => panic!("Expected UTF8 value"),
404		}
405
406		match value1 {
407			Value::Int8(i) => assert_eq!(i, 9876543210),
408			_ => panic!("Expected Int8 value"),
409		}
410
411		match value2 {
412			Value::Utf8(s) => assert_eq!(s, "another_string"),
413			_ => panic!("Expected UTF8 value"),
414		}
415	}
416
417	#[test]
418	fn test_set_none_with_utf8_fields() {
419		let shape = RowShape::testing(&[Type::Utf8, Type::Boolean, Type::Utf8]);
420		let mut row = shape.allocate();
421
422		// Set some values
423		shape.set_value(&mut row, 0, &Value::Utf8("hello".to_string()));
424		shape.set_value(&mut row, 1, &Value::Boolean(true));
425		shape.set_value(&mut row, 2, &Value::Utf8("world".to_string()));
426
427		assert!(row.is_defined(0));
428		assert!(row.is_defined(1));
429		assert!(row.is_defined(2));
430
431		// Set some as undefined
432		shape.set_value(&mut row, 0, &Value::none());
433		shape.set_value(&mut row, 2, &Value::none());
434
435		assert!(!row.is_defined(0));
436		assert!(row.is_defined(1));
437		assert!(!row.is_defined(2));
438
439		assert_eq!(shape.get_bool(&row, 1), true);
440	}
441
442	#[test]
443	fn test_get_all_types_including_utf8() {
444		let shape = RowShape::testing(&[
445			Type::Boolean,
446			Type::Int1,
447			Type::Int2,
448			Type::Int4,
449			Type::Int8,
450			Type::Uint1,
451			Type::Uint2,
452			Type::Uint4,
453			Type::Uint8,
454			Type::Float4,
455			Type::Float8,
456			Type::Utf8,
457		]);
458		let mut row = shape.allocate();
459
460		shape.set_bool(&mut row, 0, true);
461		shape.set_i8(&mut row, 1, -42);
462		shape.set_i16(&mut row, 2, -1000i16);
463		shape.set_i32(&mut row, 3, -50000i32);
464		shape.set_i64(&mut row, 4, -3000000000i64);
465		shape.set_u8(&mut row, 5, 200u8);
466		shape.set_u16(&mut row, 6, 50000u16);
467		shape.set_u32(&mut row, 7, 3000000000u32);
468		shape.set_u64(&mut row, 8, 15000000000000000000u64);
469		shape.set_f32(&mut row, 9, 2.5);
470		shape.set_f64(&mut row, 10, 123.456789);
471		shape.set_utf8(&mut row, 11, "dynamic_string");
472
473		let values: Vec<Value> = (0..12).map(|i| shape.get_value(&row, i)).collect();
474
475		assert_eq!(values[0], Value::Boolean(true));
476		assert_eq!(values[1], Value::Int1(-42));
477		assert_eq!(values[2], Value::Int2(-1000));
478		assert_eq!(values[3], Value::Int4(-50000));
479		assert_eq!(values[4], Value::Int8(-3000000000));
480		assert_eq!(values[5], Value::Uint1(200));
481		assert_eq!(values[6], Value::Uint2(50000));
482		assert_eq!(values[7], Value::Uint4(3000000000));
483		assert_eq!(values[8], Value::Uint8(15000000000000000000));
484		assert_eq!(values[9], Value::Float4(OrderedF32::try_from(2.5f32).unwrap()));
485		assert_eq!(values[10], Value::Float8(OrderedF64::try_from(123.456789f64).unwrap()));
486		assert_eq!(values[11], Value::Utf8("dynamic_string".to_string()));
487	}
488
489	#[test]
490	fn test_set_values_sparse_with_utf8() {
491		let shape = RowShape::testing(&[Type::Utf8, Type::Utf8, Type::Utf8, Type::Utf8]);
492		let mut row = shape.allocate();
493
494		// Only set some values
495		let values = vec![
496			Value::Utf8("first".to_string()),
497			Value::none(),
498			Value::Utf8("third".to_string()),
499			Value::none(),
500		];
501
502		shape.set_values(&mut row, &values);
503
504		assert!(row.is_defined(0));
505		assert!(!row.is_defined(1));
506		assert!(row.is_defined(2));
507		assert!(!row.is_defined(3));
508
509		assert_eq!(shape.get_utf8(&row, 0), "first");
510		assert_eq!(shape.get_utf8(&row, 2), "third");
511	}
512
513	#[test]
514	fn test_set_values_unicode_strings() {
515		let shape = RowShape::testing(&[Type::Utf8, Type::Int4, Type::Utf8]);
516		let mut row = shape.allocate();
517
518		let values = vec![
519			Value::Utf8("πŸŽ‰πŸš€βœ¨".to_string()),
520			Value::Int4(123),
521			Value::Utf8("Hello δΈ–η•Œ".to_string()),
522		];
523
524		shape.set_values(&mut row, &values);
525
526		assert_eq!(shape.get_utf8(&row, 0), "πŸŽ‰πŸš€βœ¨");
527		assert_eq!(shape.get_i32(&row, 1), 123);
528		assert_eq!(shape.get_utf8(&row, 2), "Hello δΈ–η•Œ");
529	}
530
531	#[test]
532	fn test_static_fields_only_no_dynamic_with_values() {
533		let shape = RowShape::testing(&[Type::Boolean, Type::Int4, Type::Float8]);
534		let mut row = shape.allocate();
535
536		let values =
537			vec![Value::Boolean(false), Value::Int4(999), Value::Float8(OrderedF64::try_from(E).unwrap())];
538
539		shape.set_values(&mut row, &values);
540
541		// Verify no dynamic section
542		assert_eq!(shape.dynamic_section_size(&row), 0);
543		assert_eq!(row.len(), shape.total_static_size());
544
545		assert_eq!(shape.get_bool(&row, 0), false);
546		assert_eq!(shape.get_i32(&row, 1), 999);
547		assert_eq!(shape.get_f64(&row, 2), E);
548	}
549
550	#[test]
551	fn test_temporal_types_roundtrip() {
552		let shape = RowShape::testing(&[Type::Date, Type::DateTime, Type::Time, Type::Duration]);
553		let mut row = shape.allocate();
554
555		let original_values = vec![
556			Value::Date(Date::new(2025, 7, 15).unwrap()),
557			Value::DateTime(DateTime::from_ymd_hms(2025, 7, 15, 14, 30, 45).unwrap()),
558			Value::Time(Time::new(14, 30, 45, 123456789).unwrap()),
559			Value::Duration(Duration::from_seconds(3600).unwrap()),
560		];
561
562		shape.set_values(&mut row, &original_values);
563
564		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
565
566		assert_eq!(retrieved_values, original_values);
567	}
568
569	#[test]
570	fn test_temporal_types_with_undefined() {
571		let shape = RowShape::testing(&[Type::Date, Type::DateTime, Type::Time, Type::Duration]);
572		let mut row = shape.allocate();
573
574		let values = vec![
575			Value::Date(Date::new(2000, 1, 1).unwrap()),
576			Value::none(),
577			Value::Time(Time::default()),
578			Value::none(),
579		];
580
581		shape.set_values(&mut row, &values);
582
583		assert!(row.is_defined(0));
584		assert!(!row.is_defined(1));
585		assert!(row.is_defined(2));
586		assert!(!row.is_defined(3));
587
588		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
589
590		assert_eq!(retrieved_values[0], values[0]);
591		assert_eq!(retrieved_values[1], Value::none());
592		assert_eq!(retrieved_values[2], values[2]);
593		assert_eq!(retrieved_values[3], Value::none());
594	}
595
596	#[test]
597	fn test_mixed_temporal_and_regular_types() {
598		let shape = RowShape::testing(&[
599			Type::Boolean,
600			Type::Date,
601			Type::Utf8,
602			Type::DateTime,
603			Type::Int4,
604			Type::Time,
605			Type::Duration,
606		]);
607		let mut row = shape.allocate();
608
609		let values = vec![
610			Value::Boolean(true),
611			Value::Date(Date::new(1985, 10, 26).unwrap()),
612			Value::Utf8("time travel".to_string()),
613			Value::DateTime(DateTime::new(2015, 10, 21, 16, 29, 0, 0).unwrap()),
614			Value::Int4(88),
615			Value::Time(Time::new(12, 0, 0, 0).unwrap()),
616			Value::Duration(Duration::from_minutes(30).unwrap()),
617		];
618
619		shape.set_values(&mut row, &values);
620
621		let retrieved_values: Vec<Value> = (0..7).map(|i| shape.get_value(&row, i)).collect();
622
623		assert_eq!(retrieved_values, values);
624	}
625
626	#[test]
627	fn test_roundtrip_with_dynamic_content() {
628		let shape = RowShape::testing(&[Type::Utf8, Type::Int2, Type::Utf8, Type::Float4]);
629		let mut row = shape.allocate();
630
631		let original_values = vec![
632			Value::Utf8("roundtrip_test".to_string()),
633			Value::Int2(32000),
634			Value::Utf8("".to_string()),
635			Value::Float4(OrderedF32::try_from(1.5f32).unwrap()),
636		];
637
638		// Set values
639		shape.set_values(&mut row, &original_values);
640
641		// Get values back
642		let retrieved_values: Vec<Value> = (0..4).map(|i| shape.get_value(&row, i)).collect();
643
644		assert_eq!(retrieved_values, original_values);
645	}
646
647	#[test]
648	fn test_blob_roundtrip() {
649		let shape = RowShape::testing(&[Type::Blob, Type::Int4, Type::Blob]);
650		let mut row = shape.allocate();
651
652		let blob1 = Blob::new(vec![0xDE, 0xAD, 0xBE, 0xEF]);
653		let blob2 = Blob::new(vec![]);
654		let values = vec![Value::Blob(blob1.clone()), Value::Int4(42), Value::Blob(blob2.clone())];
655
656		shape.set_values(&mut row, &values);
657
658		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
659
660		assert_eq!(retrieved_values, values);
661
662		// Verify blob content directly
663		match &retrieved_values[0] {
664			Value::Blob(b) => assert_eq!(b.as_bytes(), &[0xDE, 0xAD, 0xBE, 0xEF]),
665			_ => panic!("Expected Blob value"),
666		}
667
668		match &retrieved_values[2] {
669			Value::Blob(b) => assert!(b.is_empty()),
670			_ => panic!("Expected Blob value"),
671		}
672	}
673
674	#[test]
675	fn test_blob_with_undefined() {
676		let shape = RowShape::testing(&[Type::Blob, Type::Blob, Type::Blob]);
677		let mut row = shape.allocate();
678
679		let values = vec![
680			Value::Blob(Blob::new(vec![0x00, 0x01, 0x02])),
681			Value::none(),
682			Value::Blob(Blob::new(vec![0xFF, 0xFE])),
683		];
684
685		shape.set_values(&mut row, &values);
686
687		assert!(row.is_defined(0));
688		assert!(!row.is_defined(1));
689		assert!(row.is_defined(2));
690
691		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
692
693		assert_eq!(retrieved_values[0], values[0]);
694		assert_eq!(retrieved_values[1], Value::none());
695		assert_eq!(retrieved_values[2], values[2]);
696	}
697
698	#[test]
699	fn test_uuid_roundtrip() {
700		let (_, clock, rng) = test_clock_and_rng();
701		let shape = RowShape::testing(&[Type::Uuid4, Type::Uuid7, Type::Int4]);
702		let mut row = shape.allocate();
703
704		let uuid4 = Uuid4::generate();
705		let uuid7 = Uuid7::generate(&clock, &rng);
706		let values = vec![Value::Uuid4(uuid4), Value::Uuid7(uuid7), Value::Int4(123)];
707
708		shape.set_values(&mut row, &values);
709
710		let retrieved_values: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
711
712		assert_eq!(retrieved_values, values);
713	}
714
715	#[test]
716	fn test_uuid_with_undefined() {
717		let (_, clock, rng) = test_clock_and_rng();
718		let shape = RowShape::testing(&[Type::Uuid4, Type::Uuid7]);
719		let mut row = shape.allocate();
720
721		let values = vec![Value::none(), Value::Uuid7(Uuid7::generate(&clock, &rng))];
722
723		shape.set_values(&mut row, &values);
724
725		assert!(!row.is_defined(0));
726		assert!(row.is_defined(1));
727
728		let retrieved_values: Vec<Value> = (0..2).map(|i| shape.get_value(&row, i)).collect();
729
730		assert_eq!(retrieved_values[0], Value::none());
731		assert_eq!(retrieved_values[1], values[1]);
732	}
733
734	#[test]
735	fn test_mixed_blob_row_number_uuid_types() {
736		let (_, clock, rng) = test_clock_and_rng();
737		let shape =
738			RowShape::testing(&[Type::Blob, Type::Int16, Type::Uuid4, Type::Utf8, Type::Uuid7, Type::Int4]);
739		let mut row = shape.allocate();
740
741		let values = vec![
742			Value::Blob(Blob::new(vec![0xCA, 0xFE, 0xBA, 0xBE])),
743			Value::Int16(42424242i128),
744			Value::Uuid4(Uuid4::generate()),
745			Value::Utf8("mixed types test".to_string()),
746			Value::Uuid7(Uuid7::generate(&clock, &rng)),
747			Value::Int4(-999),
748		];
749
750		shape.set_values(&mut row, &values);
751
752		let retrieved_values: Vec<Value> = (0..6).map(|i| shape.get_value(&row, i)).collect();
753
754		assert_eq!(retrieved_values, values);
755
756		// Verify dynamic content exists (for blob and utf8)
757		assert!(shape.dynamic_section_size(&row) > 0);
758	}
759
760	#[test]
761	fn test_all_types_comprehensive() {
762		// except encoded id
763		let (_, clock, rng) = test_clock_and_rng();
764
765		let shape = RowShape::testing(&[
766			Type::Boolean,
767			Type::Int1,
768			Type::Int2,
769			Type::Int4,
770			Type::Int8,
771			Type::Int16,
772			Type::Uint1,
773			Type::Uint2,
774			Type::Uint4,
775			Type::Uint8,
776			Type::Uint16,
777			Type::Float4,
778			Type::Float8,
779			Type::Utf8,
780			Type::Date,
781			Type::DateTime,
782			Type::Time,
783			Type::Duration,
784			Type::Uuid4,
785			Type::Uuid7,
786			Type::Blob,
787		]);
788		let mut row = shape.allocate();
789
790		let values = vec![
791			Value::Boolean(true),
792			Value::Int1(-128),
793			Value::Int2(-32768),
794			Value::Int4(-2147483648),
795			Value::Int8(-9223372036854775808),
796			Value::Int16(-170141183460469231731687303715884105728),
797			Value::Uint1(255),
798			Value::Uint2(65535),
799			Value::Uint4(4294967295),
800			Value::Uint8(18446744073709551615),
801			Value::Uint16(340282366920938463463374607431768211455),
802			Value::Float4(OrderedF32::try_from(3.14159f32).unwrap()),
803			Value::Float8(OrderedF64::try_from(2.718281828459045).unwrap()),
804			Value::Utf8("comprehensive test".to_string()),
805			Value::Date(Date::new(2025, 12, 31).unwrap()),
806			Value::DateTime(DateTime::new(2025, 1, 1, 0, 0, 0, 0).unwrap()),
807			Value::Time(Time::new(23, 59, 59, 999999999).unwrap()),
808			Value::Duration(Duration::from_hours(24).unwrap()),
809			Value::Uuid4(Uuid4::generate()),
810			Value::Uuid7(Uuid7::generate(&clock, &rng)),
811			Value::Blob(Blob::new(vec![
812				0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
813				0xEE, 0xFF,
814			])),
815		];
816
817		shape.set_values(&mut row, &values);
818
819		let retrieved_values: Vec<Value> = (0..21).map(|i| shape.get_value(&row, i)).collect();
820
821		assert_eq!(retrieved_values, values);
822
823		// Verify all fields are defined
824		for i in 0..21 {
825			assert!(row.is_defined(i), "Field {} should be defined", i);
826		}
827	}
828
829	#[test]
830	fn test_dictionary_id_roundtrip_u4() {
831		let constraint = TypeConstraint::dictionary(DictionaryId::from(42u64), Type::Uint4);
832		let shape = RowShape::new(vec![RowShapeField::new("status", constraint)]);
833
834		let mut row = shape.allocate();
835		let entry = DictionaryEntryId::U4(7);
836		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
837
838		assert!(row.is_defined(0));
839		let retrieved = shape.get_value(&row, 0);
840		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U4(7)));
841	}
842
843	#[test]
844	fn test_dictionary_id_roundtrip_u2() {
845		let constraint = TypeConstraint::dictionary(DictionaryId::from(10u64), Type::Uint2);
846		let shape = RowShape::new(vec![RowShapeField::new("category", constraint)]);
847
848		let mut row = shape.allocate();
849		let entry = DictionaryEntryId::U2(500);
850		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
851
852		assert!(row.is_defined(0));
853		let retrieved = shape.get_value(&row, 0);
854		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U2(500)));
855	}
856
857	#[test]
858	fn test_dictionary_id_roundtrip_u8() {
859		let constraint = TypeConstraint::dictionary(DictionaryId::from(99u64), Type::Uint8);
860		let shape = RowShape::new(vec![RowShapeField::new("tag", constraint)]);
861
862		let mut row = shape.allocate();
863		let entry = DictionaryEntryId::U8(123456789);
864		shape.set_value(&mut row, 0, &Value::DictionaryId(entry));
865
866		assert!(row.is_defined(0));
867		let retrieved = shape.get_value(&row, 0);
868		assert_eq!(retrieved, Value::DictionaryId(DictionaryEntryId::U8(123456789)));
869	}
870
871	#[test]
872	fn test_dictionary_id_with_undefined() {
873		let constraint = TypeConstraint::dictionary(DictionaryId::from(1u64), Type::Uint4);
874		let shape = RowShape::new(vec![
875			RowShapeField::new("dict_col", constraint),
876			RowShapeField::unconstrained("int_col", Type::Int4),
877		]);
878
879		let mut row = shape.allocate();
880		shape.set_value(&mut row, 0, &Value::none());
881		shape.set_value(&mut row, 1, &Value::Int4(42));
882
883		assert!(!row.is_defined(0));
884		assert!(row.is_defined(1));
885
886		assert_eq!(shape.get_value(&row, 0), Value::none());
887		assert_eq!(shape.get_value(&row, 1), Value::Int4(42));
888	}
889
890	#[test]
891	fn test_dictionary_id_mixed_with_other_types() {
892		let dict_constraint = TypeConstraint::dictionary(DictionaryId::from(5u64), Type::Uint4);
893		let shape = RowShape::new(vec![
894			RowShapeField::unconstrained("id", Type::Int4),
895			RowShapeField::new("status", dict_constraint),
896			RowShapeField::unconstrained("name", Type::Utf8),
897		]);
898
899		let mut row = shape.allocate();
900		let values = vec![
901			Value::Int4(100),
902			Value::DictionaryId(DictionaryEntryId::U4(3)),
903			Value::Utf8("test".to_string()),
904		];
905		shape.set_values(&mut row, &values);
906
907		let retrieved: Vec<Value> = (0..3).map(|i| shape.get_value(&row, i)).collect();
908		assert_eq!(retrieved, values);
909	}
910}