sql_cli/debug/
dataview_debug.rs

1use crate::data::data_view::{DataView, SortOrder};
2use crate::debug::debug_trace::{DebugSection, DebugSectionBuilder, DebugTrace, Priority};
3use std::sync::Arc;
4
5/// Debug trace implementation for `DataView`
6pub struct DataViewDebugProvider {
7    dataview: Arc<DataView>,
8}
9
10impl DataViewDebugProvider {
11    #[must_use]
12    pub fn new(dataview: Arc<DataView>) -> Self {
13        Self { dataview }
14    }
15}
16
17impl DebugTrace for DataViewDebugProvider {
18    fn name(&self) -> &'static str {
19        "DataView"
20    }
21
22    fn debug_sections(&self) -> Vec<DebugSection> {
23        let mut builder = DebugSectionBuilder::new();
24
25        // Main DataView state section
26        builder.add_section("DATAVIEW STATE", "", Priority::DATAVIEW);
27
28        // Basic counts
29        builder.add_field("Visible Rows", self.dataview.row_count());
30        builder.add_field("Visible Columns", self.dataview.column_count());
31        builder.add_field("Source Rows", self.dataview.source().row_count());
32        builder.add_field("Source Columns", self.dataview.source().column_count());
33
34        // Column mapping information
35        builder.add_line("");
36        builder.add_line(self.dataview.get_column_debug_info());
37
38        // Show visible columns in order
39        let visible_columns = self.dataview.column_names();
40        let column_mappings = self.dataview.get_column_index_mapping();
41        builder.add_line(format!(
42            "\nVisible Columns ({}) with Index Mapping:",
43            visible_columns.len()
44        ));
45        for (visible_idx, col_name, datatable_idx) in &column_mappings {
46            builder.add_line(format!(
47                "  V[{visible_idx:3}] → DT[{datatable_idx:3}] : {col_name}"
48            ));
49        }
50
51        // Show internal state
52        builder.add_line("\n--- Internal State ---");
53        let visible_indices = self.dataview.get_visible_column_indices();
54        builder.add_line(format!("visible_columns array: {visible_indices:?}"));
55
56        // Pinned columns
57        let pinned_names = self.dataview.get_pinned_column_names();
58        if pinned_names.is_empty() {
59            builder.add_line("Pinned Columns: None");
60        } else {
61            builder.add_line(format!("\nPinned Columns ({}):", pinned_names.len()));
62            for (idx, name) in pinned_names.iter().enumerate() {
63                let source_idx = self.dataview.source().get_column_index(name).unwrap_or(999);
64                builder.add_line(format!("  [{idx}] {name} (source_idx: {source_idx})"));
65            }
66        }
67
68        // Sort state
69        let sort_state = self.dataview.get_sort_state();
70        match sort_state.order {
71            SortOrder::None => {
72                builder.add_line("Sort State: None");
73            }
74            SortOrder::Ascending => {
75                if let Some(col_idx) = sort_state.column {
76                    let col_name = visible_columns
77                        .get(col_idx)
78                        .map_or("unknown", std::string::String::as_str);
79                    builder.add_line(format!(
80                        "Sort State: Column {col_idx} ('{col_name}') Ascending ↑"
81                    ));
82                } else {
83                    builder.add_line("Sort State: Ascending (no column)");
84                }
85            }
86            SortOrder::Descending => {
87                if let Some(col_idx) = sort_state.column {
88                    let col_name = visible_columns
89                        .get(col_idx)
90                        .map_or("unknown", std::string::String::as_str);
91                    builder.add_line(format!(
92                        "Sort State: Column {col_idx} ('{col_name}') Descending ↓"
93                    ));
94                } else {
95                    builder.add_line("Sort State: Descending (no column)");
96                }
97            }
98        }
99
100        // Filter state
101        if let Some(filter) = self.dataview.get_filter_pattern() {
102            builder.add_line(format!("\nText Filter Active: '{filter}'"));
103        }
104        if let Some(fuzzy) = self.dataview.get_fuzzy_filter_pattern() {
105            builder.add_line(format!("Fuzzy Filter Active: '{fuzzy}'"));
106        }
107        if self.dataview.has_column_search() {
108            if let Some(pattern) = self.dataview.column_search_pattern() {
109                builder.add_line(format!("Column Search Active: '{pattern}'"));
110                let matches = self.dataview.get_matching_columns();
111                builder.add_line(format!("  {} matches found", matches.len()));
112            }
113        }
114
115        // Column order changes
116        let original_columns = self.dataview.source().column_names();
117        if visible_columns == original_columns {
118            builder.add_line("\nColumn Order Changed: NO");
119        } else {
120            builder.add_line("\nColumn Order Changed: YES");
121
122            // Show hidden columns
123            let hidden: Vec<String> = original_columns
124                .iter()
125                .filter(|col| !visible_columns.contains(col))
126                .cloned()
127                .collect();
128            if !hidden.is_empty() {
129                builder.add_line(format!("Hidden Columns ({}):", hidden.len()));
130                for col in hidden {
131                    builder.add_line(format!("  - {col}"));
132                }
133            }
134        }
135
136        builder.build()
137    }
138
139    fn debug_summary(&self) -> Option<String> {
140        let rows = self.dataview.row_count();
141        let cols = self.dataview.column_count();
142        let pinned = self.dataview.get_pinned_columns().len();
143        let filtered = self.dataview.has_filter();
144
145        let mut summary = format!("{rows}x{cols} view");
146        if pinned > 0 {
147            summary.push_str(&format!(", {pinned} pinned"));
148        }
149        if filtered {
150            summary.push_str(", filtered");
151        }
152
153        Some(summary)
154    }
155
156    fn is_active(&self) -> bool {
157        true
158    }
159}