vantage_table/references/
foreign.rs1use std::{any::Any, marker::PhantomData, sync::Arc};
9
10use vantage_core::Result;
11use vantage_types::Entity;
12
13use crate::{
14 any::AnyTable, references::Reference, table::Table, traits::table_source::TableSource,
15};
16
17type ResolveFn<T, E> = dyn Fn(&Table<T, E>) -> Result<AnyTable> + Send + Sync;
18
19pub struct HasForeign<T: TableSource, SourceE: Entity<T::Value>> {
20 resolve: Arc<ResolveFn<T, SourceE>>,
22 target_type: &'static str,
24 _phantom: PhantomData<(T, SourceE)>,
25}
26
27impl<T: TableSource + 'static, SourceE: Entity<T::Value> + 'static> HasForeign<T, SourceE> {
28 pub fn new(
29 target_type: &'static str,
30 resolve: impl Fn(&Table<T, SourceE>) -> Result<AnyTable> + Send + Sync + 'static,
31 ) -> Self {
32 Self {
33 resolve: Arc::new(resolve),
34 target_type,
35 _phantom: PhantomData,
36 }
37 }
38}
39
40impl<T: TableSource, SourceE: Entity<T::Value>> Clone for HasForeign<T, SourceE> {
41 fn clone(&self) -> Self {
42 Self {
43 resolve: self.resolve.clone(),
44 target_type: self.target_type,
45 _phantom: PhantomData,
46 }
47 }
48}
49
50impl<T: TableSource, SourceE: Entity<T::Value>> std::fmt::Debug for HasForeign<T, SourceE> {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 f.debug_struct("HasForeign")
53 .field("target_type", &self.target_type)
54 .finish()
55 }
56}
57
58impl<T: TableSource + 'static, SourceE: Entity<T::Value> + 'static> Reference
59 for HasForeign<T, SourceE>
60{
61 fn columns(&self, _source_id: &str, _target_id: &str) -> (String, String) {
62 unreachable!("columns() should not be called on foreign references")
63 }
64
65 fn build_target(&self, _data_source: &dyn Any) -> Box<dyn Any> {
66 unreachable!("build_target() should not be called on foreign references")
67 }
68
69 fn is_foreign(&self) -> bool {
70 true
71 }
72
73 fn resolve_as_any(&self, source_table: &dyn Any) -> Result<AnyTable> {
74 let source = source_table
75 .downcast_ref::<Table<T, SourceE>>()
76 .ok_or_else(|| {
77 vantage_core::error!("Source table type mismatch in HasForeign::resolve_as_any")
78 })?;
79 (self.resolve)(source)
80 }
81
82 fn target_type_name(&self) -> &'static str {
83 self.target_type
84 }
85}