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 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
304 self.inner.get_ref(relation)
305 }
306}
307
308impl AnyTable {
309 pub fn get_ref(&self, relation: &str) -> Result<AnyTable> {
313 TableLike::get_ref(self, relation)
314 }
315
316 pub fn with_pagination<F>(&mut self, func: F)
318 where
319 F: FnOnce(&mut Pagination),
320 {
321 let mut pagination = self.inner.get_pagination().copied().unwrap_or_default();
322 func(&mut pagination);
323 self.inner.set_pagination(Some(pagination));
324 }
325}
326
327struct CborAdapter<T: TableSource, E: Entity<T::Value>> {
332 inner: Table<T, E>,
333}
334
335impl<T: TableSource, E: Entity<T::Value>> Clone for CborAdapter<T, E> {
336 fn clone(&self) -> Self {
337 Self {
338 inner: self.inner.clone(),
339 }
340 }
341}
342
343impl<T, E> CborAdapter<T, E>
344where
345 T: TableSource,
346 T::Value: Into<CborValue>,
347 T::Id: Display,
348 E: Entity<T::Value>,
349{
350 fn convert_record(record: Record<T::Value>) -> Record<CborValue> {
351 record.into_iter().map(|(k, v)| (k, v.into())).collect()
352 }
353
354 fn convert_record_back(record: &Record<CborValue>) -> Record<T::Value>
355 where
356 T::Value: From<CborValue>,
357 {
358 record
359 .iter()
360 .map(|(k, v)| (k.clone(), T::Value::from(v.clone())))
361 .collect()
362 }
363}
364
365impl<T, E> ValueSet for CborAdapter<T, E>
366where
367 T: TableSource,
368 E: Entity<T::Value>,
369{
370 type Id = String;
371 type Value = CborValue;
372}
373
374#[async_trait]
375impl<T, E> ReadableValueSet for CborAdapter<T, E>
376where
377 T: TableSource,
378 T::Value: Into<CborValue>,
379 T::Id: Display + From<String>,
380 E: Entity<T::Value>,
381{
382 async fn list_values(&self) -> Result<IndexMap<String, Record<CborValue>>> {
383 let raw = self
384 .inner
385 .data_source()
386 .list_table_values(&self.inner)
387 .await?;
388 Ok(raw
389 .into_iter()
390 .map(|(id, rec)| (id.to_string(), Self::convert_record(rec)))
391 .collect())
392 }
393
394 async fn get_value(&self, id: &String) -> Result<Option<Record<CborValue>>> {
395 let native_id: T::Id = id.clone().into();
396 let rec = self
397 .inner
398 .data_source()
399 .get_table_value(&self.inner, &native_id)
400 .await?;
401 Ok(rec.map(Self::convert_record))
402 }
403
404 async fn get_some_value(&self) -> Result<Option<(String, Record<CborValue>)>> {
405 let result = self
406 .inner
407 .data_source()
408 .get_table_some_value(&self.inner)
409 .await?;
410 Ok(result.map(|(id, rec)| (id.to_string(), Self::convert_record(rec))))
411 }
412}
413
414#[async_trait]
415impl<T, E> WritableValueSet for CborAdapter<T, E>
416where
417 T: TableSource,
418 T::Value: Into<CborValue> + From<CborValue>,
419 T::Id: Display + From<String>,
420 E: Entity<T::Value>,
421{
422 async fn insert_value(
423 &self,
424 id: &String,
425 record: &Record<CborValue>,
426 ) -> Result<Record<CborValue>> {
427 let native_id: T::Id = id.clone().into();
428 let native_rec = Self::convert_record_back(record);
429 let returned = self
430 .inner
431 .data_source()
432 .insert_table_value(&self.inner, &native_id, &native_rec)
433 .await?;
434 Ok(Self::convert_record(returned))
435 }
436
437 async fn replace_value(
438 &self,
439 id: &String,
440 record: &Record<CborValue>,
441 ) -> Result<Record<CborValue>> {
442 let native_id: T::Id = id.clone().into();
443 let native_rec = Self::convert_record_back(record);
444 let returned = self
445 .inner
446 .data_source()
447 .replace_table_value(&self.inner, &native_id, &native_rec)
448 .await?;
449 Ok(Self::convert_record(returned))
450 }
451
452 async fn patch_value(
453 &self,
454 id: &String,
455 partial: &Record<CborValue>,
456 ) -> Result<Record<CborValue>> {
457 let native_id: T::Id = id.clone().into();
458 let native_rec = Self::convert_record_back(partial);
459 let returned = self
460 .inner
461 .data_source()
462 .patch_table_value(&self.inner, &native_id, &native_rec)
463 .await?;
464 Ok(Self::convert_record(returned))
465 }
466
467 async fn delete(&self, id: &String) -> Result<()> {
468 let native_id: T::Id = id.clone().into();
469 self.inner
470 .data_source()
471 .delete_table_value(&self.inner, &native_id)
472 .await
473 }
474
475 async fn delete_all(&self) -> Result<()> {
476 self.inner
477 .data_source()
478 .delete_table_all_values(&self.inner)
479 .await
480 }
481}
482
483#[async_trait]
484impl<T, E> TableLike for CborAdapter<T, E>
485where
486 T: TableSource + 'static,
487 T::Value: Into<CborValue> + From<CborValue>,
488 T::Id: Display + From<String>,
489 E: Entity<T::Value> + 'static,
490{
491 fn table_name(&self) -> &str {
492 self.inner.table_name()
493 }
494
495 fn table_alias(&self) -> &str {
496 self.inner.table_name()
497 }
498
499 fn column_names(&self) -> Vec<String> {
500 self.inner.columns().keys().cloned().collect()
501 }
502
503 fn add_condition(&mut self, _condition: Box<dyn std::any::Any + Send + Sync>) -> Result<()> {
504 Err(error!("add_condition not supported through CborAdapter"))
505 }
506
507 fn temp_add_condition(
508 &mut self,
509 _condition: vantage_expressions::AnyExpression,
510 ) -> Result<ConditionHandle> {
511 Err(error!(
512 "temp_add_condition not supported through CborAdapter"
513 ))
514 }
515
516 fn temp_remove_condition(&mut self, _handle: ConditionHandle) -> Result<()> {
517 Err(error!(
518 "temp_remove_condition not supported through CborAdapter"
519 ))
520 }
521
522 fn search_expression(&self, _search_value: &str) -> Result<vantage_expressions::AnyExpression> {
523 Err(error!(
524 "search_expression not supported through CborAdapter"
525 ))
526 }
527
528 fn clone_box(&self) -> Box<dyn TableLike<Value = CborValue, Id = String>> {
529 Box::new(self.clone())
530 }
531
532 fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
533 self
534 }
535
536 fn as_any_ref(&self) -> &dyn std::any::Any {
537 self
538 }
539
540 fn set_pagination(&mut self, pagination: Option<Pagination>) {
541 self.inner.set_pagination(pagination);
542 }
543
544 fn get_pagination(&self) -> Option<&Pagination> {
545 self.inner.pagination()
546 }
547
548 async fn get_count(&self) -> Result<i64> {
549 self.inner.data_source().get_table_count(&self.inner).await
550 }
551
552 fn get_ref(&self, relation: &str) -> Result<AnyTable> {
553 self.inner.get_ref(relation)
554 }
555}
556
557