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