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