reifydb_type/value/frame/
frame.rs1use std::{
5 fmt::{self, Display, Formatter},
6 ops::{Deref, Index},
7};
8
9use serde::{Deserialize, Serialize};
10
11use super::FrameColumn;
12use crate::{RowNumber, util::unicode::UnicodeWidthStr};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Frame {
16 pub row_numbers: Vec<RowNumber>,
17 pub columns: Vec<FrameColumn>,
18}
19
20impl Deref for Frame {
21 type Target = [FrameColumn];
22
23 fn deref(&self) -> &Self::Target {
24 &self.columns
25 }
26}
27
28impl Index<usize> for Frame {
29 type Output = FrameColumn;
30
31 fn index(&self, index: usize) -> &Self::Output {
32 self.columns.index(index)
33 }
34}
35
36fn escape_control_chars(s: &str) -> String {
37 s.replace('\n', "\\n").replace('\t', "\\t")
38}
39
40impl Frame {
41 pub fn new(columns: Vec<FrameColumn>) -> Self {
42 Self {
43 row_numbers: Vec::new(),
44 columns,
45 }
46 }
47
48 pub fn with_row_numbers(columns: Vec<FrameColumn>, row_numbers: Vec<RowNumber>) -> Self {
49 Self {
50 row_numbers,
51 columns,
52 }
53 }
54}
55
56impl Display for Frame {
57 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
58 let row_count = self.first().map_or(0, |c| c.data.len());
59 let has_row_numbers = !self.row_numbers.is_empty();
60
61 let mut col_widths: Vec<usize> = Vec::new();
63
64 if has_row_numbers {
66 let header_width = "rownum".width();
67 let max_val_width = self.row_numbers.iter().map(|rn| rn.to_string().width()).max().unwrap_or(0);
68 col_widths.push(header_width.max(max_val_width));
69 }
70
71 for col in &self.columns {
73 let header_width = escape_control_chars(&col.qualified_name()).width();
74 let mut max_val_width = 0;
75 for i in 0..col.data.len() {
76 max_val_width = max_val_width.max(escape_control_chars(&col.data.as_string(i)).width());
77 }
78 col_widths.push(header_width.max(max_val_width));
79 }
80
81 for w in &mut col_widths {
83 *w += 2;
84 }
85
86 let sep: String = if col_widths.is_empty() {
88 "++".to_string()
89 } else {
90 col_widths.iter().map(|w| format!("+{}", "-".repeat(*w + 2))).collect::<String>() + "+"
91 };
92
93 writeln!(f, "{}", sep)?;
94
95 let mut header_parts = Vec::new();
97 let mut col_idx = 0;
98 if has_row_numbers {
99 let name = "rownum";
100 let w = col_widths[col_idx];
101 let pad = w - name.width();
102 let l = pad / 2;
103 let r = pad - l;
104 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
105 col_idx += 1;
106 }
107 for col in &self.columns {
108 let name = escape_control_chars(&col.qualified_name());
109 let w = col_widths[col_idx];
110 let pad = w - name.width();
111 let l = pad / 2;
112 let r = pad - l;
113 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
114 col_idx += 1;
115 }
116 writeln!(f, "|{}|", header_parts.join("|"))?;
117 writeln!(f, "{}", sep)?;
118
119 for row_idx in 0..row_count {
121 let mut row_parts = Vec::new();
122 let mut col_idx = 0;
123 if has_row_numbers {
124 let w = col_widths[col_idx];
125 let val = if row_idx < self.row_numbers.len() {
126 self.row_numbers[row_idx].to_string()
127 } else {
128 "Undefined".to_string()
129 };
130 let pad = w - val.width();
131 let l = pad / 2;
132 let r = pad - l;
133 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
134 col_idx += 1;
135 }
136 for col in &self.columns {
137 let w = col_widths[col_idx];
138 let val = escape_control_chars(&col.data.as_string(row_idx));
139 let pad = w - val.width();
140 let l = pad / 2;
141 let r = pad - l;
142 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
143 col_idx += 1;
144 }
145 writeln!(f, "|{}|", row_parts.join("|"))?;
146 }
147
148 writeln!(f, "{}", sep)
149 }
150}