vantage_table/table/impls/
selectable.rs1use vantage_core::Result;
2use vantage_expressions::traits::selectable::Selectable;
3use vantage_expressions::{Expression, Expressive, SelectableDataSource, expr_any};
4use vantage_types::Entity;
5
6use crate::{
7 column::core::ColumnType,
8 source::{SelectSeed, SelectSource},
9 table::Table,
10 traits::column_like::ColumnLike,
11 traits::table_source::TableSource,
12};
13
14impl<T, E> Table<T, E>
15where
16 T: SelectableDataSource<T::Value, T::Condition> + TableSource,
17 T::Source: SelectSeed<T::Select, T::Value, T::Condition>,
18 T::Value: From<String>, E: Entity<T::Value>,
20{
21 pub fn select_empty(&self) -> T::Select {
25 let mut select = self.data_source.select();
26 self.source.seed(&mut select);
27
28 for condition in self.conditions.values() {
29 select.add_where_condition(condition.clone());
30 }
31
32 for (expr, direction) in self.order_by.values() {
33 let order = match direction {
34 crate::sorting::SortDirection::Ascending => vantage_expressions::Order::Asc,
35 crate::sorting::SortDirection::Descending => vantage_expressions::Order::Desc,
36 };
37 select.add_order_by(expr.clone(), order);
38 }
39
40 if let Some(pagination) = &self.pagination {
41 select.set_limit(Some(pagination.limit()), Some(pagination.skip()));
42 }
43
44 select
45 }
46
47 pub fn select(&self) -> T::Select {
49 let mut select = self.select_empty();
50
51 for column in self.columns.values() {
53 if let Some(expr_fn) = self.expressions.get(column.name()) {
54 let expr = expr_fn(self);
55 self.data_source.add_select_column(
56 &mut select,
57 expr_any!("({})", (expr)),
58 Some(column.name()),
59 );
60 } else if let Some(alias) = column.alias() {
61 let expr = self.data_source.expr(column.name(), vec![]);
62 self.data_source
63 .add_select_column(&mut select, expr, Some(alias));
64 } else {
65 select.add_field(column.name());
66 }
67 }
68
69 for (name, expr_fn) in &self.expressions {
71 if !self.columns.contains_key(name) {
72 let expr = expr_fn(self);
73 self.data_source.add_select_column(
74 &mut select,
75 expr_any!("({})", (expr)),
76 Some(name),
77 );
78 }
79 }
80
81 select
82 }
83 pub async fn get_count(&self) -> Result<i64> {
85 self.data_source.get_table_count(self).await
86 }
87
88 pub async fn get_sum(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
90 self.data_source.get_table_sum(self, column).await
91 }
92
93 pub async fn get_max(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
95 self.data_source.get_table_max(self, column).await
96 }
97
98 pub async fn get_min(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
100 self.data_source.get_table_min(self, column).await
101 }
102
103 pub fn get_count_query(&self) -> Expression<T::Value> {
106 expr_any!("({})", (self.select_empty().as_count()))
107 }
108
109 pub fn get_sum_query<Type>(&self, column: &T::Column<Type>) -> Expression<T::Value>
112 where
113 Type: ColumnType,
114 T::Column<Type>: Expressive<T::Value>,
115 {
116 expr_any!("({})", (self.select_empty().as_sum(column.expr())))
117 }
118
119 pub fn select_column(&self, field: &str) -> Option<Expression<T::Value>>
134 where
135 T::Column<T::AnyType>: Expressive<T::Value>,
136 T::Select: Expressive<T::Value>,
137 {
138 let expr = self.get_column_expr(field)?;
139 let mut select = self.select_empty();
140 select.clear_fields();
141 select.clear_order_by();
142 select.add_expression(expr);
143 Some(select.expr())
144 }
145}
146
147impl<T, E, V, C, S> Table<T, E>
152where
153 T: SelectableDataSource<V, C, Select = S>
154 + TableSource<Value = V, Condition = C, Source = SelectSource<S>>,
155 V: Clone + Send + Sync + 'static + From<String>,
156 C: Clone + Send + Sync + 'static,
157 S: Expressive<V> + Clone,
158 E: Entity<V>,
159{
160 pub fn from_select(data_source: T, alias: impl Into<String>, select: S) -> Self {
163 let alias = alias.into();
164 let mut table = Table::new(alias.clone(), data_source);
165 table.source = SelectSource::query(select, alias);
166 table
167 }
168
169 pub fn derive_from<E2: Entity<V> + 'static>(
178 source: &Table<T, E2>,
179 alias: impl Into<String>,
180 modifier: impl FnOnce(S) -> S,
181 columns: &[&str],
182 relations: &[&str],
183 ) -> Self
184 where
185 T: 'static,
186 E: 'static,
187 {
188 let alias = alias.into();
189 let select = modifier(source.select());
190 let mut table = Table::new(alias.clone(), source.data_source().clone());
191 table.source = SelectSource::query(select, alias);
192 table.copy_columns_from(source, Some(columns));
193 table.copy_relations_from(source, Some(relations));
194 table.id_field = source.id_field.clone();
195 table.title_field = source.title_field.clone();
196 table.title_fields = source.title_fields.clone();
197 table
198 }
199}
200
201impl<T, E> Table<T, E>
203where
204 T: SelectableDataSource<serde_json::Value, T::Condition>
205 + TableSource<Value = serde_json::Value>
206 + vantage_expressions::traits::datasource::ExprDataSource<serde_json::Value>,
207 T::Source: SelectSeed<T::Select, serde_json::Value, T::Condition>,
208 T::Value: From<String>,
209 E: Entity<serde_json::Value>,
210{
211 pub async fn get_count_via_query(&self) -> Result<i64> {
213 let count_query = self.get_count_query();
214 let result = self.data_source.execute(&count_query).await?;
215
216 let result = match result.as_array().map(Vec::as_slice) {
219 Some([single]) => single,
220 _ => &result,
221 };
222
223 if let Some(count) = result.get("count").and_then(|v| v.as_i64()) {
227 Ok(count)
228 } else if let Some(count) = result.as_i64() {
229 Ok(count)
230 } else {
231 Err(vantage_core::util::error::vantage_error!(
232 "count query returned an unexpected result shape: {result}"
233 ))
234 }
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241 use crate::mocks::mock_table_source::MockTableSource;
242 use serde_json::json;
243 use vantage_expressions::mocks::datasource::MockSelectableDataSource;
244 use vantage_expressions::traits::datasource::ExprDataSource;
245
246 #[tokio::test]
247 async fn test_selectable_functionality() {
248 let mock_select_source = MockSelectableDataSource::new(json!([
249 {"id": "1", "name": "Alice", "age": 30},
250 {"id": "2", "name": "Bob", "age": 25}
251 ]));
252
253 let mock_query_source = vantage_expressions::mocks::mock_builder::new()
254 .on_exact_select("(SELECT COUNT(*) FROM \"users\")", json!(42));
255
256 let table = MockTableSource::new()
257 .with_data(
258 "users",
259 vec![
260 json!({"id": "1", "name": "Alice", "age": 30}),
261 json!({"id": "2", "name": "Bob", "age": 25}),
262 ],
263 )
264 .await
265 .with_select_source(mock_select_source)
266 .with_query_source(mock_query_source);
267 let table = Table::<_, vantage_types::EmptyEntity>::new("users", table);
268
269 let select = table.select();
271 assert_eq!(select.source(), Some("users"));
272
273 let query_expr: vantage_expressions::Expression<serde_json::Value> = select.into();
275 assert_eq!(query_expr.preview(), "SELECT * FROM users");
276
277 let count_query = table.get_count_query();
279 assert_eq!(count_query.preview(), "(SELECT COUNT(*) FROM \"users\")");
280
281 let count = table.get_count_via_query().await.unwrap();
289 assert_eq!(count, 42);
290 }
291
292 async fn count_table_returning(
293 count_result: serde_json::Value,
294 ) -> Table<MockTableSource, vantage_types::EmptyEntity> {
295 let mock_select_source = MockSelectableDataSource::new(json!([]));
296 let mock_query_source = vantage_expressions::mocks::mock_builder::new()
297 .on_exact_select("(SELECT COUNT(*) FROM \"users\")", count_result);
298 let source = MockTableSource::new()
299 .with_select_source(mock_select_source)
300 .with_query_source(mock_query_source);
301 Table::<_, vantage_types::EmptyEntity>::new("users", source)
302 }
303
304 #[tokio::test]
305 async fn test_count_unwraps_single_element_array() {
306 let table = count_table_returning(json!([{"count": 7}])).await;
308 assert_eq!(table.get_count_via_query().await.unwrap(), 7);
309 }
310
311 #[tokio::test]
312 async fn test_count_errors_on_unexpected_shape() {
313 let table = count_table_returning(json!({"total": 5})).await;
315 assert!(table.get_count_via_query().await.is_err());
316 }
317
318 #[tokio::test]
319 #[should_panic(expected = "MockTableSource select source not set")]
320 async fn test_panics_without_select_source() {
321 let table = Table::<_, vantage_types::EmptyEntity>::new("users", MockTableSource::new());
322 let _select = table.select();
323 }
324
325 #[tokio::test]
326 #[should_panic(expected = "MockTableSource query source not set")]
327 async fn test_panics_without_query_source() {
328 let table = Table::<_, vantage_types::EmptyEntity>::new("users", MockTableSource::new());
329 let query = table.data_source().expr("SELECT COUNT(*)", vec![]);
330 let _result = table.data_source().execute(&query).await;
331 }
332}