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(table.table_name(), id_field_name(table).as_deref())
106 .await
107 }
108
109 async fn get_table_value<E>(
110 &self,
111 table: &Table<Self, E>,
112 id: &Self::Id,
113 ) -> Result<Option<Record<Self::Value>>>
114 where
115 E: Entity<Self::Value>,
116 Self: Sized,
117 {
118 let records = self
119 .fetch_records(table.table_name(), id_field_name(table).as_deref())
120 .await?;
121 Ok(records.get(id).cloned())
122 }
123
124 async fn get_table_some_value<E>(
125 &self,
126 table: &Table<Self, E>,
127 ) -> Result<Option<(Self::Id, Record<Self::Value>)>>
128 where
129 E: Entity<Self::Value>,
130 Self: Sized,
131 {
132 let records = self
133 .fetch_records(table.table_name(), id_field_name(table).as_deref())
134 .await?;
135 Ok(records.into_iter().next())
136 }
137
138 async fn get_table_count<E>(&self, table: &Table<Self, E>) -> Result<i64>
139 where
140 E: Entity<Self::Value>,
141 Self: Sized,
142 {
143 let records = self
144 .fetch_records(table.table_name(), id_field_name(table).as_deref())
145 .await?;
146 Ok(records.len() as i64)
147 }
148
149 async fn get_table_sum<E>(
150 &self,
151 _table: &Table<Self, E>,
152 _column: &Self::Column<Self::AnyType>,
153 ) -> Result<Self::Value>
154 where
155 E: Entity<Self::Value>,
156 Self: Sized,
157 {
158 Err(error!("Sum not implemented for API backend"))
159 }
160
161 async fn get_table_max<E>(
162 &self,
163 _table: &Table<Self, E>,
164 _column: &Self::Column<Self::AnyType>,
165 ) -> Result<Self::Value>
166 where
167 E: Entity<Self::Value>,
168 Self: Sized,
169 {
170 Err(error!("Max not implemented for API backend"))
171 }
172
173 async fn get_table_min<E>(
174 &self,
175 _table: &Table<Self, E>,
176 _column: &Self::Column<Self::AnyType>,
177 ) -> Result<Self::Value>
178 where
179 E: Entity<Self::Value>,
180 Self: Sized,
181 {
182 Err(error!("Min not implemented for API backend"))
183 }
184
185 async fn insert_table_value<E>(
186 &self,
187 _table: &Table<Self, E>,
188 _id: &Self::Id,
189 _record: &Record<Self::Value>,
190 ) -> Result<Record<Self::Value>>
191 where
192 E: Entity<Self::Value>,
193 Self: Sized,
194 {
195 Err(error!("REST API is a read-only data source"))
196 }
197
198 async fn replace_table_value<E>(
199 &self,
200 _table: &Table<Self, E>,
201 _id: &Self::Id,
202 _record: &Record<Self::Value>,
203 ) -> Result<Record<Self::Value>>
204 where
205 E: Entity<Self::Value>,
206 Self: Sized,
207 {
208 Err(error!("REST API is a read-only data source"))
209 }
210
211 async fn patch_table_value<E>(
212 &self,
213 _table: &Table<Self, E>,
214 _id: &Self::Id,
215 _partial: &Record<Self::Value>,
216 ) -> Result<Record<Self::Value>>
217 where
218 E: Entity<Self::Value>,
219 Self: Sized,
220 {
221 Err(error!("REST API is a read-only data source"))
222 }
223
224 async fn delete_table_value<E>(&self, _table: &Table<Self, E>, _id: &Self::Id) -> Result<()>
225 where
226 E: Entity<Self::Value>,
227 Self: Sized,
228 {
229 Err(error!("REST API is a read-only data source"))
230 }
231
232 async fn delete_table_all_values<E>(&self, _table: &Table<Self, E>) -> Result<()>
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 insert_table_return_id_value<E>(
241 &self,
242 _table: &Table<Self, E>,
243 _record: &Record<Self::Value>,
244 ) -> Result<Self::Id>
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 fn related_in_condition<SourceE: Entity<Self::Value> + 'static>(
253 &self,
254 _target_field: &str,
255 _source_table: &Table<Self, SourceE>,
256 _source_column: &str,
257 ) -> Self::Condition
258 where
259 Self: Sized,
260 {
261 unimplemented!("related_in_condition not yet supported for REST API")
262 }
263
264 fn column_table_values_expr<'a, E, Type: ColumnType>(
265 &'a self,
266 _table: &Table<Self, E>,
267 _column: &Self::Column<Type>,
268 ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>>
269 where
270 E: Entity<Self::Value> + 'static,
271 Self: Sized,
272 {
273 unimplemented!("column_table_values_expr not yet supported for REST API")
274 }
275}