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