1use serde_json::Value;
2use std::path::Path;
3
4use crate::cli::error::AppError;
5use crate::cli::sheet_query::SheetBounds;
6use crate::excel::{Sheet, Workbook};
7use crate::utils::index_to_col_name;
8
9pub(crate) fn file_format(path: &Path) -> String {
10 path.extension()
11 .and_then(|extension| extension.to_str())
12 .map(str::to_lowercase)
13 .unwrap_or_else(|| "unknown".to_string())
14}
15
16pub(crate) fn format_range(
17 start_row: usize,
18 start_col: usize,
19 end_row: usize,
20 end_col: usize,
21) -> String {
22 format!(
23 "{}{}:{}{}",
24 index_to_col_name(start_col),
25 start_row,
26 index_to_col_name(end_col),
27 end_row
28 )
29}
30
31pub(crate) fn format_bounds(bounds: SheetBounds) -> String {
32 format_range(
33 bounds.start_row,
34 bounds.start_col,
35 bounds.end_row,
36 bounds.end_col,
37 )
38}
39
40pub(crate) fn value_text(value: &Value) -> String {
41 match value {
42 Value::Null => String::new(),
43 Value::String(value) => value.clone(),
44 other => other.to_string(),
45 }
46}
47
48pub(crate) fn tab_separated_values(values: &[Value]) -> String {
49 values.iter().map(value_text).collect::<Vec<_>>().join("\t")
50}
51
52pub(crate) fn sheet_by_index<'a>(
53 workbook: &'a Workbook,
54 sheet_index: usize,
55 sheet_name: &str,
56) -> Result<&'a Sheet, AppError> {
57 workbook
58 .get_sheet_by_index(sheet_index)
59 .ok_or_else(|| AppError::TargetNotFound {
60 message: format!("Sheet '{}' not found", sheet_name),
61 })
62}