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