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::{
15 Value,
16 datetime::DateTime,
17 diff_type::DiffType,
18 row_number::RowNumber,
19 system_columns::{SystemColumn, SystemColumns},
20 },
21};
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub struct Frame {
25 pub system: SystemColumns,
26 pub columns: Vec<FrameColumn>,
27 pub op: Option<DiffType>,
28}
29
30impl Frame {
31 #[inline]
32 pub fn row_numbers(&self) -> &[RowNumber] {
33 self.system.row_numbers()
34 }
35
36 #[inline]
37 pub fn created_at(&self) -> &[DateTime] {
38 self.system.created_at()
39 }
40
41 #[inline]
42 pub fn updated_at(&self) -> &[DateTime] {
43 self.system.updated_at()
44 }
45
46 #[inline]
47 pub fn time(&self) -> &[DateTime] {
48 self.system.time()
49 }
50}
51
52impl Deref for Frame {
53 type Target = [FrameColumn];
54
55 fn deref(&self) -> &Self::Target {
56 &self.columns
57 }
58}
59
60impl Index<usize> for Frame {
61 type Output = FrameColumn;
62
63 fn index(&self, index: usize) -> &Self::Output {
64 self.columns.index(index)
65 }
66}
67
68fn escape_control_chars(s: &str) -> String {
69 s.replace('\n', "\\n").replace('\t', "\\t")
70}
71
72fn present_system_columns(frame: &Frame) -> Vec<(&'static str, Vec<String>)> {
73 let candidates = [
74 (
75 SystemColumn::RowNumbers.name(),
76 frame.row_numbers().iter().map(|v| v.to_string()).collect::<Vec<_>>(),
77 ),
78 (SystemColumn::CreatedAt.name(), frame.created_at().iter().map(|v| v.to_string()).collect()),
79 (SystemColumn::UpdatedAt.name(), frame.updated_at().iter().map(|v| v.to_string()).collect()),
80 ];
81 candidates.into_iter().filter(|(_, cells)| !cells.is_empty()).collect()
82}
83
84fn centered(width: usize, content: &str) -> String {
85 let pad = width - content.width();
86 let l = pad / 2;
87 let r = pad - l;
88 format!(" {:l$}{}{:r$} ", "", content, "")
89}
90
91impl Frame {
92 pub fn new(columns: Vec<FrameColumn>) -> Self {
93 Self {
94 system: SystemColumns::empty(),
95 columns,
96 op: None,
97 }
98 }
99
100 pub fn with_op(mut self, op: DiffType) -> Self {
101 self.op = Some(op);
102 self
103 }
104
105 pub fn with_row_numbers(columns: Vec<FrameColumn>, row_numbers: Vec<RowNumber>) -> Self {
106 Self {
107 system: SystemColumns::new(row_numbers, Vec::new(), Vec::new(), Vec::new(), Vec::new()),
108 columns,
109 op: None,
110 }
111 }
112
113 pub fn to_rows(&self) -> Vec<Vec<(String, Value)>> {
114 let row_count = self.first().map_or(0, |c| c.data.len());
115 (0..row_count)
116 .map(|row_idx| {
117 self.columns.iter().map(|col| (col.name.clone(), col.data.get_value(row_idx))).collect()
118 })
119 .collect()
120 }
121}
122
123impl Display for Frame {
124 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
125 let row_count = self.first().map_or(0, |c| c.data.len());
126 let system = present_system_columns(self);
127
128 let mut col_widths: Vec<usize> = Vec::new();
129
130 for (header, cells) in &system {
131 let max_val_width = cells.iter().map(|c| c.width()).max().unwrap_or(0);
132 col_widths.push(header.width().max(max_val_width));
133 }
134
135 for col in &self.columns {
136 let header_width = escape_control_chars(&col.name).width();
137 let mut max_val_width = 0;
138 for i in 0..col.data.len() {
139 max_val_width = max_val_width.max(escape_control_chars(&col.data.as_string(i)).width());
140 }
141 col_widths.push(header_width.max(max_val_width));
142 }
143
144 for w in &mut col_widths {
145 *w += 2;
146 }
147
148 let sep: String = if col_widths.is_empty() {
149 "++".to_string()
150 } else {
151 col_widths.iter().map(|w| format!("+{}", "-".repeat(*w + 2))).collect::<String>() + "+"
152 };
153
154 writeln!(f, "{}", sep)?;
155
156 let mut header_parts = Vec::new();
157 for (col_idx, (header, _)) in system.iter().enumerate() {
158 header_parts.push(centered(col_widths[col_idx], header));
159 }
160 for (offset, col) in self.columns.iter().enumerate() {
161 let name = escape_control_chars(&col.name);
162 header_parts.push(centered(col_widths[system.len() + offset], &name));
163 }
164 writeln!(f, "|{}|", header_parts.join("|"))?;
165 writeln!(f, "{}", sep)?;
166
167 for row_idx in 0..row_count {
168 let mut row_parts = Vec::new();
169 for (col_idx, (_, cells)) in system.iter().enumerate() {
170 row_parts.push(centered(col_widths[col_idx], &cells[row_idx]));
171 }
172 for (offset, col) in self.columns.iter().enumerate() {
173 let val = escape_control_chars(&col.data.as_string(row_idx));
174 row_parts.push(centered(col_widths[system.len() + offset], &val));
175 }
176 writeln!(f, "|{}|", row_parts.join("|"))?;
177 }
178
179 writeln!(f, "{}", sep)
180 }
181}