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}