vantage_table/table/impls/
columns.rs1use indexmap::IndexMap;
2use vantage_expressions::{Expression, Expressive, traits::datasource::ExprDataSource};
3use vantage_types::Entity;
4
5use crate::{
6 column::core::ColumnType, prelude::ColumnLike, table::Table, traits::table_source::TableSource,
7};
8
9impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
10 pub fn add_column<NewColumnType>(&mut self, column: T::Column<NewColumnType>)
12 where
13 NewColumnType: ColumnType,
14 {
15 let name = column.name().to_string();
16
17 if self.columns.contains_key(&name) {
18 panic!("Duplicate column: {}", name);
19 }
20
21 let any_column = self.data_source.to_any_column(column);
23 self.columns.insert(name, any_column);
24 }
25
26 pub fn with_column<NewColumnType>(mut self, column: T::Column<NewColumnType>) -> Self
28 where
29 NewColumnType: ColumnType,
30 {
31 self.add_column(column);
32 self
33 }
34
35 pub fn copy_columns_from<E2: Entity<T::Value>>(
40 &mut self,
41 other: &Table<T, E2>,
42 names: Option<&[&str]>,
43 ) {
44 for col in other.columns().values() {
45 let name = col.name();
46 if names.is_some_and(|ns| !ns.contains(&name)) {
47 continue;
48 }
49 if !self.columns.contains_key(name) {
50 self.add_column(col.clone());
51 }
52 }
53 }
54
55 pub fn add_column_of<NewColumnType>(&mut self, name: impl Into<String>)
57 where
58 NewColumnType: ColumnType,
59 {
60 let column = self
61 .data_source
62 .create_column::<NewColumnType>(&name.into());
63 self.add_column(column);
64 }
65
66 pub fn with_id_column(mut self, name: impl Into<String>) -> Self
68 where
69 T::Id: ColumnType,
70 {
71 let name = name.into();
72 self.id_field = Some(name.clone());
73 let column = self.data_source.create_column::<T::Id>(&name);
74 self.add_column(column);
75 self
76 }
77
78 pub fn with_text_id(mut self) -> Self {
84 self.id_text = true;
85 self
86 }
87
88 pub fn id_is_text(&self) -> bool {
90 self.id_text
91 }
92
93 pub fn with_auto_id(mut self) -> Self {
97 self.id_auto = true;
98 self
99 }
100
101 pub fn has_auto_id(&self) -> bool {
103 self.id_auto
104 }
105
106 pub fn with_title_column_of<NewColumnType>(mut self, name: impl Into<String>) -> Self
112 where
113 NewColumnType: ColumnType,
114 {
115 let name = name.into();
116 if !self.title_fields.contains(&name) {
117 self.title_fields.push(name.clone());
118 }
119 if self.title_field.is_none() {
120 self.title_field = Some(name.clone());
121 }
122 let column = self.data_source.create_column::<NewColumnType>(&name);
123 self.add_column(column);
124 self
125 }
126
127 pub fn with_title_column<NewColumnType>(mut self, column: T::Column<NewColumnType>) -> Self
131 where
132 NewColumnType: ColumnType,
133 {
134 let name = column.name().to_string();
135 if !self.title_fields.contains(&name) {
136 self.title_fields.push(name.clone());
137 }
138 if self.title_field.is_none() {
139 self.title_field = Some(name);
140 }
141 self.add_column(column);
142 self
143 }
144
145 pub fn with_column_of<NewColumnType>(self, name: impl Into<String>) -> Self
147 where
148 NewColumnType: ColumnType,
149 {
150 let column = self
151 .data_source
152 .create_column::<NewColumnType>(&name.into());
153 self.with_column(column)
154 }
155
156 pub fn columns(&self) -> &IndexMap<String, T::Column<T::AnyType>> {
158 &self.columns
159 }
160
161 pub fn get_column<Type>(&self, name: &str) -> Option<T::Column<Type>>
163 where
164 Type: ColumnType,
165 {
166 let any_column = self.columns.get(name)?;
167 self.data_source
168 .convert_any_column::<Type>(any_column.clone())
169 }
170
171 pub fn get_column_expr(&self, name: &str) -> Option<vantage_expressions::Expression<T::Value>>
177 where
178 T::Column<T::AnyType>: vantage_expressions::Expressive<T::Value>,
179 {
180 if let Some(expr_fn) = self.expressions.get(name) {
181 Some(expr_fn(self.as_entity_erased()))
182 } else {
183 use vantage_expressions::Expressive;
184 self.columns.get(name).map(|c| c.expr())
185 }
186 }
187}
188
189impl<T, E> Table<T, E>
190where
191 T: TableSource + ExprDataSource<T::Value>,
192 E: Entity<T::Value> + 'static,
193{
194 pub fn column_values_expr(&self, column_name: &str) -> Expression<T::Value> {
207 let col = self
208 .get_column::<T::AnyType>(column_name)
209 .unwrap_or_else(|| panic!("column {column_name:?} not found on table"));
210 self.data_source.column_table_values_expr(self, &col).expr()
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::mocks::mock_column::MockColumn;
218 use crate::prelude::MockTableSource;
219 use serde_json::Value;
220 use vantage_types::EmptyEntity;
221
222 #[test]
223 fn test_add_column() {
224 let ds = MockTableSource::new();
225 let mut table = Table::<MockTableSource, EmptyEntity>::new("test", ds);
226
227 table.add_column(MockColumn::<String>::new("name"));
228
229 assert!(table.columns().contains_key("name"));
230 assert_eq!(table.columns().len(), 1);
231 }
232
233 #[test]
234 fn test_with_column() {
235 let ds = MockTableSource::new();
236 let table = Table::<MockTableSource, EmptyEntity>::new("test", ds)
237 .with_column(MockColumn::<Value>::new("name"))
238 .with_column(MockColumn::<i32>::new("email"));
239
240 assert!(table.columns().contains_key("name"));
241 assert!(table.columns().contains_key("email"));
242 assert_eq!(table.columns().len(), 2);
243 }
244
245 #[test]
246 #[should_panic(expected = "Duplicate column")]
247 fn test_duplicate_column_panics() {
248 let ds = MockTableSource::new();
249 let mut table = Table::<MockTableSource, EmptyEntity>::new("test", ds);
250
251 table.add_column(MockColumn::<String>::new("name"));
252 table.add_column(MockColumn::<String>::new("name")); }
254
255 #[test]
256 fn test_with_column_of() {
257 let ds = MockTableSource::new();
258 let table = Table::<MockTableSource, EmptyEntity>::new("test", ds)
259 .with_column_of::<String>("name")
260 .with_column_of::<i64>("age")
261 .with_column_of::<bool>("active");
262
263 assert!(table.columns().contains_key("name"));
264 assert!(table.columns().contains_key("age"));
265 assert!(table.columns().contains_key("active"));
266 assert_eq!(table.columns().len(), 3);
267 }
268
269 #[test]
270 fn test_add_column_of() {
271 let ds = MockTableSource::new();
272 let mut table = Table::<MockTableSource, EmptyEntity>::new("test", ds);
273
274 table.add_column_of::<String>("email");
275 table.add_column_of::<i64>("balance");
276
277 assert!(table.columns().contains_key("email"));
278 assert!(table.columns().contains_key("balance"));
279 assert_eq!(table.columns().len(), 2);
280 }
281
282 #[test]
283 fn test_columns_access() {
284 let ds = MockTableSource::new();
285 let table = Table::<MockTableSource, EmptyEntity>::new("test", ds)
286 .with_column_of::<String>("name")
287 .with_column_of::<i64>("age");
288
289 let columns = table.columns();
290 assert!(columns.contains_key("name"));
291 assert!(columns.contains_key("age"));
292 assert_eq!(columns.len(), 2);
293
294 let name_column = table.columns().get("name");
295 assert!(name_column.is_some());
296 assert_eq!(name_column.unwrap().name(), "name");
297
298 let missing_column = table.columns().get("missing");
299 assert!(missing_column.is_none());
300 }
301}