1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use async_trait::async_trait;
use indexmap::IndexMap;
use vantage_core::Result;
use vantage_dataset::prelude::{ReadableValueSet, WritableValueSet};
use vantage_expressions::AnyExpression;
use crate::{any::AnyTable, conditions::ConditionHandle, pagination::Pagination};
/// Dyn-safe trait for table operations.
#[async_trait]
pub trait TableLike: ReadableValueSet + WritableValueSet + Send + Sync {
fn table_name(&self) -> &str;
fn table_alias(&self) -> &str;
fn column_names(&self) -> Vec<String>;
/// Name of the column flagged as the id field, if any.
fn id_field_name(&self) -> Option<String> {
None
}
/// Names of columns flagged as `TitleField`.
fn title_field_names(&self) -> Vec<String> {
Vec::new()
}
/// Map of column name -> original Rust type name. Backends that
/// preserve type metadata (e.g. `Column::get_type()`) override this
/// so generic UIs can drive type-aware rendering without poking at
/// concrete column types.
fn column_types(&self) -> IndexMap<String, &'static str> {
IndexMap::new()
}
/// Names of relations traversable via [`get_ref`].
fn get_ref_names(&self) -> Vec<String> {
Vec::new()
}
/// Add a condition to this table using a type-erased expression
/// The expression must be of type T::Expr for the underlying table's TableSource
fn add_condition(&mut self, condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()>;
/// Add a permanent equality condition expressed as raw strings.
///
/// Generic CLIs (and other type-erased callers) work with
/// `field=value` text and cannot reach into `T::Condition`. Each
/// backend that supports textual eq filtering overrides this; the
/// default returns an error.
fn add_condition_eq(&mut self, field: &str, value: &str) -> Result<()> {
let _ = (field, value);
Err(vantage_core::error!(
"add_condition_eq not supported on this TableLike"
))
}
/// Add a temporary condition using AnyExpression that can be removed later
fn temp_add_condition(&mut self, condition: AnyExpression) -> Result<ConditionHandle>;
/// Remove a temporary condition by its handle
fn temp_remove_condition(&mut self, handle: ConditionHandle) -> Result<()>;
/// Create a search expression for this table
fn search_expression(&self, search_value: &str) -> Result<AnyExpression>;
/// Clone into a Box for object-safe cloning
fn clone_box(&self) -> Box<dyn TableLike<Value = Self::Value, Id = Self::Id>>;
/// Convert to Any for downcasting
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
fn as_any_ref(&self) -> &dyn std::any::Any;
/// Set pagination for this table
fn set_pagination(&mut self, pagination: Option<Pagination>);
/// Get pagination for this table
fn get_pagination(&self) -> Option<&Pagination>;
/// Get count of records in the table
async fn get_count(&self) -> Result<i64>;
/// Traverse a named reference and return the related table as `AnyTable`.
///
/// Default impl returns an error so wrappers without ref support compile
/// unchanged. `Table<T, E>` overrides this to delegate to its inherent
/// `get_ref`; `AnyTable`, `CborAdapter` and `LiveTable` override to forward
/// through to the underlying table that holds the refs.
fn get_ref(&self, _relation: &str) -> Result<AnyTable> {
Err(vantage_core::error!(
"get_ref not supported on this TableLike"
))
}
}