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 id_field_name(&self) -> Option<String> {
261 self.inner.id_field_name()
262 }
263
264 fn title_field_names(&self) -> Vec<String> {
265 self.inner.title_field_names()
266 }
267
268 fn column_types(&self) -> IndexMap<String, &'static str> {
269 self.inner.column_types()
270 }
271
272 fn get_ref_names(&self) -> Vec<String> {
273 self.inner.get_ref_names()
274 }
275
276 fn add_condition(&mut self, condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
277 self.inner.add_condition(condition)
278 }
279
280 fn add_condition_eq(&mut self, field: &str, value: &str) -> Result<()> {
281 self.inner.add_condition_eq(field, value)
282 }
283
284 fn temp_add_condition(
285 &mut self,
286 condition: vantage_expressions::AnyExpression,
287 ) -> Result<ConditionHandle> {
288 self.inner.temp_add_condition(condition)
289 }
290
291 fn temp_remove_condition(&mut self, handle: ConditionHandle) -> Result<()> {
292 self.inner.temp_remove_condition(handle)
293 }
294
295 fn search_expression(&self, search_value: &str) -> Result<vantage_expressions::AnyExpression> {
296 self.inner.search_expression(search_value)
297 }
298
299 fn clone_box(&self) -> Box<dyn TableLike<Value = Self::Value, Id = Self::Id>> {
300 Box::new(self.clone())
301 }
302
303 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
304 self
305 }
306
307 fn as_any_ref(&self) -> &dyn std::any::Any {
308 self
309 }
310
311 fn set_pagination(&mut self, pagination: Option<Pagination>) {
312 self.inner.set_pagination(pagination)
313 }
314
315 fn get_pagination(&self) -> Option<&Pagination> {
316 self.inner.get_pagination()
317 }
318
319 async fn get_count(&self) -> vantage_core::Result<i64> {
320 self.inner.get_count().await
321 }
322
323 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
324 self.inner.get_ref(relation)
325 }
326}
327
328impl AnyTable {
329 pub fn get_ref(&self, relation: &str) -> Result<AnyTable> {
333 TableLike::get_ref(self, relation)
334 }
335
336 pub fn with_pagination<F>(&mut self, func: F)
338 where
339 F: FnOnce(&mut Pagination),
340 {
341 let mut pagination = self.inner.get_pagination().copied().unwrap_or_default();
342 func(&mut pagination);
343 self.inner.set_pagination(Some(pagination));
344 }
345}
346
347struct CborAdapter<T: TableSource, E: Entity<T::Value>> {
352 inner: Table<T, E>,
353}
354
355impl<T: TableSource, E: Entity<T::Value>> Clone for CborAdapter<T, E> {
356 fn clone(&self) -> Self {
357 Self {
358 inner: self.inner.clone(),
359 }
360 }
361}
362
363impl<T, E> CborAdapter<T, E>
364where
365 T: TableSource,
366 T::Value: Into<CborValue>,
367 T::Id: Display,
368 E: Entity<T::Value>,
369{
370 fn convert_record(record: Record<T::Value>) -> Record<CborValue> {
371 record.into_iter().map(|(k, v)| (k, v.into())).collect()
372 }
373
374 fn convert_record_back(record: &Record<CborValue>) -> Record<T::Value>
375 where
376 T::Value: From<CborValue>,
377 {
378 record
379 .iter()
380 .map(|(k, v)| (k.clone(), T::Value::from(v.clone())))
381 .collect()
382 }
383}
384
385impl<T, E> ValueSet for CborAdapter<T, E>
386where
387 T: TableSource,
388 E: Entity<T::Value>,
389{
390 type Id = String;
391 type Value = CborValue;
392}
393
394#[async_trait]
395impl<T, E> ReadableValueSet for CborAdapter<T, E>
396where
397 T: TableSource,
398 T::Value: Into<CborValue>,
399 T::Id: Display + From<String>,
400 E: Entity<T::Value>,
401{
402 async fn list_values(&self) -> Result<IndexMap<String, Record<CborValue>>> {
403 let raw = self
404 .inner
405 .data_source()
406 .list_table_values(&self.inner)
407 .await?;
408 Ok(raw
409 .into_iter()
410 .map(|(id, rec)| (id.to_string(), Self::convert_record(rec)))
411 .collect())
412 }
413
414 async fn get_value(&self, id: &String) -> Result<Option<Record<CborValue>>> {
415 let native_id: T::Id = id.clone().into();
416 let rec = self
417 .inner
418 .data_source()
419 .get_table_value(&self.inner, &native_id)
420 .await?;
421 Ok(rec.map(Self::convert_record))
422 }
423
424 async fn get_some_value(&self) -> Result<Option<(String, Record<CborValue>)>> {
425 let result = self
426 .inner
427 .data_source()
428 .get_table_some_value(&self.inner)
429 .await?;
430 Ok(result.map(|(id, rec)| (id.to_string(), Self::convert_record(rec))))
431 }
432}
433
434#[async_trait]
435impl<T, E> WritableValueSet for CborAdapter<T, E>
436where
437 T: TableSource,
438 T::Value: Into<CborValue> + From<CborValue>,
439 T::Id: Display + From<String>,
440 E: Entity<T::Value>,
441{
442 async fn insert_value(
443 &self,
444 id: &String,
445 record: &Record<CborValue>,
446 ) -> Result<Record<CborValue>> {
447 let native_id: T::Id = id.clone().into();
448 let native_rec = Self::convert_record_back(record);
449 let returned = self
450 .inner
451 .data_source()
452 .insert_table_value(&self.inner, &native_id, &native_rec)
453 .await?;
454 Ok(Self::convert_record(returned))
455 }
456
457 async fn replace_value(
458 &self,
459 id: &String,
460 record: &Record<CborValue>,
461 ) -> Result<Record<CborValue>> {
462 let native_id: T::Id = id.clone().into();
463 let native_rec = Self::convert_record_back(record);
464 let returned = self
465 .inner
466 .data_source()
467 .replace_table_value(&self.inner, &native_id, &native_rec)
468 .await?;
469 Ok(Self::convert_record(returned))
470 }
471
472 async fn patch_value(
473 &self,
474 id: &String,
475 partial: &Record<CborValue>,
476 ) -> Result<Record<CborValue>> {
477 let native_id: T::Id = id.clone().into();
478 let native_rec = Self::convert_record_back(partial);
479 let returned = self
480 .inner
481 .data_source()
482 .patch_table_value(&self.inner, &native_id, &native_rec)
483 .await?;
484 Ok(Self::convert_record(returned))
485 }
486
487 async fn delete(&self, id: &String) -> Result<()> {
488 let native_id: T::Id = id.clone().into();
489 self.inner
490 .data_source()
491 .delete_table_value(&self.inner, &native_id)
492 .await
493 }
494
495 async fn delete_all(&self) -> Result<()> {
496 self.inner
497 .data_source()
498 .delete_table_all_values(&self.inner)
499 .await
500 }
501}
502
503#[async_trait]
504impl<T, E> TableLike for CborAdapter<T, E>
505where
506 T: TableSource + 'static,
507 T::Value: Into<CborValue> + From<CborValue>,
508 T::Id: Display + From<String>,
509 E: Entity<T::Value> + 'static,
510{
511 fn table_name(&self) -> &str {
512 self.inner.table_name()
513 }
514
515 fn table_alias(&self) -> &str {
516 self.inner.table_name()
517 }
518
519 fn column_names(&self) -> Vec<String> {
520 self.inner.columns().keys().cloned().collect()
521 }
522
523 fn id_field_name(&self) -> Option<String> {
524 TableLike::id_field_name(&self.inner)
525 }
526
527 fn title_field_names(&self) -> Vec<String> {
528 TableLike::title_field_names(&self.inner)
529 }
530
531 fn column_types(&self) -> IndexMap<String, &'static str> {
532 TableLike::column_types(&self.inner)
533 }
534
535 fn get_ref_names(&self) -> Vec<String> {
536 TableLike::get_ref_names(&self.inner)
537 }
538
539 fn add_condition(&mut self, _condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
540 Err(error!("add_condition not supported through CborAdapter"))
541 }
542
543 fn add_condition_eq(&mut self, field: &str, value: &str) -> Result<()> {
544 TableLike::add_condition_eq(&mut self.inner, field, value)
545 }
546
547 fn temp_add_condition(
548 &mut self,
549 _condition: vantage_expressions::AnyExpression,
550 ) -> Result<ConditionHandle> {
551 Err(error!(
552 "temp_add_condition not supported through CborAdapter"
553 ))
554 }
555
556 fn temp_remove_condition(&mut self, _handle: ConditionHandle) -> Result<()> {
557 Err(error!(
558 "temp_remove_condition not supported through CborAdapter"
559 ))
560 }
561
562 fn search_expression(&self, _search_value: &str) -> Result<vantage_expressions::AnyExpression> {
563 Err(error!(
564 "search_expression not supported through CborAdapter"
565 ))
566 }
567
568 fn clone_box(&self) -> Box<dyn TableLike<Value = CborValue, Id = String>> {
569 Box::new(self.clone())
570 }
571
572 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
573 self
574 }
575
576 fn as_any_ref(&self) -> &dyn std::any::Any {
577 self
578 }
579
580 fn set_pagination(&mut self, pagination: Option<Pagination>) {
581 self.inner.set_pagination(pagination);
582 }
583
584 fn get_pagination(&self) -> Option<&Pagination> {
585 self.inner.pagination()
586 }
587
588 async fn get_count(&self) -> Result<i64> {
589 self.inner.data_source().get_table_count(&self.inner).await
590 }
591
592 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
593 self.inner.get_ref(relation)
594 }
595}
596
597