1use crate::{
2 display::format_grid_cell_display_value,
3 models::{GridColumnDef, GridRow},
4 state::sanitize_download_filename,
5 utils::{titleize, to_csv_value},
6};
7
8pub const GRID_CSV_MIME_TYPE: &str = "text/csv;charset=utf-8";
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct GridExportContext<'a> {
12 pub grid_id: &'a str,
13 pub columns: &'a [GridColumnDef],
14 pub rows: &'a [GridRow],
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct GridExportPayload {
19 pub filename: String,
20 pub mime_type: String,
21 pub contents: String,
22}
23
24pub fn header_label(column: &GridColumnDef) -> String {
25 column
26 .display_name
27 .clone()
28 .unwrap_or_else(|| titleize(&column.name))
29}
30
31pub fn build_grid_export_context<'a>(
32 grid_id: &'a str,
33 columns: &'a [GridColumnDef],
34 rows: &'a [GridRow],
35) -> GridExportContext<'a> {
36 GridExportContext {
37 grid_id,
38 columns,
39 rows,
40 }
41}
42
43pub fn build_grid_export_payload(
44 filename: impl Into<String>,
45 mime_type: impl Into<String>,
46 contents: impl Into<String>,
47) -> GridExportPayload {
48 GridExportPayload {
49 filename: filename.into(),
50 mime_type: mime_type.into(),
51 contents: contents.into(),
52 }
53}
54
55pub fn default_csv_export_filename(grid_id: &str) -> String {
56 format!("{}.csv", sanitize_download_filename(grid_id))
57}
58
59pub fn export_csv_rows_with<F>(
60 columns: &[GridColumnDef],
61 rows: &[GridRow],
62 format_cell: F,
63) -> String
64where
65 F: Fn(&GridRow, &GridColumnDef) -> String,
66{
67 let header = columns
68 .iter()
69 .map(|column| to_csv_value(&header_label(column)))
70 .collect::<Vec<_>>()
71 .join(",");
72
73 let body = rows
74 .iter()
75 .map(|row| {
76 columns
77 .iter()
78 .map(|column| to_csv_value(&format_cell(row, column)))
79 .collect::<Vec<_>>()
80 .join(",")
81 })
82 .collect::<Vec<_>>();
83
84 std::iter::once(header)
85 .chain(body)
86 .collect::<Vec<_>>()
87 .join("\n")
88}
89
90pub fn export_csv_rows(columns: &[GridColumnDef], rows: &[GridRow]) -> String {
91 export_csv_rows_with(columns, rows, |row, column| {
92 format_grid_cell_display_value(row, column)
93 })
94}
95
96pub fn build_csv_export_payload(context: &GridExportContext<'_>) -> GridExportPayload {
97 build_grid_export_payload(
98 default_csv_export_filename(context.grid_id),
99 GRID_CSV_MIME_TYPE,
100 export_csv_rows(context.columns, context.rows),
101 )
102}
103
104pub fn build_csv_export_payload_with<F>(
105 context: &GridExportContext<'_>,
106 format_cell: F,
107) -> GridExportPayload
108where
109 F: Fn(&GridRow, &GridColumnDef) -> String,
110{
111 build_grid_export_payload(
112 default_csv_export_filename(context.grid_id),
113 GRID_CSV_MIME_TYPE,
114 export_csv_rows_with(context.columns, context.rows, format_cell),
115 )
116}