hawk_data/
output.rs

1use indexmap::IndexSet;
2use serde_json::Value;
3
4use crate::{Error, OutputFormat, value_to_string};
5
6#[derive(Debug)]
7enum DataType {
8    SimpleList,  // [string, number, bool]
9    ObjectArray, // [{"name": "Alice"}, {"name": "Bob"}]
10    NestedArray, // [[{"name": "Project1"}], [{"name": "Project2"}]]
11    Mixed,       // Other complex structures
12}
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            // 明示的にJSON出力
22            // Explicitly output JSON
23            print_as_json(data)?;
24        }
25        OutputFormat::Table => {
26            // 明示的にテーブル出力(可能な場合)
27            // Explicitly output table (if possible)
28            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            // 明示的にリスト出力
43            // Explicitly output list
44            print_as_list(data);
45        }
46        OutputFormat::Auto => {
47            // 既存のスマート判定ロジック
48            // Existing smart judgment logic
49            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    // ネストした配列かチェック
80    // Check for nested arrays
81    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                // 配列の中身を展開
95                // Expand the contents of the array
96                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                // serde_json::Mapは順序を保持
112                // serde_json::Map preserves order
113                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            // 配列は簡略表示
151            // Arrays are displayed in simplified form.
152            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    // 1. 全オブジェクトからフラット化されたフィールド名を収集
208    // 1. Collect flattened field names from all objects
209    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    // 2. 各列の最大幅を計算
217    // 2. Calculate the maximum width of each column
218    let mut max_widths = vec![0; fields.len()];
219
220    // ヘッダーの幅
221    // Header width
222    for (i, field) in fields.iter().enumerate() {
223        max_widths[i] = field.len();
224    }
225
226    // データの幅
227    // Data width
228    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    // 3. ヘッダー出力
236    // 3. Header output
237    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    // 4. データ行出力
246    // 4. Data row output
247    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    // データ型の分析
268    // Analysis of data types
269    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            // フィールド一覧と型情報
277            // Field list and type information
278            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            // 配列フィールドの詳細
286            // Details of array fields
287            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            // ネストした配列の詳細
307            // Details of nested arrays
308        }
309        _ => {
310            println!("Type: Simple Values");
311            // プリミティブ値の統計
312            // Statistics on primitive values
313        }
314    }
315}