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