Skip to main content

reifydb_core/encoded/
value.rs

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