reifydb_core/value/frame/
display.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use std::fmt::{self, Display, Formatter};
5
6use crate::value::frame::{Frame, FrameRenderer};
7
8impl Display for Frame {
9	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
10		FrameRenderer::render_full_to(self, f)
11	}
12}
13
14#[cfg(test)]
15mod tests {
16	use reifydb_type::{Blob, Date, DateTime, Duration, RowNumber, Time, Uuid4, Uuid7, parse_uuid4, parse_uuid7};
17
18	use super::*;
19	use crate::{
20		BitVec, FrameColumn, FrameColumnData,
21		value::container::{
22			BlobContainer, BoolContainer, NumberContainer, RowNumberContainer, TemporalContainer,
23			UndefinedContainer, Utf8Container, UuidContainer,
24		},
25	};
26
27	// Macro to create test columns with optional values (None = undefined)
28	macro_rules! column_with_undefineds {
29		($name:expr, Bool, $data:expr) => {{
30			let (values, bitvec): (Vec<_>, Vec<_>) = $data
31				.into_iter()
32				.map(|opt| match opt {
33					Some(v) => (v, true),
34					None => (false, false), // dummy value, will be marked as undefined
35				})
36				.unzip();
37
38			FrameColumn {
39				namespace: None,
40				source: None,
41				name: $name.to_string(),
42				data: FrameColumnData::Bool(BoolContainer::new(values, BitVec::from_slice(&bitvec))),
43			}
44		}};
45		($name:expr, Float4, $data:expr) => {{
46			let (values, bitvec): (Vec<_>, Vec<_>) = $data
47				.into_iter()
48				.map(|opt| match opt {
49					Some(v) => (v, true),
50					None => (0.0_f32, false), // dummy value, will be marked as undefined
51				})
52				.unzip();
53
54			FrameColumn {
55				namespace: None,
56				source: None,
57				name: $name.to_string(),
58				data: FrameColumnData::Float4(NumberContainer::new(
59					values,
60					BitVec::from_slice(&bitvec),
61				)),
62			}
63		}};
64		($name:expr, Float8, $data:expr) => {{
65			let (values, bitvec): (Vec<_>, Vec<_>) = $data
66				.into_iter()
67				.map(|opt| match opt {
68					Some(v) => (v, true),
69					None => (0.0_f64, false), // dummy value, will be marked as undefined
70				})
71				.unzip();
72
73			FrameColumn {
74				namespace: None,
75				source: None,
76				name: $name.to_string(),
77				data: FrameColumnData::Float8(NumberContainer::new(
78					values,
79					BitVec::from_slice(&bitvec),
80				)),
81			}
82		}};
83		($name:expr, Int1, $data:expr) => {{
84			let (values, bitvec): (Vec<_>, Vec<_>) = $data
85				.into_iter()
86				.map(|opt| match opt {
87					Some(v) => (v, true),
88					None => (0_i8, false), // dummy value, will be marked as undefined
89				})
90				.unzip();
91
92			FrameColumn {
93				namespace: None,
94				source: None,
95				name: $name.to_string(),
96				data: FrameColumnData::Int1(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
97			}
98		}};
99		($name:expr, Int2, $data:expr) => {{
100			let (values, bitvec): (Vec<_>, Vec<_>) = $data
101				.into_iter()
102				.map(|opt| match opt {
103					Some(v) => (v, true),
104					None => (0_i16, false), // dummy value, will be marked as undefined
105				})
106				.unzip();
107
108			FrameColumn {
109				namespace: None,
110				source: None,
111				name: $name.to_string(),
112				data: FrameColumnData::Int2(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
113			}
114		}};
115		($name:expr, Int4, $data:expr) => {{
116			let (values, bitvec): (Vec<_>, Vec<_>) = $data
117				.into_iter()
118				.map(|opt| match opt {
119					Some(v) => (v, true),
120					None => (0_i32, false), // dummy value, will be marked as undefined
121				})
122				.unzip();
123
124			FrameColumn {
125				namespace: None,
126				source: None,
127				name: $name.to_string(),
128				data: FrameColumnData::Int4(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
129			}
130		}};
131		($name:expr, Int8, $data:expr) => {{
132			let (values, bitvec): (Vec<_>, Vec<_>) = $data
133				.into_iter()
134				.map(|opt| match opt {
135					Some(v) => (v, true),
136					None => (0_i64, false), // dummy value, will be marked as undefined
137				})
138				.unzip();
139
140			FrameColumn {
141				namespace: None,
142				source: None,
143				name: $name.to_string(),
144				data: FrameColumnData::Int8(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
145			}
146		}};
147		($name:expr, Int16, $data:expr) => {{
148			let (values, bitvec): (Vec<_>, Vec<_>) = $data
149				.into_iter()
150				.map(|opt| match opt {
151					Some(v) => (v, true),
152					None => (0_i128, false), // dummy value, will be marked as undefined
153				})
154				.unzip();
155
156			FrameColumn {
157				namespace: None,
158				source: None,
159				name: $name.to_string(),
160				data: FrameColumnData::Int16(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
161			}
162		}};
163		($name:expr, Uint1, $data:expr) => {{
164			let (values, bitvec): (Vec<_>, Vec<_>) = $data
165				.into_iter()
166				.map(|opt| match opt {
167					Some(v) => (v, true),
168					None => (0_u8, false), // dummy value, will be marked as undefined
169				})
170				.unzip();
171
172			FrameColumn {
173				namespace: None,
174				source: None,
175				name: $name.to_string(),
176				data: FrameColumnData::Uint1(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
177			}
178		}};
179		($name:expr, Uint2, $data:expr) => {{
180			let (values, bitvec): (Vec<_>, Vec<_>) = $data
181				.into_iter()
182				.map(|opt| match opt {
183					Some(v) => (v, true),
184					None => (0_u16, false), // dummy value, will be marked as undefined
185				})
186				.unzip();
187
188			FrameColumn {
189				namespace: None,
190				source: None,
191				name: $name.to_string(),
192				data: FrameColumnData::Uint2(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
193			}
194		}};
195		($name:expr, Uint4, $data:expr) => {{
196			let (values, bitvec): (Vec<_>, Vec<_>) = $data
197				.into_iter()
198				.map(|opt| match opt {
199					Some(v) => (v, true),
200					None => (0_u32, false), // dummy value, will be marked as undefined
201				})
202				.unzip();
203
204			FrameColumn {
205				namespace: None,
206				source: None,
207				name: $name.to_string(),
208				data: FrameColumnData::Uint4(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
209			}
210		}};
211		($name:expr, Uint8, $data:expr) => {{
212			let (values, bitvec): (Vec<_>, Vec<_>) = $data
213				.into_iter()
214				.map(|opt| match opt {
215					Some(v) => (v, true),
216					None => (0_u64, false), // dummy value, will be marked as undefined
217				})
218				.unzip();
219
220			FrameColumn {
221				namespace: None,
222				source: None,
223				name: $name.to_string(),
224				data: FrameColumnData::Uint8(NumberContainer::new(values, BitVec::from_slice(&bitvec))),
225			}
226		}};
227		($name:expr, Uint16, $data:expr) => {{
228			let (values, bitvec): (Vec<_>, Vec<_>) = $data
229				.into_iter()
230				.map(|opt| match opt {
231					Some(v) => (v, true),
232					None => (0_u128, false), // dummy value, will be marked as undefined
233				})
234				.unzip();
235
236			FrameColumn {
237				namespace: None,
238				source: None,
239				name: $name.to_string(),
240				data: FrameColumnData::Uint16(NumberContainer::new(
241					values,
242					BitVec::from_slice(&bitvec),
243				)),
244			}
245		}};
246		($name:expr, Utf8, $data:expr) => {{
247			let (values, bitvec): (Vec<_>, Vec<_>) = $data
248				.into_iter()
249				.map(|opt| match opt {
250					Some(v) => (v.to_string(), true),
251					None => (String::new(), false), // dummy value, will be marked as undefined
252				})
253				.unzip();
254
255			FrameColumn {
256				namespace: None,
257				source: None,
258				name: $name.to_string(),
259				data: FrameColumnData::Utf8(Utf8Container::new(values, BitVec::from_slice(&bitvec))),
260			}
261		}};
262		($name:expr, Date, $data:expr) => {{
263			let (values, bitvec): (Vec<_>, Vec<_>) = $data
264				.into_iter()
265				.map(|opt| match opt {
266					Some(v) => (v, true),
267					None => (Date::from_ymd(1970, 1, 1).unwrap(), false), // dummy value
268				})
269				.unzip();
270
271			FrameColumn {
272				namespace: None,
273				source: None,
274				name: $name.to_string(),
275				data: FrameColumnData::Date(TemporalContainer::new(
276					values,
277					BitVec::from_slice(&bitvec),
278				)),
279			}
280		}};
281		($name:expr, DateTime, $data:expr) => {{
282			let (values, bitvec): (Vec<_>, Vec<_>) = $data
283				.into_iter()
284				.map(|opt| match opt {
285					Some(v) => (v, true),
286					None => (DateTime::from_timestamp(0).unwrap(), false), // dummy value
287				})
288				.unzip();
289
290			FrameColumn {
291				namespace: None,
292				source: None,
293				name: $name.to_string(),
294				data: FrameColumnData::DateTime(TemporalContainer::new(
295					values,
296					BitVec::from_slice(&bitvec),
297				)),
298			}
299		}};
300		($name:expr, Time, $data:expr) => {{
301			let (values, bitvec): (Vec<_>, Vec<_>) = $data
302				.into_iter()
303				.map(|opt| match opt {
304					Some(v) => (v, true),
305					None => (Time::from_hms(0, 0, 0).unwrap(), false), // dummy value
306				})
307				.unzip();
308
309			FrameColumn {
310				namespace: None,
311				source: None,
312				name: $name.to_string(),
313				data: FrameColumnData::Time(TemporalContainer::new(
314					values,
315					BitVec::from_slice(&bitvec),
316				)),
317			}
318		}};
319		($name:expr, Duration, $data:expr) => {{
320			let (values, bitvec): (Vec<_>, Vec<_>) = $data
321				.into_iter()
322				.map(|opt| match opt {
323					Some(v) => (v, true),
324					None => (Duration::from_days(0), false), // dummy value
325				})
326				.unzip();
327
328			FrameColumn {
329				namespace: None,
330				source: None,
331				name: $name.to_string(),
332				data: FrameColumnData::Duration(TemporalContainer::new(
333					values,
334					BitVec::from_slice(&bitvec),
335				)),
336			}
337		}};
338		($name:expr, Blob, $data:expr) => {{
339			let (values, bitvec): (Vec<_>, Vec<_>) = $data
340				.into_iter()
341				.map(|opt| match opt {
342					Some(v) => (v, true),
343					None => (Blob::new(vec![]), false), // dummy value
344				})
345				.unzip();
346
347			FrameColumn {
348				namespace: None,
349				source: None,
350				name: $name.to_string(),
351				data: FrameColumnData::Blob(BlobContainer::new(values, BitVec::from_slice(&bitvec))),
352			}
353		}};
354		($name:expr, Uuid4, $data:expr) => {{
355			let (values, bitvec): (Vec<_>, Vec<_>) = $data
356				.into_iter()
357				.map(|opt| match opt {
358					Some(v) => (v, true),
359					None => (
360						Uuid4::from(
361							parse_uuid4("550e8400-e29b-41d4-a716-446655440000").unwrap(),
362						),
363						false,
364					), // dummy value
365				})
366				.unzip();
367
368			FrameColumn {
369				namespace: None,
370				source: None,
371				name: $name.to_string(),
372				data: FrameColumnData::Uuid4(UuidContainer::new(values, BitVec::from_slice(&bitvec))),
373			}
374		}};
375		($name:expr, Uuid7, $data:expr) => {{
376			let (values, bitvec): (Vec<_>, Vec<_>) = $data
377				.into_iter()
378				.map(|opt| match opt {
379					Some(v) => (v, true),
380					None => (
381						Uuid7::from(
382							parse_uuid7("00000000-0000-7000-8000-000000000000").unwrap(),
383						),
384						false,
385					), // dummy value
386				})
387				.unzip();
388
389			FrameColumn {
390				namespace: None,
391				source: None,
392				name: $name.to_string(),
393				data: FrameColumnData::Uuid7(UuidContainer::new(values, BitVec::from_slice(&bitvec))),
394			}
395		}};
396		($name:expr, RowNumber, $data:expr) => {{
397			let (values, bitvec): (Vec<_>, Vec<_>) = $data
398				.into_iter()
399				.map(|opt| match opt {
400					Some(v) => (v, true),
401					None => (RowNumber(1), false), // dummy value
402				})
403				.unzip();
404
405			FrameColumn {
406				namespace: None,
407				source: None,
408				name: "__ROW__NUMBER__".to_string(),
409				data: FrameColumnData::RowNumber(RowNumberContainer::new(
410					values,
411					BitVec::from_slice(&bitvec),
412				)),
413			}
414		}};
415	}
416
417	fn undefined_column(name: &str, count: usize) -> FrameColumn {
418		FrameColumn {
419			namespace: None,
420			source: None,
421			name: name.to_string(),
422			data: FrameColumnData::Undefined(UndefinedContainer::new(count)),
423		}
424	}
425
426	fn row_number_column(data: impl IntoIterator<Item = RowNumber>) -> FrameColumn {
427		let data_vec: Vec<RowNumber> = data.into_iter().collect();
428		let bitvec = BitVec::repeat(data_vec.len(), true);
429		FrameColumn {
430			namespace: None,
431			source: None,
432			name: "__ROW__NUMBER__".to_string(),
433			data: FrameColumnData::RowNumber(RowNumberContainer::new(data_vec, bitvec)),
434		}
435	}
436
437	#[test]
438	fn test_bool() {
439		let frame = Frame::new(vec![column_with_undefineds!("bool", Bool, [Some(true), None])]);
440		let output = format!("{}", frame);
441		let expected = "\
442+-------------+
443|    bool     |
444+-------------+
445|    true     |
446|  Undefined  |
447+-------------+
448";
449		assert_eq!(output, expected);
450	}
451
452	#[test]
453	fn test_float4() {
454		let frame = Frame::new(vec![column_with_undefineds!("float4", Float4, [Some(1.2_f32), None])]);
455		let output = format!("{}", frame);
456		let expected = "\
457+-------------+
458|   float4    |
459+-------------+
460|     1.2     |
461|  Undefined  |
462+-------------+
463";
464		assert_eq!(output, expected);
465	}
466
467	#[test]
468	#[allow(clippy::approx_constant)]
469	fn test_float8() {
470		let frame = Frame::new(vec![column_with_undefineds!("float8", Float8, [Some(3.14_f64), None])]);
471		let output = format!("{}", frame);
472		let expected = "\
473+-------------+
474|   float8    |
475+-------------+
476|    3.14     |
477|  Undefined  |
478+-------------+
479";
480		assert_eq!(output, expected);
481	}
482
483	#[test]
484	fn test_int1() {
485		let frame = Frame::new(vec![column_with_undefineds!("int1", Int1, [Some(1_i8), None])]);
486		let output = format!("{}", frame);
487		let expected = "\
488+-------------+
489|    int1     |
490+-------------+
491|      1      |
492|  Undefined  |
493+-------------+
494";
495		assert_eq!(output, expected);
496	}
497
498	#[test]
499	fn test_int2() {
500		let frame = Frame::new(vec![column_with_undefineds!("int2", Int2, [Some(100_i16), None])]);
501		let output = format!("{}", frame);
502		let expected = "\
503+-------------+
504|    int2     |
505+-------------+
506|     100     |
507|  Undefined  |
508+-------------+
509";
510		assert_eq!(output, expected);
511	}
512
513	#[test]
514	fn test_int4() {
515		let frame = Frame::new(vec![column_with_undefineds!("int4", Int4, [Some(1000_i32), None])]);
516		let output = format!("{}", frame);
517		let expected = "\
518+-------------+
519|    int4     |
520+-------------+
521|    1000     |
522|  Undefined  |
523+-------------+
524";
525		assert_eq!(output, expected);
526	}
527
528	#[test]
529	fn test_int8() {
530		let frame = Frame::new(vec![column_with_undefineds!("int8", Int8, [Some(10000_i64), None])]);
531		let output = format!("{}", frame);
532		let expected = "\
533+-------------+
534|    int8     |
535+-------------+
536|    10000    |
537|  Undefined  |
538+-------------+
539";
540		assert_eq!(output, expected);
541	}
542
543	#[test]
544	fn test_int16() {
545		let frame = Frame::new(vec![column_with_undefineds!("int16", Int16, [Some(100000_i128), None])]);
546		let output = format!("{}", frame);
547		let expected = "\
548+-------------+
549|    int16    |
550+-------------+
551|   100000    |
552|  Undefined  |
553+-------------+
554";
555		assert_eq!(output, expected);
556	}
557
558	#[test]
559	fn test_uint1() {
560		let frame = Frame::new(vec![column_with_undefineds!("uint1", Uint1, [Some(1_u8), None])]);
561		let output = format!("{}", frame);
562		let expected = "\
563+-------------+
564|    uint1    |
565+-------------+
566|      1      |
567|  Undefined  |
568+-------------+
569";
570		assert_eq!(output, expected);
571	}
572
573	#[test]
574	fn test_uint2() {
575		let frame = Frame::new(vec![column_with_undefineds!("uint2", Uint2, [Some(100_u16), None])]);
576		let output = format!("{}", frame);
577		let expected = "\
578+-------------+
579|    uint2    |
580+-------------+
581|     100     |
582|  Undefined  |
583+-------------+
584";
585		assert_eq!(output, expected);
586	}
587
588	#[test]
589	fn test_uint4() {
590		let frame = Frame::new(vec![column_with_undefineds!("uint4", Uint4, [Some(1000_u32), None])]);
591		let output = format!("{}", frame);
592		let expected = "\
593+-------------+
594|    uint4    |
595+-------------+
596|    1000     |
597|  Undefined  |
598+-------------+
599";
600		assert_eq!(output, expected);
601	}
602
603	#[test]
604	fn test_uint8() {
605		let frame = Frame::new(vec![column_with_undefineds!("uint8", Uint8, [Some(10000_u64), None])]);
606		let output = format!("{}", frame);
607		let expected = "\
608+-------------+
609|    uint8    |
610+-------------+
611|    10000    |
612|  Undefined  |
613+-------------+
614";
615		assert_eq!(output, expected);
616	}
617
618	#[test]
619	fn test_uint16() {
620		let frame = Frame::new(vec![column_with_undefineds!("uint16", Uint16, [Some(100000_u128), None])]);
621		let output = format!("{}", frame);
622		let expected = "\
623+-------------+
624|   uint16    |
625+-------------+
626|   100000    |
627|  Undefined  |
628+-------------+
629";
630		assert_eq!(output, expected);
631	}
632
633	#[test]
634	fn test_string() {
635		let frame = Frame::new(vec![column_with_undefineds!("string", Utf8, [Some("foo"), None])]);
636		let output = format!("{}", frame);
637		let expected = "\
638+-------------+
639|   string    |
640+-------------+
641|     foo     |
642|  Undefined  |
643+-------------+
644";
645		assert_eq!(output, expected);
646	}
647
648	#[test]
649	fn test_undefined() {
650		let frame = Frame::new(vec![undefined_column("undefined", 2)]);
651		let output = format!("{}", frame);
652		let expected = "\
653+-------------+
654|  undefined  |
655+-------------+
656|  Undefined  |
657|  Undefined  |
658+-------------+
659";
660		assert_eq!(output, expected);
661	}
662
663	#[test]
664	fn test_date() {
665		let frame = Frame::new(vec![column_with_undefineds!(
666			"date",
667			Date,
668			[Some(Date::from_ymd(2025, 1, 15).unwrap()), None]
669		)]);
670		let output = format!("{}", frame);
671		let expected = "\
672+--------------+
673|     date     |
674+--------------+
675|  2025-01-15  |
676|  Undefined   |
677+--------------+
678";
679		assert_eq!(output, expected);
680	}
681
682	#[test]
683	fn test_datetime() {
684		let frame = Frame::new(vec![column_with_undefineds!(
685			"datetime",
686			DateTime,
687			[Some(DateTime::from_timestamp(1642694400).unwrap()), None]
688		)]);
689		let output = format!("{}", frame);
690		let expected = "\
691+----------------------------------+
692|             datetime             |
693+----------------------------------+
694|  2022-01-20T16:00:00.000000000Z  |
695|            Undefined             |
696+----------------------------------+
697";
698		assert_eq!(output, expected);
699	}
700
701	#[test]
702	fn test_time() {
703		let frame = Frame::new(vec![column_with_undefineds!(
704			"time",
705			Time,
706			[Some(Time::from_hms(14, 30, 45).unwrap()), None]
707		)]);
708		let output = format!("{}", frame);
709		let expected = "\
710+----------------------+
711|         time         |
712+----------------------+
713|  14:30:45.000000000  |
714|      Undefined       |
715+----------------------+
716";
717		assert_eq!(output, expected);
718	}
719
720	#[test]
721	fn test_interval() {
722		let frame = Frame::new(vec![column_with_undefineds!(
723			"interval",
724			Duration,
725			[Some(Duration::from_days(30)), None]
726		)]);
727		let output = format!("{}", frame);
728
729		let expected = "\
730+-------------+
731|  interval   |
732+-------------+
733|    P30D     |
734|  Undefined  |
735+-------------+
736";
737		assert_eq!(output, expected);
738	}
739
740	#[test]
741	fn test_row_number() {
742		let frame = Frame::new(vec![column_with_undefineds!(
743			"__ROW__NUMBER__",
744			RowNumber,
745			[Some(RowNumber(1234)), None]
746		)]);
747		let output = format!("{}", frame);
748		let expected = "\
749+-------------------+
750|  __ROW__NUMBER__  |
751+-------------------+
752|       1234        |
753|     Undefined     |
754+-------------------+
755";
756		assert_eq!(output, expected);
757	}
758
759	#[test]
760	fn test_row_number_column_ordering() {
761		// Create a frame with regular columns and a RowNumber column
762		let regular_column = column_with_undefineds!("name", Utf8, [Some("Alice"), Some("Bob")]);
763
764		let age_column = column_with_undefineds!("age", Int4, [Some(25_i32), Some(30_i32)]);
765
766		let row_number_column = row_number_column([RowNumber::new(1), RowNumber::new(2)]);
767
768		// Create frame with RowNumber column NOT first (it should be
769		// reordered)
770		let frame = Frame::new(vec![regular_column, age_column, row_number_column]);
771		let output = format!("{}", frame);
772
773		// Verify that __ROW__ID__ appears as the first column in the
774		// output
775		let lines: Vec<&str> = output.lines().collect();
776		let header_line = lines[1]; // Second line contains the header
777
778		// The header should start with __ROW__ID__ column
779		assert!(header_line.contains("__ROW__NUMBER__"));
780
781		// Check that the first data value in the first encoded is from the
782		// RowNumber column
783		let first_data_line = lines[3]; // Fourth line contains first data encoded
784		assert!(first_data_line.contains("1")); // First RowNumber value
785	}
786
787	#[test]
788	fn test_row_number_undefined_display() {
789		// Create a RowNumber column with one undefined value
790		let row_number_column = column_with_undefineds!(
791			"__ROW__NUMBER__",
792			RowNumber,
793			[Some(RowNumber::new(1)), None] /* Second value is
794			                                 * undefined */
795		);
796
797		let frame = Frame::new(vec![row_number_column]);
798		let output = format!("{}", frame);
799
800		// Verify that undefined RowNumber displays as "Undefined"
801		let lines: Vec<&str> = output.lines().collect();
802		let first_data_line = lines[3]; // First data encoded
803		let second_data_line = lines[4]; // Second data encoded
804
805		assert!(first_data_line.contains("1")); // First RowNumber value
806		assert!(second_data_line.contains("Undefined")); // Second value should be undefined
807	}
808
809	#[test]
810	fn test_blob() {
811		let frame = Frame::new(vec![column_with_undefineds!(
812			"blob",
813			Blob,
814			[Some(Blob::new(vec![0x01, 0x02, 0x03])), None]
815		)]);
816		let output = format!("{}", frame);
817		let expected = "\
818+-------------+
819|    blob     |
820+-------------+
821|  0x010203   |
822|  Undefined  |
823+-------------+
824";
825		assert_eq!(output, expected);
826	}
827
828	#[test]
829	fn test_uuid4() {
830		let frame = Frame::new(vec![column_with_undefineds!(
831			"uuid4",
832			Uuid4,
833			[Some(Uuid4::from(parse_uuid4("550e8400-e29b-41d4-a716-446655440000").unwrap())), None]
834		)]);
835		let output = format!("{}", frame);
836		let expected = "\
837+----------------------------------------+
838|                 uuid4                  |
839+----------------------------------------+
840|  550e8400-e29b-41d4-a716-446655440000  |
841|               Undefined                |
842+----------------------------------------+
843";
844		assert_eq!(output, expected);
845	}
846
847	#[test]
848	fn test_uuid7() {
849		let frame = Frame::new(vec![column_with_undefineds!(
850			"uuid7",
851			Uuid7,
852			[Some(Uuid7::from(parse_uuid7("01890a5d-ac96-774b-b9aa-789c0686aaa4").unwrap())), None]
853		)]);
854		let output = format!("{}", frame);
855		let expected = "\
856+----------------------------------------+
857|                 uuid7                  |
858+----------------------------------------+
859|  01890a5d-ac96-774b-b9aa-789c0686aaa4  |
860|               Undefined                |
861+----------------------------------------+
862";
863		assert_eq!(output, expected);
864	}
865
866	#[test]
867	fn test_renderer_without_row_numbers() {
868		// Create a frame with encoded numbers
869		let regular_column = column_with_undefineds!("name", Utf8, [Some("Alice"), Some("Bob")]);
870		let age_column = column_with_undefineds!("age", Int4, [Some(25_i32), Some(30_i32)]);
871
872		let mut frame = Frame::new(vec![regular_column, age_column]);
873		frame.row_numbers = vec![RowNumber::new(1), RowNumber::new(2)];
874
875		// Render with encoded numbers (using Display trait which uses full renderer)
876		let output_with_row_numbers = format!("{}", frame);
877		assert!(output_with_row_numbers.contains("__ROW__NUMBER__"));
878
879		// Render without encoded numbers using the new renderer
880		let output_without_row_numbers = FrameRenderer::render_without_row_numbers(&frame).unwrap();
881		assert!(!output_without_row_numbers.contains("__ROW__NUMBER__"));
882
883		// Check that it only has the regular columns
884		let expected_without_row_numbers = "\
885+---------+-------+
886|  name   |  age  |
887+---------+-------+
888|  Alice  |  25   |
889|   Bob   |  30   |
890+---------+-------+
891";
892		assert_eq!(output_without_row_numbers, expected_without_row_numbers);
893	}
894}