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
92 where
93 T: TableLike<Value = CborValue, Id = String> + 'static,
94 {
95 Self {
96 inner: Box::new(table),
97 datasource_type_id: TypeId::of::<T>(),
98 entity_type_id: TypeId::of::<()>(),
99 datasource_name: std::any::type_name::<T>(),
100 entity_name: "<wrapped>",
101 }
102 }
103
104 pub fn downcast<
108 T: TableSource<Value = CborValue, Id = String> + 'static,
109 E: Entity<CborValue> + 'static,
110 >(
111 self,
112 ) -> Result<Table<T, E>> {
113 if self.datasource_type_id != TypeId::of::<T>() {
115 let expected = std::any::type_name::<T>();
116 return Err(error!(
117 "DataSource type mismatch",
118 expected = expected,
119 actual = self.datasource_name
120 ));
121 }
122 if self.entity_type_id != TypeId::of::<E>() {
123 let expected = std::any::type_name::<E>();
124 return Err(error!(
125 "Entity type mismatch",
126 expected = expected,
127 actual = self.entity_name
128 ));
129 }
130
131 self.inner
133 .into_any()
134 .downcast::<Table<T, E>>()
135 .map(|boxed| *boxed)
136 .map_err(|_| error!("Failed to downcast table"))
137 }
138
139 pub fn datasource_name(&self) -> &str {
141 self.datasource_name
142 }
143
144 pub fn entity_name(&self) -> &str {
146 self.entity_name
147 }
148
149 pub fn datasource_type_id(&self) -> TypeId {
151 self.datasource_type_id
152 }
153
154 pub fn entity_type_id(&self) -> TypeId {
156 self.entity_type_id
157 }
158
159 pub fn is_type<T: TableSource + 'static, E: Entity<CborValue> + 'static>(&self) -> bool {
161 self.datasource_type_id == TypeId::of::<T>() && self.entity_type_id == TypeId::of::<E>()
162 }
163}
164
165impl Clone for AnyTable {
166 fn clone(&self) -> Self {
167 Self {
168 inner: self.inner.clone_box(),
169 datasource_type_id: self.datasource_type_id,
170 entity_type_id: self.entity_type_id,
171 datasource_name: self.datasource_name,
172 entity_name: self.entity_name,
173 }
174 }
175}
176
177impl std::fmt::Debug for AnyTable {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 f.debug_struct("AnyTable")
180 .field("datasource", &self.datasource_name)
181 .field("entity", &self.entity_name)
182 .finish()
183 }
184}
185
186impl ValueSet for AnyTable {
188 type Id = String;
189 type Value = CborValue;
190}
191
192#[async_trait]
194impl ReadableValueSet for AnyTable {
195 async fn list_values(&self) -> Result<IndexMap<Self::Id, Record<Self::Value>>> {
196 self.inner.list_values().await
197 }
198
199 async fn get_value(&self, id: &Self::Id) -> Result<Option<Record<Self::Value>>> {
200 self.inner.get_value(id).await
201 }
202
203 async fn get_some_value(&self) -> Result<Option<(Self::Id, Record<Self::Value>)>> {
204 self.inner.get_some_value().await
205 }
206}
207
208#[async_trait]
210impl WritableValueSet for AnyTable {
211 async fn insert_value(
212 &self,
213 id: &Self::Id,
214 record: &Record<Self::Value>,
215 ) -> Result<Record<Self::Value>> {
216 self.inner.insert_value(id, record).await
217 }
218
219 async fn replace_value(
220 &self,
221 id: &Self::Id,
222 record: &Record<Self::Value>,
223 ) -> Result<Record<Self::Value>> {
224 self.inner.replace_value(id, record).await
225 }
226
227 async fn patch_value(
228 &self,
229 id: &Self::Id,
230 partial: &Record<Self::Value>,
231 ) -> Result<Record<Self::Value>> {
232 self.inner.patch_value(id, partial).await
233 }
234
235 async fn delete(&self, id: &Self::Id) -> Result<()> {
236 self.inner.delete(id).await
237 }
238
239 async fn delete_all(&self) -> Result<()> {
240 self.inner.delete_all().await
241 }
242}
243
244#[async_trait]
246impl TableLike for AnyTable {
247 fn table_name(&self) -> &str {
248 self.inner.table_name()
249 }
250
251 fn set_table_name(&mut self, name: String) {
252 self.inner.set_table_name(name);
253 }
254
255 fn table_alias(&self) -> &str {
256 self.inner.table_alias()
257 }
258
259 fn column_names(&self) -> Vec<String> {
260 self.inner.column_names()
261 }
262
263 fn id_field_name(&self) -> Option<String> {
264 self.inner.id_field_name()
265 }
266
267 fn title_field_names(&self) -> Vec<String> {
268 self.inner.title_field_names()
269 }
270
271 fn column_types(&self) -> IndexMap<String, &'static str> {
272 self.inner.column_types()
273 }
274
275 fn get_ref_names(&self) -> Vec<String> {
276 self.inner.get_ref_names()
277 }
278
279 fn add_condition(&mut self, condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
280 self.inner.add_condition(condition)
281 }
282
283 fn add_condition_eq(&mut self, field: &str, value: &str) -> Result<()> {
284 self.inner.add_condition_eq(field, value)
285 }
286
287 fn temp_add_condition(
288 &mut self,
289 condition: vantage_expressions::AnyExpression,
290 ) -> Result<ConditionHandle> {
291 self.inner.temp_add_condition(condition)
292 }
293
294 fn temp_remove_condition(&mut self, handle: ConditionHandle) -> Result<()> {
295 self.inner.temp_remove_condition(handle)
296 }
297
298 fn search_expression(&self, search_value: &str) -> Result<vantage_expressions::AnyExpression> {
299 self.inner.search_expression(search_value)
300 }
301
302 fn clone_box(&self) -> Box<dyn TableLike<Value = Self::Value, Id = Self::Id>> {
303 Box::new(self.clone())
304 }
305
306 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
307 self
308 }
309
310 fn as_any_ref(&self) -> &dyn std::any::Any {
311 self
312 }
313
314 fn set_pagination(&mut self, pagination: Option<Pagination>) {
315 self.inner.set_pagination(pagination)
316 }
317
318 fn get_pagination(&self) -> Option<&Pagination> {
319 self.inner.get_pagination()
320 }
321
322 async fn get_count(&self) -> vantage_core::Result<i64> {
323 self.inner.get_count().await
324 }
325
326 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
327 self.inner.get_ref(relation)
328 }
329}
330
331impl AnyTable {
332 pub fn get_ref(&self, relation: &str) -> Result<AnyTable> {
336 TableLike::get_ref(self, relation)
337 }
338
339 pub fn with_pagination<F>(&mut self, func: F)
341 where
342 F: FnOnce(&mut Pagination),
343 {
344 let mut pagination = self.inner.get_pagination().copied().unwrap_or_default();
345 func(&mut pagination);
346 self.inner.set_pagination(Some(pagination));
347 }
348}
349
350struct CborAdapter<T: TableSource, E: Entity<T::Value>> {
355 inner: Table<T, E>,
356}
357
358impl<T: TableSource, E: Entity<T::Value>> Clone for CborAdapter<T, E> {
359 fn clone(&self) -> Self {
360 Self {
361 inner: self.inner.clone(),
362 }
363 }
364}
365
366impl<T, E> CborAdapter<T, E>
367where
368 T: TableSource,
369 T::Value: Into<CborValue>,
370 T::Id: Display,
371 E: Entity<T::Value>,
372{
373 fn convert_record(record: Record<T::Value>) -> Record<CborValue> {
374 record.into_iter().map(|(k, v)| (k, v.into())).collect()
375 }
376
377 fn convert_record_back(record: &Record<CborValue>) -> Record<T::Value>
378 where
379 T::Value: From<CborValue>,
380 {
381 record
382 .iter()
383 .map(|(k, v)| (k.clone(), T::Value::from(v.clone())))
384 .collect()
385 }
386}
387
388impl<T, E> ValueSet for CborAdapter<T, E>
389where
390 T: TableSource,
391 E: Entity<T::Value>,
392{
393 type Id = String;
394 type Value = CborValue;
395}
396
397#[async_trait]
398impl<T, E> ReadableValueSet for CborAdapter<T, E>
399where
400 T: TableSource,
401 T::Value: Into<CborValue>,
402 T::Id: Display + From<String>,
403 E: Entity<T::Value>,
404{
405 async fn list_values(&self) -> Result<IndexMap<String, Record<CborValue>>> {
406 let raw = self
407 .inner
408 .data_source()
409 .list_table_values(&self.inner)
410 .await?;
411 Ok(raw
412 .into_iter()
413 .map(|(id, rec)| (id.to_string(), Self::convert_record(rec)))
414 .collect())
415 }
416
417 async fn get_value(&self, id: &String) -> Result<Option<Record<CborValue>>> {
418 let native_id: T::Id = id.clone().into();
419 let rec = self
420 .inner
421 .data_source()
422 .get_table_value(&self.inner, &native_id)
423 .await?;
424 Ok(rec.map(Self::convert_record))
425 }
426
427 async fn get_some_value(&self) -> Result<Option<(String, Record<CborValue>)>> {
428 let result = self
429 .inner
430 .data_source()
431 .get_table_some_value(&self.inner)
432 .await?;
433 Ok(result.map(|(id, rec)| (id.to_string(), Self::convert_record(rec))))
434 }
435}
436
437#[async_trait]
438impl<T, E> WritableValueSet for CborAdapter<T, E>
439where
440 T: TableSource,
441 T::Value: Into<CborValue> + From<CborValue>,
442 T::Id: Display + From<String>,
443 E: Entity<T::Value>,
444{
445 async fn insert_value(
446 &self,
447 id: &String,
448 record: &Record<CborValue>,
449 ) -> Result<Record<CborValue>> {
450 let native_id: T::Id = id.clone().into();
451 let native_rec = Self::convert_record_back(record);
452 let returned = self
453 .inner
454 .data_source()
455 .insert_table_value(&self.inner, &native_id, &native_rec)
456 .await?;
457 Ok(Self::convert_record(returned))
458 }
459
460 async fn replace_value(
461 &self,
462 id: &String,
463 record: &Record<CborValue>,
464 ) -> Result<Record<CborValue>> {
465 let native_id: T::Id = id.clone().into();
466 let native_rec = Self::convert_record_back(record);
467 let returned = self
468 .inner
469 .data_source()
470 .replace_table_value(&self.inner, &native_id, &native_rec)
471 .await?;
472 Ok(Self::convert_record(returned))
473 }
474
475 async fn patch_value(
476 &self,
477 id: &String,
478 partial: &Record<CborValue>,
479 ) -> Result<Record<CborValue>> {
480 let native_id: T::Id = id.clone().into();
481 let native_rec = Self::convert_record_back(partial);
482 let returned = self
483 .inner
484 .data_source()
485 .patch_table_value(&self.inner, &native_id, &native_rec)
486 .await?;
487 Ok(Self::convert_record(returned))
488 }
489
490 async fn delete(&self, id: &String) -> Result<()> {
491 let native_id: T::Id = id.clone().into();
492 self.inner
493 .data_source()
494 .delete_table_value(&self.inner, &native_id)
495 .await
496 }
497
498 async fn delete_all(&self) -> Result<()> {
499 self.inner
500 .data_source()
501 .delete_table_all_values(&self.inner)
502 .await
503 }
504}
505
506#[async_trait]
507impl<T, E> TableLike for CborAdapter<T, E>
508where
509 T: TableSource + 'static,
510 T::Value: Into<CborValue> + From<CborValue>,
511 T::Id: Display + From<String>,
512 E: Entity<T::Value> + 'static,
513{
514 fn table_name(&self) -> &str {
515 self.inner.table_name()
516 }
517
518 fn set_table_name(&mut self, name: String) {
519 self.inner.set_table_name(name);
520 }
521
522 fn table_alias(&self) -> &str {
523 self.inner.table_name()
524 }
525
526 fn column_names(&self) -> Vec<String> {
527 self.inner.columns().keys().cloned().collect()
528 }
529
530 fn id_field_name(&self) -> Option<String> {
531 TableLike::id_field_name(&self.inner)
532 }
533
534 fn title_field_names(&self) -> Vec<String> {
535 TableLike::title_field_names(&self.inner)
536 }
537
538 fn column_types(&self) -> IndexMap<String, &'static str> {
539 TableLike::column_types(&self.inner)
540 }
541
542 fn get_ref_names(&self) -> Vec<String> {
543 TableLike::get_ref_names(&self.inner)
544 }
545
546 fn add_condition(&mut self, _condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
547 Err(error!("add_condition not supported through CborAdapter"))
548 }
549
550 fn add_condition_eq(&mut self, field: &str, value: &str) -> Result<()> {
551 TableLike::add_condition_eq(&mut self.inner, field, value)
552 }
553
554 fn temp_add_condition(
555 &mut self,
556 _condition: vantage_expressions::AnyExpression,
557 ) -> Result<ConditionHandle> {
558 Err(error!(
559 "temp_add_condition not supported through CborAdapter"
560 ))
561 }
562
563 fn temp_remove_condition(&mut self, _handle: ConditionHandle) -> Result<()> {
564 Err(error!(
565 "temp_remove_condition not supported through CborAdapter"
566 ))
567 }
568
569 fn search_expression(&self, _search_value: &str) -> Result<vantage_expressions::AnyExpression> {
570 Err(error!(
571 "search_expression not supported through CborAdapter"
572 ))
573 }
574
575 fn clone_box(&self) -> Box<dyn TableLike<Value = CborValue, Id = String>> {
576 Box::new(self.clone())
577 }
578
579 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
580 self
581 }
582
583 fn as_any_ref(&self) -> &dyn std::any::Any {
584 self
585 }
586
587 fn set_pagination(&mut self, pagination: Option<Pagination>) {
588 self.inner.set_pagination(pagination);
589 }
590
591 fn get_pagination(&self) -> Option<&Pagination> {
592 self.inner.pagination()
593 }
594
595 async fn get_count(&self) -> Result<i64> {
596 self.inner.data_source().get_table_count(&self.inner).await
597 }
598
599 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
600 self.inner.get_ref(relation)
601 }
602}
603
604