vantage_table/table/impls/
selectable.rs1use std::sync::Arc;
2
3use vantage_core::{Result, error};
4use vantage_expressions::traits::selectable::Selectable;
5use vantage_expressions::{Expression, Expressive, SelectableDataSource, expr_any};
6use vantage_types::{EmptyEntity, Entity};
7
8use crate::{
9 column::core::ColumnType,
10 source::{SelectSeed, SelectSource},
11 table::Table,
12 traits::column_like::ColumnLike,
13 traits::table_source::TableSource,
14};
15
16impl<T, E> Table<T, E>
17where
18 T: SelectableDataSource<T::Value, T::Condition> + TableSource,
19 T::Source: SelectSeed<T::Select, T::Value, T::Condition>,
20 T::Value: From<String>, E: Entity<T::Value>,
22{
23 pub fn select_empty(&self) -> T::Select {
27 let mut select = self.data_source.select();
28 self.source.seed(&mut select);
29
30 for condition in self.conditions.values() {
31 select.add_where_condition(condition.clone());
32 }
33
34 for (expr, direction) in self.order_by.values() {
35 let order = match direction {
36 crate::sorting::SortDirection::Ascending => vantage_expressions::Order::Asc,
37 crate::sorting::SortDirection::Descending => vantage_expressions::Order::Desc,
38 };
39 select.add_order_by(expr.clone(), order);
40 }
41
42 if let Some(pagination) = &self.pagination {
43 select.set_limit(Some(pagination.limit()), Some(pagination.skip()));
44 }
45
46 select
47 }
48
49 pub fn select(&self) -> T::Select {
51 let mut select = self.select_empty();
52
53 for column in self.columns.values() {
54 if self.lazy_expressions.contains_key(column.name()) {
59 continue;
60 }
61 if !self.is_active(column.name()) {
64 continue;
65 }
66 if let Some(expr_fn) = self.expressions.get(column.name()) {
67 let expr = expr_fn(self.as_entity_erased());
68 self.data_source.add_select_column(
69 &mut select,
70 expr_any!("({})", (expr)),
71 Some(column.name()),
72 );
73 } else if let Some(alias) = column.alias() {
74 let expr = self.data_source.expr(column.name(), vec![]);
75 self.data_source
76 .add_select_column(&mut select, expr, Some(alias));
77 } else {
78 select.add_field(column.name());
79 }
80 }
81
82 for (name, expr_fn) in &self.expressions {
83 if !self.columns.contains_key(name) && self.is_active(name) {
84 let expr = expr_fn(self.as_entity_erased());
85 self.data_source.add_select_column(
86 &mut select,
87 expr_any!("({})", (expr)),
88 Some(name),
89 );
90 }
91 }
92
93 select
94 }
95 pub async fn get_count(&self) -> Result<i64> {
97 self.check_read().await?;
98 self.data_source.get_table_count(self).await
99 }
100
101 pub async fn get_sum(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
103 self.check_read().await?;
104 self.data_source.get_table_sum(self, column).await
105 }
106
107 pub async fn get_max(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
109 self.check_read().await?;
110 self.data_source.get_table_max(self, column).await
111 }
112
113 pub async fn get_min(&self, column: &T::Column<T::AnyType>) -> Result<T::Value> {
115 self.check_read().await?;
116 self.data_source.get_table_min(self, column).await
117 }
118
119 pub fn get_count_query(&self) -> Expression<T::Value> {
122 expr_any!("({})", (self.select_empty().as_count()))
123 }
124
125 pub fn get_sum_query<Type>(&self, column: &T::Column<Type>) -> Expression<T::Value>
128 where
129 Type: ColumnType,
130 T::Column<Type>: Expressive<T::Value>,
131 {
132 expr_any!("({})", (self.select_empty().as_sum(column.expr())))
133 }
134
135 pub fn select_column(&self, field: &str) -> Option<Expression<T::Value>>
150 where
151 T::Column<T::AnyType>: Expressive<T::Value>,
152 T::Select: Expressive<T::Value>,
153 {
154 Some(self.select_expression(self.get_column_expr(field)?))
155 }
156
157 pub fn select_expression(&self, expr: Expression<T::Value>) -> Expression<T::Value>
164 where
165 T::Select: Expressive<T::Value>,
166 {
167 let mut select = self.select_empty();
168 select.clear_fields();
169 select.clear_order_by();
170 select.add_expression(expr);
171 select.expr()
172 }
173
174 fn is_active(&self, name: &str) -> bool {
178 match &self.active_columns {
179 None => true,
180 Some(set) => set.contains(name) || self.id_field.as_deref() == Some(name),
181 }
182 }
183
184 pub fn with_active_columns(mut self, cols: &[&str]) -> Result<Self>
208 where
209 T: 'static,
210 E: 'static,
211 T::Column<T::AnyType>: Expressive<T::Value>,
212 T::Select: Expressive<T::Value>,
213 {
214 for &col in cols {
215 let parts: Vec<&str> = col.split('.').collect();
216 if parts.iter().any(|p| p.is_empty()) {
217 return Err(error!("invalid active column name", column = col));
218 }
219
220 if parts.len() >= 2 {
221 self.import_dotted_column(col)?;
222 self.active_columns
223 .get_or_insert_with(Default::default)
224 .insert(col.to_string());
225 } else {
226 if !self.columns.contains_key(col) && !self.expressions.contains_key(col) {
230 return Err(error!("unknown active column", column = col));
231 }
232 self.active_columns
233 .get_or_insert_with(Default::default)
234 .insert(col.to_string());
235 }
236 }
237 Ok(self)
238 }
239
240 pub fn with_imported_column(mut self, col: &str) -> Result<Self>
246 where
247 T: 'static,
248 E: 'static,
249 T::Column<T::AnyType>: Expressive<T::Value>,
250 T::Select: Expressive<T::Value>,
251 {
252 self.import_dotted_column(col)?;
253 Ok(self)
254 }
255
256 pub fn add_imported_column(&mut self, col: &str) -> Result<()>
258 where
259 T: 'static,
260 E: 'static,
261 T::Column<T::AnyType>: Expressive<T::Value>,
262 T::Select: Expressive<T::Value>,
263 {
264 self.import_dotted_column(col)
265 }
266
267 fn import_dotted_column(&mut self, col: &str) -> Result<()>
273 where
274 T: 'static,
275 E: 'static,
276 T::Column<T::AnyType>: Expressive<T::Value>,
277 T::Select: Expressive<T::Value>,
278 {
279 let parts: Vec<&str> = col.split('.').collect();
280 if parts.len() < 2 || parts.iter().any(|p| p.is_empty()) {
281 return Err(error!("invalid dotted column name", column = col));
282 }
283 let column = parts[parts.len() - 1];
284 let hops = &parts[..parts.len() - 1];
285
286 if !self.data_source().supports_traversal() {
287 return Err(error!(
288 "backend does not support implicit-reference traversal in columns",
289 column = col
290 ));
291 }
292
293 let (target, fk_hops) = self.resolve_has_one_target(hops)?;
294 if !target.columns().contains_key(column) {
295 return Err(error!(
296 "implicit reference target has no such column",
297 column = column
298 ));
299 }
300
301 let fk_refs: Vec<&str> = fk_hops.iter().map(String::as_str).collect();
309 let expr = match self.data_source().traversal_path_expr(&fk_refs, column) {
310 Some(e) => e,
311 None => self.traverse_rest_generic(hops, column)?,
312 };
313
314 let dotted = col.to_string();
315 if !self.columns.contains_key(&dotted) {
316 let column_def = self.data_source.create_column::<T::AnyType>(&dotted);
317 self.add_column(column_def);
318 }
319 let wrapped: crate::table::base::ExpressionFn<T> = Arc::new(move |_| expr.clone());
320 self.expressions.insert(dotted.clone(), wrapped);
321 self.imported_columns.insert(dotted.clone());
322 Ok(())
323 }
324
325 fn traverse_rest_generic(&self, hops: &[&str], column: &str) -> Result<Expression<T::Value>>
331 where
332 T: 'static,
333 E: 'static,
334 T::Column<T::AnyType>: Expressive<T::Value>,
335 T::Select: Expressive<T::Value>,
336 {
337 match hops.split_first() {
338 None => self.get_column_expr(column).ok_or_else(|| {
339 error!(
340 "implicit reference target has no such column",
341 column = column
342 )
343 }),
344 Some((head, tail)) => {
345 let target: Table<T, EmptyEntity> = self.get_subquery_erased(head)?;
346 let inner = target.traverse_rest_generic(tail, column)?;
347 let inner = if tail.is_empty() {
351 inner
352 } else {
353 expr_any!("({})", (inner))
354 };
355 Ok(target.select_expression(inner))
356 }
357 }
358 }
359
360 fn resolve_has_one_target(&self, hops: &[&str]) -> Result<(Table<T, EmptyEntity>, Vec<String>)>
366 where
367 T: 'static,
368 E: 'static,
369 {
370 let (head, tail) = hops
371 .split_first()
372 .ok_or_else(|| error!("empty implicit reference path"))?;
373 if self.ref_cardinality(head)? != vantage_vista::ReferenceKind::HasOne {
374 return Err(error!(
375 "implicit reference hop must traverse a has_one relation",
376 relation = *head
377 ));
378 }
379 let fk = self.ref_foreign_key(head)?;
380 let target: Table<T, EmptyEntity> = self.get_ref_target_erased(head)?;
381 if tail.is_empty() {
382 Ok((target, vec![fk]))
383 } else {
384 let (final_target, mut fks) = target.resolve_has_one_target(tail)?;
385 fks.insert(0, fk);
386 Ok((final_target, fks))
387 }
388 }
389}
390
391impl<T, E, V, C, S> Table<T, E>
396where
397 T: SelectableDataSource<V, C, Select = S>
398 + TableSource<Value = V, Condition = C, Source = SelectSource<S>>,
399 V: Clone + Send + Sync + 'static + From<String>,
400 C: Clone + Send + Sync + 'static,
401 S: Expressive<V> + Clone,
402 E: Entity<V>,
403{
404 pub fn from_select(data_source: T, alias: impl Into<String>, select: S) -> Self {
407 let alias = alias.into();
408 let mut table = Table::new(alias.clone(), data_source);
409 table.source = SelectSource::query(select, alias);
410 table
411 }
412
413 pub fn derive_from<E2: Entity<V> + 'static>(
427 source: &Table<T, E2>,
428 alias: impl Into<String>,
429 modifier: impl FnOnce(S) -> S,
430 columns: &[&str],
431 relations: &[&str],
432 ) -> Self
433 where
434 T: 'static,
435 E: 'static,
436 {
437 let alias = alias.into();
438 let select = modifier(source.select());
439 let mut table = Table::new(alias.clone(), source.data_source().clone());
440 table.source = SelectSource::query(select, alias);
441 table.copy_columns_from(source, Some(columns));
442 table.copy_relations_from(source, Some(relations));
443 table.id_field = source.id_field.clone();
444 table.title_field = source.title_field.clone();
445 table.title_fields = source.title_fields.clone();
446 table
447 }
448}
449
450impl<T, E> Table<T, E>
451where
452 T: SelectableDataSource<serde_json::Value, T::Condition>
453 + TableSource<Value = serde_json::Value>
454 + vantage_expressions::traits::datasource::ExprDataSource<serde_json::Value>,
455 T::Source: SelectSeed<T::Select, serde_json::Value, T::Condition>,
456 T::Value: From<String>,
457 E: Entity<serde_json::Value>,
458{
459 pub async fn get_count_via_query(&self) -> Result<i64> {
461 self.check_read().await?;
462 let count_query = self.get_count_query();
463 let result = self.data_source.execute(&count_query).await?;
464
465 let result = match result.as_array().map(Vec::as_slice) {
468 Some([single]) => single,
469 _ => &result,
470 };
471
472 if let Some(count) = result.get("count").and_then(|v| v.as_i64()) {
475 Ok(count)
476 } else if let Some(count) = result.as_i64() {
477 Ok(count)
478 } else {
479 Err(vantage_core::error!(
480 "count query returned an unexpected result shape",
481 result = result
482 ))
483 }
484 }
485}