Skip to main content

yew_datatable_core/column/
column_def.rs

1//! Definition of a table column.
2//!
3//! `ColumnDef` is generic over the row data type `T` and provides
4//! all configuration needed to display and interact with a column.
5
6use std::fmt;
7
8use crate::column::column_id::ColumnId;
9use crate::column::column_meta::ColumnMeta;
10use crate::column::data_table_dyn_accessor::DataTableDynAccessor;
11use crate::column::data_table_dyn_value::DataTableDynValue;
12use crate::features::aggregation::aggregation_fn::AggregationFn;
13use crate::features::filtering::filter_fn::FilterFn;
14use crate::features::sorting::sorting_fn::SortingFn;
15
16/// Definition of a table column.
17///
18/// `ColumnDef` is generic over the row data type `T` and provides
19/// all configuration needed to display and interact with a column.
20pub struct ColumnDef<T> {
21    /// Column metadata (ID, header, footer, etc.).
22    pub meta: ColumnMeta,
23
24    /// Accessor function to get the cell value from row data.
25    pub accessor: Option<DataTableDynAccessor<T>>,
26
27    /// Custom sorting function.
28    pub sorting_fn: Option<SortingFn<T>>,
29
30    /// Custom filter function.
31    pub filter_fn: Option<FilterFn<T>>,
32
33    /// Aggregation function for grouped rows.
34    pub aggregation_fn: Option<AggregationFn<T>>,
35
36    /// Child columns for grouped columns.
37    pub columns: Vec<ColumnDef<T>>,
38
39    /// Enable multi-sorting for this column.
40    pub enable_multi_sort: bool,
41
42    /// Invert the sort direction.
43    pub invert_sorting: bool,
44
45    /// Sort undefined values to the end.
46    pub sort_undefined_last: bool,
47}
48
49impl<T> ColumnDef<T> {
50    /// Creates a new column definition with the given ID and header.
51    ///
52    /// # Parameters
53    ///
54    /// - `id`: The column identifier.
55    /// - `header`: The display header text.
56    ///
57    /// # Returns
58    ///
59    /// - `ColumnDef<T>`: A new column definition with default settings.
60    pub fn new(id: impl Into<ColumnId>, header: impl Into<String>) -> Self {
61        Self {
62            meta: ColumnMeta::new(id, header),
63            accessor: None,
64            sorting_fn: None,
65            filter_fn: None,
66            aggregation_fn: None,
67            columns: Vec::new(),
68            enable_multi_sort: true,
69            invert_sorting: false,
70            sort_undefined_last: true,
71        }
72    }
73
74    /// Creates a group column with child columns.
75    ///
76    /// # Parameters
77    ///
78    /// - `id`: The column identifier.
79    /// - `header`: The display header text.
80    /// - `columns`: The child column definitions.
81    ///
82    /// # Returns
83    ///
84    /// - `ColumnDef<T>`: A new group column definition.
85    pub fn group(id: impl Into<ColumnId>, header: impl Into<String>, columns: Vec<ColumnDef<T>>) -> Self {
86        Self {
87            meta: ColumnMeta::new(id, header).as_group(),
88            accessor: None,
89            sorting_fn: None,
90            filter_fn: None,
91            aggregation_fn: None,
92            columns,
93            enable_multi_sort: false,
94            invert_sorting: false,
95            sort_undefined_last: true,
96        }
97    }
98
99    /// Returns the column ID.
100    ///
101    /// # Returns
102    ///
103    /// - `&ColumnId`: A reference to the column identifier.
104    pub fn id(&self) -> &ColumnId {
105        &self.meta.id
106    }
107
108    /// Returns the column header text.
109    ///
110    /// # Returns
111    ///
112    /// - `&str`: The column header text.
113    pub fn header(&self) -> &str {
114        &self.meta.header
115    }
116
117    /// Returns whether this column is sortable.
118    ///
119    /// # Returns
120    ///
121    /// - `bool`: Whether sorting is enabled for this column.
122    pub fn is_sortable(&self) -> bool {
123        self.meta.sortable
124    }
125
126    /// Returns whether this column is filterable.
127    ///
128    /// # Returns
129    ///
130    /// - `bool`: Whether filtering is enabled for this column.
131    pub fn is_filterable(&self) -> bool {
132        self.meta.filterable
133    }
134
135    /// Returns whether this column is a group column.
136    ///
137    /// # Returns
138    ///
139    /// - `bool`: Whether this is a group column containing sub-columns.
140    pub fn is_group(&self) -> bool {
141        self.meta.is_group
142    }
143
144    /// Returns the child columns for group columns.
145    ///
146    /// # Returns
147    ///
148    /// - `&[ColumnDef<T>]`: A slice of child column definitions.
149    pub fn children(&self) -> &[ColumnDef<T>] {
150        &self.columns
151    }
152
153    /// Gets the value from the row using the accessor.
154    ///
155    /// # Parameters
156    ///
157    /// - `row`: The row data to extract the value from.
158    ///
159    /// # Returns
160    ///
161    /// - `Option<Box<dyn DataTableDynValue>>`: The extracted value, or None if no accessor is set.
162    pub fn get_value(&self, row: &T) -> Option<Box<dyn DataTableDynValue>> {
163        // Invoke the accessor if present.
164        self.accessor.as_ref().map(|a: &DataTableDynAccessor<T>| a.get(row))
165    }
166
167    /// Flattens the column hierarchy into a list of leaf columns.
168    ///
169    /// # Returns
170    ///
171    /// - `Vec<&ColumnDef<T>>`: A vector of references to leaf columns.
172    pub fn flatten(&self) -> Vec<&ColumnDef<T>> {
173        // Check if this column has children.
174        if self.columns.is_empty() {
175            vec![self]
176        } else {
177            // Recursively flatten all child columns.
178            self.columns.iter().flat_map(|c| c.flatten()).collect()
179        }
180    }
181
182    /// Returns all column IDs including nested columns.
183    ///
184    /// # Returns
185    ///
186    /// - `Vec<ColumnId>`: A vector of all column IDs in the hierarchy.
187    pub fn all_ids(&self) -> Vec<ColumnId> {
188        // Start with this column's ID.
189        let mut ids = vec![self.meta.id.clone()];
190
191        // Collect IDs from all child columns.
192        for child in &self.columns {
193            ids.extend(child.all_ids());
194        }
195
196        ids
197    }
198}
199
200/// Formats the column definition for debug output.
201impl<T> fmt::Debug for ColumnDef<T> {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        f.debug_struct("ColumnDef")
204            .field("meta", &self.meta)
205            .field("columns", &self.columns.len())
206            .finish_non_exhaustive()
207    }
208}