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
20fn 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}