1use async_trait::async_trait;
14use ciborium::Value as CborValue;
15use indexmap::IndexMap;
16use serde_json::json;
17
18use vantage_core::error;
19use vantage_dataset::traits::Result;
20use vantage_expressions::{
21 Expression, Expressive, expr_any,
22 traits::associated_expressions::AssociatedExpression,
23 traits::datasource::ExprDataSource,
24 traits::expressive::{DeferredFn, ExpressiveEnum},
25};
26use vantage_table::column::core::{Column, ColumnType};
27use vantage_table::table::Table;
28use vantage_table::traits::table_source::TableSource;
29use vantage_types::{Entity, Record};
30
31use crate::cmd::Cmd;
32use crate::condition::CmdCondition;
33
34mod detail;
35mod list;
36
37#[async_trait]
38impl TableSource for Cmd {
39 type Column<Type>
40 = Column<Type>
41 where
42 Type: ColumnType;
43 type AnyType = CborValue;
44 type Value = CborValue;
45 type Id = String;
46 type Condition = CmdCondition;
47 type Source = String;
48
49 fn eq_condition(field: &str, value: &str) -> Result<Self::Condition> {
50 Ok(CmdCondition::eq(field.to_string(), value.to_string()))
51 }
52
53 fn eq_value_condition(&self, field: &str, value: Self::Value) -> Result<Self::Condition> {
54 Ok(CmdCondition::eq(field.to_string(), value))
55 }
56
57 fn create_column<Type: ColumnType>(&self, name: &str) -> Self::Column<Type> {
58 Column::new(name)
59 }
60
61 fn to_any_column<Type: ColumnType>(
62 &self,
63 column: Self::Column<Type>,
64 ) -> Self::Column<Self::AnyType> {
65 Column::from_column(column)
66 }
67
68 fn convert_any_column<Type: ColumnType>(
69 &self,
70 any_column: Self::Column<Self::AnyType>,
71 ) -> Option<Self::Column<Type>> {
72 Some(Column::from_column(any_column))
73 }
74
75 fn expr(
76 &self,
77 template: impl Into<String>,
78 parameters: Vec<ExpressiveEnum<Self::Value>>,
79 ) -> Expression<Self::Value> {
80 Expression::new(template, parameters)
81 }
82
83 fn search_table_condition<E>(
84 &self,
85 _table: &Table<Self, E>,
86 search_value: &str,
87 ) -> Self::Condition
88 where
89 E: Entity<Self::Value>,
90 {
91 CmdCondition::eq("__search__", json!(search_value).to_string())
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.list_rows(table).await
106 }
107
108 async fn get_table_value<E>(
109 &self,
110 table: &Table<Self, E>,
111 id: &Self::Id,
112 ) -> Result<Option<Record<Self::Value>>>
113 where
114 E: Entity<Self::Value>,
115 Self: Sized,
116 {
117 let empty: Record<CborValue> = Record::new();
119 self.get_table_value_with_row(table, id, &empty).await
120 }
121
122 async fn get_table_some_value<E>(
123 &self,
124 table: &Table<Self, E>,
125 ) -> Result<Option<(Self::Id, Record<Self::Value>)>>
126 where
127 E: Entity<Self::Value>,
128 Self: Sized,
129 {
130 let all = self.list_table_values(table).await?;
131 Ok(all.into_iter().next())
132 }
133
134 async fn get_table_count<E>(&self, table: &Table<Self, E>) -> Result<i64>
135 where
136 E: Entity<Self::Value>,
137 Self: Sized,
138 {
139 let all = self.list_table_values(table).await?;
140 Ok(all.len() as i64)
141 }
142
143 async fn get_table_sum<E>(
144 &self,
145 _table: &Table<Self, E>,
146 _column: &Self::Column<Self::AnyType>,
147 ) -> Result<Self::Value>
148 where
149 E: Entity<Self::Value>,
150 Self: Sized,
151 {
152 Err(error!("Aggregations not supported by vantage-cmd"))
153 }
154
155 async fn get_table_max<E>(
156 &self,
157 _table: &Table<Self, E>,
158 _column: &Self::Column<Self::AnyType>,
159 ) -> Result<Self::Value>
160 where
161 E: Entity<Self::Value>,
162 Self: Sized,
163 {
164 Err(error!("Aggregations not supported by vantage-cmd"))
165 }
166
167 async fn get_table_min<E>(
168 &self,
169 _table: &Table<Self, E>,
170 _column: &Self::Column<Self::AnyType>,
171 ) -> Result<Self::Value>
172 where
173 E: Entity<Self::Value>,
174 Self: Sized,
175 {
176 Err(error!("Aggregations not supported by vantage-cmd"))
177 }
178
179 async fn insert_table_value<E>(
180 &self,
181 _table: &Table<Self, E>,
182 _id: &Self::Id,
183 _record: &Record<Self::Value>,
184 ) -> Result<Record<Self::Value>>
185 where
186 E: Entity<Self::Value>,
187 Self: Sized,
188 {
189 Err(error!("vantage-cmd is read-only"))
190 }
191
192 async fn replace_table_value<E>(
193 &self,
194 _table: &Table<Self, E>,
195 _id: &Self::Id,
196 _record: &Record<Self::Value>,
197 ) -> Result<Record<Self::Value>>
198 where
199 E: Entity<Self::Value>,
200 Self: Sized,
201 {
202 Err(error!("vantage-cmd is read-only"))
203 }
204
205 async fn patch_table_value<E>(
206 &self,
207 _table: &Table<Self, E>,
208 _id: &Self::Id,
209 _partial: &Record<Self::Value>,
210 ) -> Result<Record<Self::Value>>
211 where
212 E: Entity<Self::Value>,
213 Self: Sized,
214 {
215 Err(error!("vantage-cmd is read-only"))
216 }
217
218 async fn delete_table_value<E>(&self, _table: &Table<Self, E>, _id: &Self::Id) -> Result<()>
219 where
220 E: Entity<Self::Value>,
221 Self: Sized,
222 {
223 Err(error!("vantage-cmd is read-only"))
224 }
225
226 async fn delete_table_all_values<E>(&self, _table: &Table<Self, E>) -> Result<()>
227 where
228 E: Entity<Self::Value>,
229 Self: Sized,
230 {
231 Err(error!("vantage-cmd is read-only"))
232 }
233
234 async fn insert_table_return_id_value<E>(
235 &self,
236 _table: &Table<Self, E>,
237 _record: &Record<Self::Value>,
238 ) -> Result<Self::Id>
239 where
240 E: Entity<Self::Value>,
241 Self: Sized,
242 {
243 Err(error!("vantage-cmd is read-only"))
244 }
245
246 fn related_in_condition<SourceE: Entity<Self::Value> + 'static>(
247 &self,
248 target_field: &str,
249 source_table: &Table<Self, SourceE>,
250 source_column: &str,
251 ) -> Self::Condition
252 where
253 Self: Sized,
254 {
255 let src_col = self.create_column::<Self::AnyType>(source_column);
258 let values_expr = self.column_table_values_expr(source_table, &src_col);
259 CmdCondition::Deferred {
260 field: target_field.to_string(),
261 source: values_expr.expr(),
262 }
263 }
264
265 fn column_table_values_expr<'a, E, Type: ColumnType>(
266 &'a self,
267 table: &Table<Self, E>,
268 column: &Self::Column<Type>,
269 ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>>
270 where
271 E: Entity<Self::Value> + 'static,
272 Self: Sized,
273 {
274 let table_clone = table.clone();
275 let col = column.name().to_string();
276 let cmd = self.clone();
277
278 let inner = expr_any!("{}", {
279 DeferredFn::new(move || {
280 let cmd = cmd.clone();
281 let table = table_clone.clone();
282 let col = col.clone();
283 Box::pin(async move {
284 let records = cmd.list_table_values(&table).await?;
285 let values: Vec<CborValue> = records
286 .values()
287 .filter_map(|r| r.get(&col).cloned())
288 .collect();
289 Ok(ExpressiveEnum::Scalar(CborValue::Array(values)))
290 })
291 })
292 });
293
294 let expr = expr_any!("{}", { self.defer(inner) });
295 AssociatedExpression::new(expr, self)
296 }
297}