sql_cli/
column_manager.rs1use serde_json::Value;
2
3pub struct ColumnManager;
5
6impl ColumnManager {
7    #[must_use]
9    pub fn calculate_optimal_widths(data: &[Value]) -> Vec<u16> {
10        if data.is_empty() {
11            return Vec::new();
12        }
13
14        let first_row = match data.first() {
15            Some(row) => row,
16            None => return Vec::new(),
17        };
18
19        let obj = match first_row.as_object() {
20            Some(obj) => obj,
21            None => return Vec::new(),
22        };
23
24        let headers: Vec<&str> = obj.keys().map(std::string::String::as_str).collect();
25        let mut widths = Vec::new();
26
27        const MAX_ROWS_TO_CHECK: usize = 100;
29        let total_rows = data.len();
30
31        let rows_to_check: Vec<usize> = if total_rows <= MAX_ROWS_TO_CHECK {
33            (0..total_rows).collect()
35        } else {
36            let step = total_rows / MAX_ROWS_TO_CHECK;
38            (0..MAX_ROWS_TO_CHECK)
39                .map(|i| (i * step).min(total_rows - 1))
40                .collect()
41        };
42
43        for header in &headers {
44            let mut max_width = header.len();
46
47            for &row_idx in &rows_to_check {
49                if let Some(row) = data.get(row_idx) {
50                    if let Some(obj) = row.as_object() {
51                        if let Some(value) = obj.get(*header) {
52                            let display_len = match value {
53                                Value::String(s) => s.len(),
54                                Value::Number(n) => n.to_string().len(),
55                                Value::Bool(b) => b.to_string().len(),
56                                Value::Null => 4, _ => value.to_string().len(),
58                            };
59                            max_width = max_width.max(display_len);
60                        }
61                    }
62                }
63            }
64
65            let optimal_width = (max_width + 2).max(4).min(50); widths.push(optimal_width as u16);
68        }
69
70        widths
71    }
72
73    #[must_use]
75    pub fn calculate_widths_for_filtered(headers: &[String], data: &[Vec<String>]) -> Vec<u16> {
76        let mut widths = Vec::new();
77
78        const MAX_ROWS_TO_CHECK: usize = 100;
80        let total_rows = data.len();
81
82        let rows_to_check: Vec<usize> = if total_rows <= MAX_ROWS_TO_CHECK {
84            (0..total_rows).collect()
85        } else {
86            let step = total_rows / MAX_ROWS_TO_CHECK;
87            (0..MAX_ROWS_TO_CHECK)
88                .map(|i| (i * step).min(total_rows - 1))
89                .collect()
90        };
91
92        for (col_idx, header) in headers.iter().enumerate() {
93            let mut max_width = header.len();
95
96            for &row_idx in &rows_to_check {
98                if let Some(row) = data.get(row_idx) {
99                    if let Some(value) = row.get(col_idx) {
100                        max_width = max_width.max(value.len());
101                    }
102                }
103            }
104
105            let optimal_width = (max_width + 2).max(4).min(50);
107            widths.push(optimal_width as u16);
108        }
109
110        widths
111    }
112
113    #[must_use]
115    pub fn get_value_display_width(value: &Value) -> usize {
116        match value {
117            Value::String(s) => s.len(),
118            Value::Number(n) => n.to_string().len(),
119            Value::Bool(b) => b.to_string().len(),
120            Value::Null => 4, _ => value.to_string().len(),
122        }
123    }
124}