contextdb_cli/
formatter.rs1use contextdb_core::Value;
2use contextdb_engine::QueryResult;
3
4pub fn format_query_result(result: &QueryResult) -> String {
5 if result.columns.is_empty() {
6 return String::new();
7 }
8 if result.rows.is_empty() {
9 return String::new();
10 }
11
12 let mut widths: Vec<usize> = result.columns.iter().map(|c| c.len()).collect();
13
14 let rows: Vec<Vec<String>> = result
15 .rows
16 .iter()
17 .map(|row| row.iter().map(value_to_string).collect())
18 .collect();
19
20 for row in &rows {
21 for (i, cell) in row.iter().enumerate() {
22 if i < widths.len() {
23 widths[i] = widths[i].max(cell.len());
24 }
25 }
26 }
27
28 let sep = widths
29 .iter()
30 .map(|w| format!("+{}", "-".repeat(*w + 2)))
31 .collect::<String>()
32 + "+";
33
34 let mut out = String::new();
35 out.push_str(&sep);
36 out.push('\n');
37
38 out.push('|');
39 for (i, col) in result.columns.iter().enumerate() {
40 out.push(' ');
41 out.push_str(&format!("{:<width$}", col, width = widths[i]));
42 out.push(' ');
43 out.push('|');
44 }
45 out.push('\n');
46
47 out.push_str(&sep);
48 out.push('\n');
49
50 for row in rows {
51 out.push('|');
52 for (i, cell) in row.iter().enumerate() {
53 out.push(' ');
54 out.push_str(&format!("{:<width$}", cell, width = widths[i]));
55 out.push(' ');
56 out.push('|');
57 }
58 out.push('\n');
59 }
60
61 out.push_str(&sep);
62 out
63}
64
65fn value_to_string(v: &Value) -> String {
66 match v {
67 Value::Null => "NULL".to_string(),
68 Value::Bool(b) => b.to_string(),
69 Value::Int64(i) => i.to_string(),
70 Value::Float64(f) => f.to_string(),
71 Value::Text(s) => s.clone(),
72 Value::Uuid(u) => u.to_string(),
73 Value::Timestamp(ts) => ts.to_string(),
74 Value::Json(j) => j.to_string(),
75 Value::Vector(vec) => format!("{:?}", vec),
76 Value::TxId(tx) => tx.0.to_string(),
77 }
78}