1use indexmap::IndexSet;
2use serde_json::Value;
3
4use crate::{Error, OutputFormat, value_to_string};
5
6#[derive(Debug)]
7enum DataType {
8 SimpleList, ObjectArray, NestedArray, Mixed, }
13
14pub fn format_output(data: &[Value], format: OutputFormat) -> Result<(), Error> {
15 if data.is_empty() {
16 return Ok(());
17 }
18
19 match format {
20 OutputFormat::Json => {
21 print_as_json(data)?;
24 }
25 OutputFormat::Table => {
26 if is_object_array(data) {
29 print_as_table(data);
30 } else {
31 let flattened = flatten_nested_arrays(data);
32 if is_object_array(&flattened) {
33 print_as_table(&flattened);
34 } else {
35 return Err(Error::InvalidQuery(
36 "Cannot display as table: data is not object array".into(),
37 ));
38 }
39 }
40 }
41 OutputFormat::List => {
42 print_as_list(data);
45 }
46 OutputFormat::Auto => {
47 match analyze_data_structure(data) {
50 DataType::SimpleList => print_as_list(data),
51 DataType::ObjectArray => print_as_table(data),
52 DataType::NestedArray => {
53 let flattened = flatten_nested_arrays(data);
54 if is_object_array(&flattened) {
55 print_as_table(&flattened);
56 } else if is_simple_values(&flattened) {
57 print_as_list(&flattened);
58 } else {
59 print_as_json(data)?;
60 }
61 }
62 DataType::Mixed => print_as_json(data)?,
63 }
64 }
65 }
66
67 Ok(())
68}
69
70fn analyze_data_structure(data: &[Value]) -> DataType {
71 if is_simple_values(data) {
72 return DataType::SimpleList;
73 }
74
75 if is_object_array(data) {
76 return DataType::ObjectArray;
77 }
78
79 if data.len() == 1 && data[0].is_array() {
82 return DataType::NestedArray;
83 }
84
85 DataType::Mixed
86}
87
88fn flatten_nested_arrays(data: &[Value]) -> Vec<Value> {
89 let mut flattened = Vec::new();
90
91 for item in data {
92 match item {
93 Value::Array(arr) => {
94 flattened.extend(arr.iter().cloned());
97 }
98 _ => {
99 flattened.push(item.clone());
100 }
101 }
102 }
103
104 flattened
105}
106
107fn collect_flattened_fields_ordered(value: &Value, prefix: &str, fields: &mut IndexSet<String>) {
108 match value {
109 Value::Object(obj) => {
110 for (key, val) in obj {
111 let field_name = if prefix.is_empty() {
114 key.clone()
115 } else {
116 format!("{}.{}", prefix, key)
117 };
118
119 match val {
120 Value::Object(_) => {
121 collect_flattened_fields_ordered(val, &field_name, fields);
122 }
123 _ => {
124 fields.insert(field_name);
125 }
126 }
127 }
128 }
129 _ => {
130 if !prefix.is_empty() {
131 fields.insert(prefix.to_string());
132 }
133 }
134 }
135}
136
137fn get_flattened_value(item: &Value, field_path: &str) -> String {
138 let parts: Vec<&str> = field_path.split('.').collect();
139 let mut current = item;
140
141 for part in parts {
142 match current.get(part) {
143 Some(val) => current = val,
144 None => return "".to_string(),
145 }
146 }
147
148 match current {
149 Value::Array(arr) => {
150 format!("[{} items]", arr.len())
153 }
154 _ => value_to_string(current),
155 }
156}
157
158fn get_value_type_info(value: &Value) -> &'static str {
159 match value {
160 Value::String(_) => "String",
161 Value::Number(_) => "Number",
162 Value::Bool(_) => "Boolean",
163 Value::Array(_) => "Array",
164 Value::Object(_) => "Object",
165 Value::Null => "Null",
166 }
167}
168
169fn get_sample_value(value: &Value) -> String {
170 match value {
171 Value::String(s) => format!("\"{}\"", s.chars().take(20).collect::<String>()),
172 Value::Number(n) => n.to_string(),
173 Value::Bool(b) => b.to_string(),
174 Value::Array(arr) => format!("[{} items]", arr.len()),
175 Value::Object(obj) => format!("{{{}...}}", obj.keys().next().unwrap_or(&"".to_string())),
176 Value::Null => "null".to_string(),
177 }
178}
179
180fn is_simple_values(data: &[Value]) -> bool {
181 data.iter()
182 .all(|v| matches!(v, Value::String(_) | Value::Number(_) | Value::Bool(_)))
183}
184
185fn is_object_array(data: &[Value]) -> bool {
186 data.iter().all(|v| v.is_object())
187}
188
189fn print_as_list(data: &[Value]) {
190 data.iter().for_each(|item| {
191 println!("{}", value_to_string(item));
192 });
193}
194
195fn print_as_json(data: &[Value]) -> Result<(), Error> {
196 let json = serde_json::to_string_pretty(data).map_err(|e| Error::Json(e))?;
197
198 println!("{}", json);
199 Ok(())
200}
201
202fn print_as_table(data: &[Value]) {
203 if data.is_empty() {
204 return;
205 }
206
207 let mut all_fields = IndexSet::new();
210 for item in data {
211 collect_flattened_fields_ordered(item, "", &mut all_fields);
212 }
213
214 let fields: Vec<String> = all_fields.into_iter().collect();
215
216 let mut max_widths = vec![0; fields.len()];
219
220 for (i, field) in fields.iter().enumerate() {
223 max_widths[i] = field.len();
224 }
225
226 for item in data {
229 for (i, field) in fields.iter().enumerate() {
230 let value_str = get_flattened_value(item, field);
231 max_widths[i] = max_widths[i].max(value_str.len());
232 }
233 }
234
235 for (i, field) in fields.iter().enumerate() {
238 print!("{:<width$}", field, width = max_widths[i]);
239 if i < fields.len() - 1 {
240 print!(" ");
241 }
242 }
243 println!();
244
245 for item in data {
248 for (i, field) in fields.iter().enumerate() {
249 let value_str = get_flattened_value(item, field);
250 print!("{:<width$}", value_str, width = max_widths[i]);
251 if i < fields.len() - 1 {
252 print!(" ");
253 }
254 }
255 println!();
256 }
257}
258
259pub fn print_data_info(data: &[Value]) {
260 println!("=== Data Information ===");
261 println!("Total records: {}", data.len());
262
263 if data.is_empty() {
264 return;
265 }
266
267 let first_item = &data[0];
270 match first_item {
271 Value::Object(obj) => {
272 println!("Type: Object Array");
273 println!("Fields: {}", obj.len());
274 println!();
275
276 println!("Field Details:");
279 for (key, value) in obj {
280 let field_type = get_value_type_info(value);
281 let sample_value = get_sample_value(value);
282 println!(" {:<15} {:<10} (e.g., {})", key, field_type, sample_value);
283 }
284
285 println!();
288 println!("Array Fields:");
289 for (key, value) in obj {
290 if let Value::Array(arr) = value {
291 println!(" {:<15} [{} items]", key, arr.len());
292 if let Some(first_elem) = arr.get(0) {
293 if let Value::Object(elem_obj) = first_elem {
294 print!(" └─ ");
295 let sub_fields: Vec<&String> = elem_obj.keys().collect();
296 let sub_fields: Vec<&str> =
297 sub_fields.into_iter().map(|f| f.as_str()).collect();
298 println!("{}", sub_fields.join(", "));
299 }
300 }
301 }
302 }
303 }
304 Value::Array(_) => {
305 println!("Type: Nested Array");
306 }
309 _ => {
310 println!("Type: Simple Values");
311 }
314 }
315}