sql_cli/ui/operations/
data_export_operations.rs

1//! Data export operations
2//!
3//! This module contains operations for exporting data to various formats,
4//! extracted from the monolithic TUI to improve maintainability and testability.
5
6use crate::data::data_exporter::DataExporter;
7use crate::data::data_provider::DataProvider;
8
9/// Context for data export operations
10/// Provides the minimal interface needed for export operations without coupling to the full TUI
11pub struct DataExportContext<'a> {
12    pub data_provider: Option<Box<dyn DataProvider + 'a>>,
13}
14
15/// Result of a data export operation
16#[derive(Debug)]
17pub enum ExportResult {
18    Success(String),
19    Error(anyhow::Error),
20}
21
22impl ExportResult {
23    /// Apply the result to a status handler (success message or error)
24    pub fn apply_to_status<F, G>(self, set_status: F, set_error: G)
25    where
26        F: FnOnce(String),
27        G: FnOnce(&str, anyhow::Error),
28    {
29        match self {
30            ExportResult::Success(message) => set_status(message),
31            ExportResult::Error(e) => set_error("Export failed", e),
32        }
33    }
34}
35
36/// Export data to CSV format
37pub fn export_to_csv(ctx: &DataExportContext) -> ExportResult {
38    let result = if let Some(ref provider) = ctx.data_provider {
39        DataExporter::export_provider_to_csv(provider.as_ref())
40    } else {
41        Err(anyhow::anyhow!("No data available to export"))
42    };
43
44    match result {
45        Ok(message) => ExportResult::Success(message),
46        Err(e) => ExportResult::Error(e),
47    }
48}
49
50/// Export data to JSON format
51pub fn export_to_json(ctx: &DataExportContext) -> ExportResult {
52    let result = if let Some(ref provider) = ctx.data_provider {
53        DataExporter::export_provider_to_json(provider.as_ref())
54    } else {
55        Err(anyhow::anyhow!("No data available to export"))
56    };
57
58    match result {
59        Ok(message) => ExportResult::Success(message),
60        Err(e) => ExportResult::Error(e),
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::data::data_provider::DataProvider;
68
69    // Mock data provider for testing
70    #[derive(Debug)]
71    struct MockDataProvider {
72        should_fail: bool,
73    }
74
75    impl DataProvider for MockDataProvider {
76        fn get_row(&self, _index: usize) -> Option<Vec<String>> {
77            None
78        }
79
80        fn get_column_count(&self) -> usize {
81            0
82        }
83        fn get_row_count(&self) -> usize {
84            0
85        }
86        fn get_column_names(&self) -> Vec<String> {
87            vec![]
88        }
89    }
90
91    #[test]
92    fn test_export_csv_no_provider() {
93        let ctx = DataExportContext {
94            data_provider: None,
95        };
96
97        let result = export_to_csv(&ctx);
98        match result {
99            ExportResult::Error(e) => assert_eq!(e.to_string(), "No data available to export"),
100            _ => panic!("Expected error for no provider"),
101        }
102    }
103
104    #[test]
105    fn test_export_json_no_provider() {
106        let ctx = DataExportContext {
107            data_provider: None,
108        };
109
110        let result = export_to_json(&ctx);
111        match result {
112            ExportResult::Error(e) => assert_eq!(e.to_string(), "No data available to export"),
113            _ => panic!("Expected error for no provider"),
114        }
115    }
116
117    #[test]
118    fn test_export_result_apply_success() {
119        let result = ExportResult::Success("Export completed".to_string());
120        let mut status_set = false;
121        let mut error_set = false;
122
123        result.apply_to_status(
124            |msg| {
125                assert_eq!(msg, "Export completed");
126                status_set = true;
127            },
128            |_prefix, _error| {
129                error_set = true;
130            },
131        );
132
133        assert!(status_set);
134        assert!(!error_set);
135    }
136
137    #[test]
138    fn test_export_result_apply_error() {
139        let result = ExportResult::Error(anyhow::anyhow!("Test error"));
140        let mut status_set = false;
141        let mut error_set = false;
142
143        result.apply_to_status(
144            |_msg| {
145                status_set = true;
146            },
147            |prefix, error| {
148                assert_eq!(prefix, "Export failed");
149                assert_eq!(error.to_string(), "Test error");
150                error_set = true;
151            },
152        );
153
154        assert!(!status_set);
155        assert!(error_set);
156    }
157}