1use async_trait::async_trait;
2use ciborium::Value as CborValue;
3use indexmap::IndexMap;
4use vantage_core::error;
5use vantage_dataset::traits::{ReadableValueSet, 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<CborValue>>(table: &Table<RestApi, E>) -> Option<String> {
22 table.id_field().map(|col| col.name().to_string())
23}
24
25impl ExprDataSource<CborValue> for RestApi {
26 async fn execute(&self, expr: &Expression<CborValue>) -> vantage_core::Result<CborValue> {
27 if expr.parameters.is_empty() {
28 Ok(CborValue::Text(expr.template.clone()))
29 } else {
30 Ok(CborValue::Null)
31 }
32 }
33
34 fn defer(&self, expr: Expression<CborValue>) -> DeferredFn<CborValue> {
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 = CborValue;
56 type Value = CborValue;
57 type Id = String;
58 type Condition = vantage_expressions::Expression<Self::Value>;
59
60 fn eq_condition(field: &str, value: &str) -> Result<Self::Condition> {
66 Ok(crate::eq_condition(field, value.to_string()))
67 }
68
69 fn create_column<Type: ColumnType>(&self, name: &str) -> Self::Column<Type> {
70 Column::new(name)
71 }
72
73 fn to_any_column<Type: ColumnType>(
74 &self,
75 column: Self::Column<Type>,
76 ) -> Self::Column<Self::AnyType> {
77 Column::from_column(column)
78 }
79
80 fn convert_any_column<Type: ColumnType>(
81 &self,
82 any_column: Self::Column<Self::AnyType>,
83 ) -> Option<Self::Column<Type>> {
84 Some(Column::from_column(any_column))
85 }
86
87 fn expr(
88 &self,
89 template: impl Into<String>,
90 parameters: Vec<ExpressiveEnum<Self::Value>>,
91 ) -> Expression<Self::Value> {
92 Expression::new(template, parameters)
93 }
94
95 fn search_table_condition<E>(
96 &self,
97 _table: &Table<Self, E>,
98 search_value: &str,
99 ) -> Expression<Self::Value>
100 where
101 E: Entity<Self::Value>,
102 {
103 Expression::new(format!("SEARCH '{}'", search_value), vec![])
104 }
105
106 async fn list_table_values<E>(
107 &self,
108 table: &Table<Self, E>,
109 ) -> Result<IndexMap<Self::Id, Record<Self::Value>>>
110 where
111 E: Entity<Self::Value>,
112 Self: Sized,
113 {
114 self.fetch_records(
115 table.table_name(),
116 id_field_name(table).as_deref(),
117 table.pagination(),
118 table.conditions(),
119 )
120 .await
121 }
122
123 async fn get_table_value<E>(
124 &self,
125 table: &Table<Self, E>,
126 id: &Self::Id,
127 ) -> Result<Option<Record<Self::Value>>>
128 where
129 E: Entity<Self::Value>,
130 Self: Sized,
131 {
132 let records = self
133 .fetch_records(
134 table.table_name(),
135 id_field_name(table).as_deref(),
136 table.pagination(),
137 table.conditions(),
138 )
139 .await?;
140 Ok(records.get(id).cloned())
141 }
142
143 async fn get_table_some_value<E>(
144 &self,
145 table: &Table<Self, E>,
146 ) -> Result<Option<(Self::Id, Record<Self::Value>)>>
147 where
148 E: Entity<Self::Value>,
149 Self: Sized,
150 {
151 let records = self
152 .fetch_records(
153 table.table_name(),
154 id_field_name(table).as_deref(),
155 table.pagination(),
156 table.conditions(),
157 )
158 .await?;
159 Ok(records.into_iter().next())
160 }
161
162 async fn get_table_count<E>(&self, table: &Table<Self, E>) -> Result<i64>
163 where
164 E: Entity<Self::Value>,
165 Self: Sized,
166 {
167 let records = self
168 .fetch_records(
169 table.table_name(),
170 id_field_name(table).as_deref(),
171 table.pagination(),
172 table.conditions(),
173 )
174 .await?;
175 Ok(records.len() as i64)
176 }
177
178 async fn get_table_sum<E>(
179 &self,
180 _table: &Table<Self, E>,
181 _column: &Self::Column<Self::AnyType>,
182 ) -> Result<Self::Value>
183 where
184 E: Entity<Self::Value>,
185 Self: Sized,
186 {
187 Err(error!("Sum not implemented for API backend"))
188 }
189
190 async fn get_table_max<E>(
191 &self,
192 _table: &Table<Self, E>,
193 _column: &Self::Column<Self::AnyType>,
194 ) -> Result<Self::Value>
195 where
196 E: Entity<Self::Value>,
197 Self: Sized,
198 {
199 Err(error!("Max not implemented for API backend"))
200 }
201
202 async fn get_table_min<E>(
203 &self,
204 _table: &Table<Self, E>,
205 _column: &Self::Column<Self::AnyType>,
206 ) -> Result<Self::Value>
207 where
208 E: Entity<Self::Value>,
209 Self: Sized,
210 {
211 Err(error!("Min not implemented for API backend"))
212 }
213
214 async fn insert_table_value<E>(
215 &self,
216 _table: &Table<Self, E>,
217 _id: &Self::Id,
218 _record: &Record<Self::Value>,
219 ) -> Result<Record<Self::Value>>
220 where
221 E: Entity<Self::Value>,
222 Self: Sized,
223 {
224 Err(error!("REST API is a read-only data source"))
225 }
226
227 async fn replace_table_value<E>(
228 &self,
229 _table: &Table<Self, E>,
230 _id: &Self::Id,
231 _record: &Record<Self::Value>,
232 ) -> Result<Record<Self::Value>>
233 where
234 E: Entity<Self::Value>,
235 Self: Sized,
236 {
237 Err(error!("REST API is a read-only data source"))
238 }
239
240 async fn patch_table_value<E>(
241 &self,
242 _table: &Table<Self, E>,
243 _id: &Self::Id,
244 _partial: &Record<Self::Value>,
245 ) -> Result<Record<Self::Value>>
246 where
247 E: Entity<Self::Value>,
248 Self: Sized,
249 {
250 Err(error!("REST API is a read-only data source"))
251 }
252
253 async fn delete_table_value<E>(&self, _table: &Table<Self, E>, _id: &Self::Id) -> Result<()>
254 where
255 E: Entity<Self::Value>,
256 Self: Sized,
257 {
258 Err(error!("REST API is a read-only data source"))
259 }
260
261 async fn delete_table_all_values<E>(&self, _table: &Table<Self, E>) -> Result<()>
262 where
263 E: Entity<Self::Value>,
264 Self: Sized,
265 {
266 Err(error!("REST API is a read-only data source"))
267 }
268
269 async fn insert_table_return_id_value<E>(
270 &self,
271 _table: &Table<Self, E>,
272 _record: &Record<Self::Value>,
273 ) -> Result<Self::Id>
274 where
275 E: Entity<Self::Value>,
276 Self: Sized,
277 {
278 Err(error!("REST API is a read-only data source"))
279 }
280
281 fn related_in_condition<SourceE: Entity<Self::Value> + 'static>(
297 &self,
298 target_field: &str,
299 source_table: &Table<Self, SourceE>,
300 source_column: &str,
301 ) -> Self::Condition
302 where
303 Self: Sized,
304 {
305 for cond in source_table.conditions() {
306 if let Some((field, value)) = crate::condition_to_query_param(cond)
307 && field == source_column
308 {
309 let cbor_value: CborValue = if let Ok(i) = value.parse::<i64>() {
310 CborValue::Integer(i.into())
311 } else if let Ok(f) = value.parse::<f64>() {
312 CborValue::Float(f)
313 } else {
314 CborValue::Text(value)
315 };
316 return crate::eq_condition(target_field, cbor_value);
317 }
318 }
319
320 let parent = source_table.clone();
324 let column = source_column.to_string();
325 let parent_name = source_table.table_name().to_string();
326 let deferred = DeferredFn::new(move || {
327 let parent = parent.clone();
328 let column = column.clone();
329 let parent_name = parent_name.clone();
330 Box::pin(async move {
331 let records = parent.list_values().await?;
332 let value = records
333 .values()
334 .next()
335 .and_then(|r| r.get(&column))
336 .cloned()
337 .ok_or_else(|| {
338 error!(
339 "Deferred FK resolve: parent yielded no row or column missing",
340 table = parent_name,
341 column = column
342 )
343 })?;
344 Ok(ExpressiveEnum::Scalar(value))
345 })
346 });
347
348 Expression::new(
349 "{} = {}",
350 vec![
351 ExpressiveEnum::Nested(Expression::new(target_field.to_string(), vec![])),
352 ExpressiveEnum::Nested(Expression::new(
353 "{}",
354 vec![ExpressiveEnum::Deferred(deferred)],
355 )),
356 ],
357 )
358 }
359
360 fn column_table_values_expr<'a, E, Type: ColumnType>(
361 &'a self,
362 _table: &Table<Self, E>,
363 _column: &Self::Column<Type>,
364 ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>>
365 where
366 E: Entity<Self::Value> + 'static,
367 Self: Sized,
368 {
369 unimplemented!("column_table_values_expr not yet supported for REST API")
370 }
371}