Skip to main content

vantage_api_client/
table_source.rs

1use async_trait::async_trait;
2use indexmap::IndexMap;
3use serde_json::Value;
4use vantage_core::error;
5use vantage_dataset::traits::Result;
6use vantage_expressions::Expression;
7use vantage_expressions::traits::associated_expressions::AssociatedExpression;
8use vantage_expressions::traits::datasource::DataSource;
9use vantage_expressions::traits::expressive::ExpressiveEnum;
10use vantage_table::column::core::{Column, ColumnType};
11use vantage_table::table::Table;
12use vantage_table::traits::table_source::TableSource;
13use vantage_types::{Entity, Record};
14
15use vantage_expressions::traits::datasource::ExprDataSource;
16use vantage_expressions::traits::expressive::DeferredFn;
17
18use crate::RestApi;
19
20/// Extract the id field name from a table's column flags.
21fn id_field_name<E: Entity<Value>>(table: &Table<RestApi, E>) -> Option<String> {
22    table.id_field().map(|col| col.name().to_string())
23}
24
25impl ExprDataSource<Value> for RestApi {
26    async fn execute(&self, expr: &Expression<Value>) -> vantage_core::Result<Value> {
27        if expr.parameters.is_empty() {
28            Ok(Value::String(expr.template.clone()))
29        } else {
30            Ok(Value::Null)
31        }
32    }
33
34    fn defer(&self, expr: Expression<Value>) -> DeferredFn<Value> {
35        let api = self.clone();
36        DeferredFn::new(move || {
37            let api = api.clone();
38            let expr = expr.clone();
39            Box::pin(async move {
40                let result = api.execute(&expr).await?;
41                Ok(ExpressiveEnum::Scalar(result))
42            })
43        })
44    }
45}
46
47impl DataSource for RestApi {}
48
49#[async_trait]
50impl TableSource for RestApi {
51    type Column<Type>
52        = Column<Type>
53    where
54        Type: ColumnType;
55    type AnyType = Value;
56    type Value = Value;
57    type Id = String;
58    type Condition = vantage_expressions::Expression<Self::Value>;
59
60    fn create_column<Type: ColumnType>(&self, name: &str) -> Self::Column<Type> {
61        Column::new(name)
62    }
63
64    fn to_any_column<Type: ColumnType>(
65        &self,
66        column: Self::Column<Type>,
67    ) -> Self::Column<Self::AnyType> {
68        Column::from_column(column)
69    }
70
71    fn convert_any_column<Type: ColumnType>(
72        &self,
73        any_column: Self::Column<Self::AnyType>,
74    ) -> Option<Self::Column<Type>> {
75        Some(Column::from_column(any_column))
76    }
77
78    fn expr(
79        &self,
80        template: impl Into<String>,
81        parameters: Vec<ExpressiveEnum<Self::Value>>,
82    ) -> Expression<Self::Value> {
83        Expression::new(template, parameters)
84    }
85
86    fn search_table_condition<E>(
87        &self,
88        _table: &Table<Self, E>,
89        search_value: &str,
90    ) -> Expression<Self::Value>
91    where
92        E: Entity<Self::Value>,
93    {
94        Expression::new(format!("SEARCH '{}'", search_value), vec![])
95    }
96
97    async fn list_table_values<E>(
98        &self,
99        table: &Table<Self, E>,
100    ) -> Result<IndexMap<Self::Id, Record<Self::Value>>>
101    where
102        E: Entity<Self::Value>,
103        Self: Sized,
104    {
105        self.fetch_records(
106            table.table_name(),
107            id_field_name(table).as_deref(),
108            table.pagination(),
109            table.conditions(),
110        )
111        .await
112    }
113
114    async fn get_table_value<E>(
115        &self,
116        table: &Table<Self, E>,
117        id: &Self::Id,
118    ) -> Result<Option<Record<Self::Value>>>
119    where
120        E: Entity<Self::Value>,
121        Self: Sized,
122    {
123        let records = self
124            .fetch_records(
125                table.table_name(),
126                id_field_name(table).as_deref(),
127                table.pagination(),
128                table.conditions(),
129            )
130            .await?;
131        Ok(records.get(id).cloned())
132    }
133
134    async fn get_table_some_value<E>(
135        &self,
136        table: &Table<Self, E>,
137    ) -> Result<Option<(Self::Id, Record<Self::Value>)>>
138    where
139        E: Entity<Self::Value>,
140        Self: Sized,
141    {
142        let records = self
143            .fetch_records(
144                table.table_name(),
145                id_field_name(table).as_deref(),
146                table.pagination(),
147                table.conditions(),
148            )
149            .await?;
150        Ok(records.into_iter().next())
151    }
152
153    async fn get_table_count<E>(&self, table: &Table<Self, E>) -> Result<i64>
154    where
155        E: Entity<Self::Value>,
156        Self: Sized,
157    {
158        let records = self
159            .fetch_records(
160                table.table_name(),
161                id_field_name(table).as_deref(),
162                table.pagination(),
163                table.conditions(),
164            )
165            .await?;
166        Ok(records.len() as i64)
167    }
168
169    async fn get_table_sum<E>(
170        &self,
171        _table: &Table<Self, E>,
172        _column: &Self::Column<Self::AnyType>,
173    ) -> Result<Self::Value>
174    where
175        E: Entity<Self::Value>,
176        Self: Sized,
177    {
178        Err(error!("Sum not implemented for API backend"))
179    }
180
181    async fn get_table_max<E>(
182        &self,
183        _table: &Table<Self, E>,
184        _column: &Self::Column<Self::AnyType>,
185    ) -> Result<Self::Value>
186    where
187        E: Entity<Self::Value>,
188        Self: Sized,
189    {
190        Err(error!("Max not implemented for API backend"))
191    }
192
193    async fn get_table_min<E>(
194        &self,
195        _table: &Table<Self, E>,
196        _column: &Self::Column<Self::AnyType>,
197    ) -> Result<Self::Value>
198    where
199        E: Entity<Self::Value>,
200        Self: Sized,
201    {
202        Err(error!("Min not implemented for API backend"))
203    }
204
205    async fn insert_table_value<E>(
206        &self,
207        _table: &Table<Self, E>,
208        _id: &Self::Id,
209        _record: &Record<Self::Value>,
210    ) -> Result<Record<Self::Value>>
211    where
212        E: Entity<Self::Value>,
213        Self: Sized,
214    {
215        Err(error!("REST API is a read-only data source"))
216    }
217
218    async fn replace_table_value<E>(
219        &self,
220        _table: &Table<Self, E>,
221        _id: &Self::Id,
222        _record: &Record<Self::Value>,
223    ) -> Result<Record<Self::Value>>
224    where
225        E: Entity<Self::Value>,
226        Self: Sized,
227    {
228        Err(error!("REST API is a read-only data source"))
229    }
230
231    async fn patch_table_value<E>(
232        &self,
233        _table: &Table<Self, E>,
234        _id: &Self::Id,
235        _partial: &Record<Self::Value>,
236    ) -> Result<Record<Self::Value>>
237    where
238        E: Entity<Self::Value>,
239        Self: Sized,
240    {
241        Err(error!("REST API is a read-only data source"))
242    }
243
244    async fn delete_table_value<E>(&self, _table: &Table<Self, E>, _id: &Self::Id) -> Result<()>
245    where
246        E: Entity<Self::Value>,
247        Self: Sized,
248    {
249        Err(error!("REST API is a read-only data source"))
250    }
251
252    async fn delete_table_all_values<E>(&self, _table: &Table<Self, E>) -> Result<()>
253    where
254        E: Entity<Self::Value>,
255        Self: Sized,
256    {
257        Err(error!("REST API is a read-only data source"))
258    }
259
260    async fn insert_table_return_id_value<E>(
261        &self,
262        _table: &Table<Self, E>,
263        _record: &Record<Self::Value>,
264    ) -> Result<Self::Id>
265    where
266        E: Entity<Self::Value>,
267        Self: Sized,
268    {
269        Err(error!("REST API is a read-only data source"))
270    }
271
272    fn related_in_condition<SourceE: Entity<Self::Value> + 'static>(
273        &self,
274        _target_field: &str,
275        _source_table: &Table<Self, SourceE>,
276        _source_column: &str,
277    ) -> Self::Condition
278    where
279        Self: Sized,
280    {
281        unimplemented!("related_in_condition not yet supported for REST API")
282    }
283
284    fn column_table_values_expr<'a, E, Type: ColumnType>(
285        &'a self,
286        _table: &Table<Self, E>,
287        _column: &Self::Column<Type>,
288    ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>>
289    where
290        E: Entity<Self::Value> + 'static,
291        Self: Sized,
292    {
293        unimplemented!("column_table_values_expr not yet supported for REST API")
294    }
295}