reifydb_value/value/frame/
frame.rs1use std::{
5 fmt::{self, Display, Formatter},
6 ops::{Deref, Index},
7};
8
9use serde::{Deserialize, Serialize};
10
11use super::column::FrameColumn;
12use crate::{
13 util::unicode::UnicodeWidthStr,
14 value::{Value, datetime::DateTime, row_number::RowNumber},
15};
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct Frame {
19 pub row_numbers: Vec<RowNumber>,
20 pub created_at: Vec<DateTime>,
21 pub updated_at: Vec<DateTime>,
22 pub columns: Vec<FrameColumn>,
23}
24
25impl Deref for Frame {
26 type Target = [FrameColumn];
27
28 fn deref(&self) -> &Self::Target {
29 &self.columns
30 }
31}
32
33impl Index<usize> for Frame {
34 type Output = FrameColumn;
35
36 fn index(&self, index: usize) -> &Self::Output {
37 self.columns.index(index)
38 }
39}
40
41fn escape_control_chars(s: &str) -> String {
42 s.replace('\n', "\\n").replace('\t', "\\t")
43}
44
45impl Frame {
46 pub fn new(columns: Vec<FrameColumn>) -> Self {
47 Self {
48 row_numbers: Vec::new(),
49 created_at: Vec::new(),
50 updated_at: Vec::new(),
51 columns,
52 }
53 }
54
55 pub fn with_row_numbers(columns: Vec<FrameColumn>, row_numbers: Vec<RowNumber>) -> Self {
56 Self {
57 row_numbers,
58 created_at: Vec::new(),
59 updated_at: Vec::new(),
60 columns,
61 }
62 }
63
64 pub fn to_rows(&self) -> Vec<Vec<(String, Value)>> {
65 let row_count = self.first().map_or(0, |c| c.data.len());
66 (0..row_count)
67 .map(|row_idx| {
68 self.columns.iter().map(|col| (col.name.clone(), col.data.get_value(row_idx))).collect()
69 })
70 .collect()
71 }
72}
73
74impl Display for Frame {
75 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
76 let row_count = self.first().map_or(0, |c| c.data.len());
77 let has_row_numbers = !self.row_numbers.is_empty();
78 let has_created_at = !self.created_at.is_empty();
79 let has_updated_at = !self.updated_at.is_empty();
80
81 let mut col_widths: Vec<usize> = Vec::new();
82
83 if has_row_numbers {
84 let header_width = "#rownum".width();
85 let max_val_width = self.row_numbers.iter().map(|rn| rn.to_string().width()).max().unwrap_or(0);
86 col_widths.push(header_width.max(max_val_width));
87 }
88 if has_created_at {
89 let header_width = "#created_at".width();
90 let max_val_width = self.created_at.iter().map(|ts| ts.to_string().width()).max().unwrap_or(0);
91 col_widths.push(header_width.max(max_val_width));
92 }
93 if has_updated_at {
94 let header_width = "#updated_at".width();
95 let max_val_width = self.updated_at.iter().map(|ts| ts.to_string().width()).max().unwrap_or(0);
96 col_widths.push(header_width.max(max_val_width));
97 }
98
99 for col in &self.columns {
100 let header_width = escape_control_chars(&col.name).width();
101 let mut max_val_width = 0;
102 for i in 0..col.data.len() {
103 max_val_width = max_val_width.max(escape_control_chars(&col.data.as_string(i)).width());
104 }
105 col_widths.push(header_width.max(max_val_width));
106 }
107
108 for w in &mut col_widths {
109 *w += 2;
110 }
111
112 let sep: String = if col_widths.is_empty() {
113 "++".to_string()
114 } else {
115 col_widths.iter().map(|w| format!("+{}", "-".repeat(*w + 2))).collect::<String>() + "+"
116 };
117
118 writeln!(f, "{}", sep)?;
119
120 let mut header_parts = Vec::new();
121 let mut col_idx = 0;
122 if has_row_numbers {
123 let name = "#rownum";
124 let w = col_widths[col_idx];
125 let pad = w - name.width();
126 let l = pad / 2;
127 let r = pad - l;
128 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
129 col_idx += 1;
130 }
131 if has_created_at {
132 let name = "#created_at";
133 let w = col_widths[col_idx];
134 let pad = w - name.width();
135 let l = pad / 2;
136 let r = pad - l;
137 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
138 col_idx += 1;
139 }
140 if has_updated_at {
141 let name = "#updated_at";
142 let w = col_widths[col_idx];
143 let pad = w - name.width();
144 let l = pad / 2;
145 let r = pad - l;
146 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
147 col_idx += 1;
148 }
149 for col in &self.columns {
150 let name = escape_control_chars(&col.name);
151 let w = col_widths[col_idx];
152 let pad = w - name.width();
153 let l = pad / 2;
154 let r = pad - l;
155 header_parts.push(format!(" {:l$}{}{:r$} ", "", name, ""));
156 col_idx += 1;
157 }
158 writeln!(f, "|{}|", header_parts.join("|"))?;
159 writeln!(f, "{}", sep)?;
160
161 for row_idx in 0..row_count {
162 let mut row_parts = Vec::new();
163 let mut col_idx = 0;
164 if has_row_numbers {
165 let w = col_widths[col_idx];
166 let val = self.row_numbers[row_idx].to_string();
167 let pad = w - val.width();
168 let l = pad / 2;
169 let r = pad - l;
170 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
171 col_idx += 1;
172 }
173 if has_created_at {
174 let w = col_widths[col_idx];
175 let val = self.created_at[row_idx].to_string();
176 let pad = w - val.width();
177 let l = pad / 2;
178 let r = pad - l;
179 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
180 col_idx += 1;
181 }
182 if has_updated_at {
183 let w = col_widths[col_idx];
184 let val = self.updated_at[row_idx].to_string();
185 let pad = w - val.width();
186 let l = pad / 2;
187 let r = pad - l;
188 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
189 col_idx += 1;
190 }
191 for col in &self.columns {
192 let w = col_widths[col_idx];
193 let val = escape_control_chars(&col.data.as_string(row_idx));
194 let pad = w - val.width();
195 let l = pad / 2;
196 let r = pad - l;
197 row_parts.push(format!(" {:l$}{}{:r$} ", "", val, ""));
198 col_idx += 1;
199 }
200 writeln!(f, "|{}|", row_parts.join("|"))?;
201 }
202
203 writeln!(f, "{}", sep)
204 }
205}