1use std::any::TypeId;
18use std::fmt::Display;
19
20use async_trait::async_trait;
21use ciborium::Value as CborValue;
22use indexmap::IndexMap;
23use vantage_core::{Result, error};
24use vantage_dataset::traits::{ReadableValueSet, ValueSet, WritableValueSet};
25use vantage_types::{Entity, Record};
26
27pub type AnyRecord = Record<CborValue>;
29
30use crate::{
31 conditions::ConditionHandle,
32 pagination::Pagination,
33 table::Table,
34 traits::{table_like::TableLike, table_source::TableSource},
35};
36
37pub struct AnyTable {
40 inner: Box<dyn TableLike<Value = CborValue, Id = String>>,
41 datasource_type_id: TypeId,
42 entity_type_id: TypeId,
43 datasource_name: &'static str,
44 entity_name: &'static str,
45}
46
47impl AnyTable {
48 pub fn new<
51 T: TableSource<Value = CborValue, Id = String> + 'static,
52 E: Entity<CborValue> + 'static,
53 >(
54 table: Table<T, E>,
55 ) -> Self {
56 Self {
57 inner: Box::new(table),
58 datasource_type_id: TypeId::of::<T>(),
59 entity_type_id: TypeId::of::<E>(),
60 datasource_name: std::any::type_name::<T>(),
61 entity_name: std::any::type_name::<E>(),
62 }
63 }
64
65 pub fn from_table<T, E>(table: Table<T, E>) -> Self
72 where
73 T: TableSource + 'static,
74 T::Value: Into<CborValue> + From<CborValue>,
75 T::Id: Display + From<String>,
76 E: Entity<T::Value> + 'static,
77 {
78 Self {
79 inner: Box::new(CborAdapter { inner: table }),
80 datasource_type_id: TypeId::of::<T>(),
81 entity_type_id: TypeId::of::<E>(),
82 datasource_name: std::any::type_name::<T>(),
83 entity_name: std::any::type_name::<E>(),
84 }
85 }
86
87 pub fn from_table_like<T>(table: T) -> Self
93 where
94 T: TableLike<Value = CborValue, Id = String> + 'static,
95 {
96 Self {
97 inner: Box::new(table),
98 datasource_type_id: TypeId::of::<T>(),
99 entity_type_id: TypeId::of::<()>(),
100 datasource_name: std::any::type_name::<T>(),
101 entity_name: "<wrapped>",
102 }
103 }
104
105 pub fn downcast<
109 T: TableSource<Value = CborValue, Id = String> + 'static,
110 E: Entity<CborValue> + 'static,
111 >(
112 self,
113 ) -> Result<Table<T, E>> {
114 if self.datasource_type_id != TypeId::of::<T>() {
116 let expected = std::any::type_name::<T>();
117 return Err(error!(
118 "DataSource type mismatch",
119 expected = expected,
120 actual = self.datasource_name
121 ));
122 }
123 if self.entity_type_id != TypeId::of::<E>() {
124 let expected = std::any::type_name::<E>();
125 return Err(error!(
126 "Entity type mismatch",
127 expected = expected,
128 actual = self.entity_name
129 ));
130 }
131
132 self.inner
134 .into_any()
135 .downcast::<Table<T, E>>()
136 .map(|boxed| *boxed)
137 .map_err(|_| error!("Failed to downcast table"))
138 }
139
140 pub fn datasource_name(&self) -> &str {
142 self.datasource_name
143 }
144
145 pub fn entity_name(&self) -> &str {
147 self.entity_name
148 }
149
150 pub fn datasource_type_id(&self) -> TypeId {
152 self.datasource_type_id
153 }
154
155 pub fn entity_type_id(&self) -> TypeId {
157 self.entity_type_id
158 }
159
160 pub fn is_type<T: TableSource + 'static, E: Entity<CborValue> + 'static>(&self) -> bool {
162 self.datasource_type_id == TypeId::of::<T>() && self.entity_type_id == TypeId::of::<E>()
163 }
164}
165
166impl Clone for AnyTable {
167 fn clone(&self) -> Self {
168 Self {
169 inner: self.inner.clone_box(),
170 datasource_type_id: self.datasource_type_id,
171 entity_type_id: self.entity_type_id,
172 datasource_name: self.datasource_name,
173 entity_name: self.entity_name,
174 }
175 }
176}
177
178impl std::fmt::Debug for AnyTable {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 f.debug_struct("AnyTable")
181 .field("datasource", &self.datasource_name)
182 .field("entity", &self.entity_name)
183 .finish()
184 }
185}
186
187impl ValueSet for AnyTable {
189 type Id = String;
190 type Value = CborValue;
191}
192
193#[async_trait]
195impl ReadableValueSet for AnyTable {
196 async fn list_values(&self) -> Result<IndexMap<Self::Id, Record<Self::Value>>> {
197 self.inner.list_values().await
198 }
199
200 async fn get_value(&self, id: &Self::Id) -> Result<Option<Record<Self::Value>>> {
201 self.inner.get_value(id).await
202 }
203
204 async fn get_some_value(&self) -> Result<Option<(Self::Id, Record<Self::Value>)>> {
205 self.inner.get_some_value().await
206 }
207}
208
209#[async_trait]
211impl WritableValueSet for AnyTable {
212 async fn insert_value(
213 &self,
214 id: &Self::Id,
215 record: &Record<Self::Value>,
216 ) -> Result<Record<Self::Value>> {
217 self.inner.insert_value(id, record).await
218 }
219
220 async fn replace_value(
221 &self,
222 id: &Self::Id,
223 record: &Record<Self::Value>,
224 ) -> Result<Record<Self::Value>> {
225 self.inner.replace_value(id, record).await
226 }
227
228 async fn patch_value(
229 &self,
230 id: &Self::Id,
231 partial: &Record<Self::Value>,
232 ) -> Result<Record<Self::Value>> {
233 self.inner.patch_value(id, partial).await
234 }
235
236 async fn delete(&self, id: &Self::Id) -> Result<()> {
237 self.inner.delete(id).await
238 }
239
240 async fn delete_all(&self) -> Result<()> {
241 self.inner.delete_all().await
242 }
243}
244
245#[async_trait]
247impl TableLike for AnyTable {
248 fn table_name(&self) -> &str {
249 self.inner.table_name()
250 }
251
252 fn table_alias(&self) -> &str {
253 self.inner.table_alias()
254 }
255
256 fn column_names(&self) -> Vec<String> {
257 self.inner.column_names()
258 }
259
260 fn add_condition(&mut self, condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
261 self.inner.add_condition(condition)
262 }
263
264 fn temp_add_condition(
265 &mut self,
266 condition: vantage_expressions::AnyExpression,
267 ) -> Result<ConditionHandle> {
268 self.inner.temp_add_condition(condition)
269 }
270
271 fn temp_remove_condition(&mut self, handle: ConditionHandle) -> Result<()> {
272 self.inner.temp_remove_condition(handle)
273 }
274
275 fn search_expression(&self, search_value: &str) -> Result<vantage_expressions::AnyExpression> {
276 self.inner.search_expression(search_value)
277 }
278
279 fn clone_box(&self) -> Box<dyn TableLike<Value = Self::Value, Id = Self::Id>> {
280 Box::new(self.clone())
281 }
282
283 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
284 self
285 }
286
287 fn as_any_ref(&self) -> &dyn std::any::Any {
288 self
289 }
290
291 fn set_pagination(&mut self, pagination: Option<Pagination>) {
292 self.inner.set_pagination(pagination)
293 }
294
295 fn get_pagination(&self) -> Option<&Pagination> {
296 self.inner.get_pagination()
297 }
298
299 async fn get_count(&self) -> vantage_core::Result<i64> {
300 self.inner.get_count().await
301 }
302}
303
304impl AnyTable {
305 pub fn with_pagination<F>(&mut self, func: F)
307 where
308 F: FnOnce(&mut Pagination),
309 {
310 let mut pagination = self.inner.get_pagination().copied().unwrap_or_default();
311 func(&mut pagination);
312 self.inner.set_pagination(Some(pagination));
313 }
314}
315
316struct CborAdapter<T: TableSource, E: Entity<T::Value>> {
321 inner: Table<T, E>,
322}
323
324impl<T: TableSource, E: Entity<T::Value>> Clone for CborAdapter<T, E> {
325 fn clone(&self) -> Self {
326 Self {
327 inner: self.inner.clone(),
328 }
329 }
330}
331
332impl<T, E> CborAdapter<T, E>
333where
334 T: TableSource,
335 T::Value: Into<CborValue>,
336 T::Id: Display,
337 E: Entity<T::Value>,
338{
339 fn convert_record(record: Record<T::Value>) -> Record<CborValue> {
340 record.into_iter().map(|(k, v)| (k, v.into())).collect()
341 }
342
343 fn convert_record_back(record: &Record<CborValue>) -> Record<T::Value>
344 where
345 T::Value: From<CborValue>,
346 {
347 record
348 .iter()
349 .map(|(k, v)| (k.clone(), T::Value::from(v.clone())))
350 .collect()
351 }
352}
353
354impl<T, E> ValueSet for CborAdapter<T, E>
355where
356 T: TableSource,
357 E: Entity<T::Value>,
358{
359 type Id = String;
360 type Value = CborValue;
361}
362
363#[async_trait]
364impl<T, E> ReadableValueSet for CborAdapter<T, E>
365where
366 T: TableSource,
367 T::Value: Into<CborValue>,
368 T::Id: Display + From<String>,
369 E: Entity<T::Value>,
370{
371 async fn list_values(&self) -> Result<IndexMap<String, Record<CborValue>>> {
372 let raw = self
373 .inner
374 .data_source()
375 .list_table_values(&self.inner)
376 .await?;
377 Ok(raw
378 .into_iter()
379 .map(|(id, rec)| (id.to_string(), Self::convert_record(rec)))
380 .collect())
381 }
382
383 async fn get_value(&self, id: &String) -> Result<Option<Record<CborValue>>> {
384 let native_id: T::Id = id.clone().into();
385 let rec = self
386 .inner
387 .data_source()
388 .get_table_value(&self.inner, &native_id)
389 .await?;
390 Ok(rec.map(Self::convert_record))
391 }
392
393 async fn get_some_value(&self) -> Result<Option<(String, Record<CborValue>)>> {
394 let result = self
395 .inner
396 .data_source()
397 .get_table_some_value(&self.inner)
398 .await?;
399 Ok(result.map(|(id, rec)| (id.to_string(), Self::convert_record(rec))))
400 }
401}
402
403#[async_trait]
404impl<T, E> WritableValueSet for CborAdapter<T, E>
405where
406 T: TableSource,
407 T::Value: Into<CborValue> + From<CborValue>,
408 T::Id: Display + From<String>,
409 E: Entity<T::Value>,
410{
411 async fn insert_value(
412 &self,
413 id: &String,
414 record: &Record<CborValue>,
415 ) -> Result<Record<CborValue>> {
416 let native_id: T::Id = id.clone().into();
417 let native_rec = Self::convert_record_back(record);
418 let returned = self
419 .inner
420 .data_source()
421 .insert_table_value(&self.inner, &native_id, &native_rec)
422 .await?;
423 Ok(Self::convert_record(returned))
424 }
425
426 async fn replace_value(
427 &self,
428 id: &String,
429 record: &Record<CborValue>,
430 ) -> Result<Record<CborValue>> {
431 let native_id: T::Id = id.clone().into();
432 let native_rec = Self::convert_record_back(record);
433 let returned = self
434 .inner
435 .data_source()
436 .replace_table_value(&self.inner, &native_id, &native_rec)
437 .await?;
438 Ok(Self::convert_record(returned))
439 }
440
441 async fn patch_value(
442 &self,
443 id: &String,
444 partial: &Record<CborValue>,
445 ) -> Result<Record<CborValue>> {
446 let native_id: T::Id = id.clone().into();
447 let native_rec = Self::convert_record_back(partial);
448 let returned = self
449 .inner
450 .data_source()
451 .patch_table_value(&self.inner, &native_id, &native_rec)
452 .await?;
453 Ok(Self::convert_record(returned))
454 }
455
456 async fn delete(&self, id: &String) -> Result<()> {
457 let native_id: T::Id = id.clone().into();
458 self.inner
459 .data_source()
460 .delete_table_value(&self.inner, &native_id)
461 .await
462 }
463
464 async fn delete_all(&self) -> Result<()> {
465 self.inner
466 .data_source()
467 .delete_table_all_values(&self.inner)
468 .await
469 }
470}
471
472#[async_trait]
473impl<T, E> TableLike for CborAdapter<T, E>
474where
475 T: TableSource + 'static,
476 T::Value: Into<CborValue> + From<CborValue>,
477 T::Id: Display + From<String>,
478 E: Entity<T::Value> + 'static,
479{
480 fn table_name(&self) -> &str {
481 self.inner.table_name()
482 }
483
484 fn table_alias(&self) -> &str {
485 self.inner.table_name()
486 }
487
488 fn column_names(&self) -> Vec<String> {
489 self.inner.columns().keys().cloned().collect()
490 }
491
492 fn add_condition(&mut self, _condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
493 Err(error!("add_condition not supported through CborAdapter"))
494 }
495
496 fn temp_add_condition(
497 &mut self,
498 _condition: vantage_expressions::AnyExpression,
499 ) -> Result<ConditionHandle> {
500 Err(error!(
501 "temp_add_condition not supported through CborAdapter"
502 ))
503 }
504
505 fn temp_remove_condition(&mut self, _handle: ConditionHandle) -> Result<()> {
506 Err(error!(
507 "temp_remove_condition not supported through CborAdapter"
508 ))
509 }
510
511 fn search_expression(&self, _search_value: &str) -> Result<vantage_expressions::AnyExpression> {
512 Err(error!(
513 "search_expression not supported through CborAdapter"
514 ))
515 }
516
517 fn clone_box(&self) -> Box<dyn TableLike<Value = CborValue, Id = String>> {
518 Box::new(self.clone())
519 }
520
521 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
522 self
523 }
524
525 fn as_any_ref(&self) -> &dyn std::any::Any {
526 self
527 }
528
529 fn set_pagination(&mut self, pagination: Option<Pagination>) {
530 self.inner.set_pagination(pagination);
531 }
532
533 fn get_pagination(&self) -> Option<&Pagination> {
534 self.inner.pagination()
535 }
536
537 async fn get_count(&self) -> Result<i64> {
538 self.inner.data_source().get_table_count(&self.inner).await
539 }
540}
541
542