vantage_table/table/impls/
references.rs1use std::sync::Arc;
4
5use indexmap::IndexMap;
6use vantage_core::{Result, error};
7use vantage_types::Entity;
8
9use crate::{
10 references::{HasMany, HasOne, Reference},
11 table::Table,
12 traits::table_source::TableSource,
13};
14
15mod contained;
16mod traversal;
17
18impl<T: TableSource + 'static, E: Entity<T::Value> + 'static> Table<T, E> {
19 pub fn with_one<E2: Entity<T::Value> + 'static>(
25 mut self,
26 relation: &str,
27 foreign_key: &str,
28 build_target: impl Fn(T) -> Table<T, E2> + Send + Sync + 'static,
29 ) -> Self
30 where
31 T::Value: Into<ciborium::Value> + From<ciborium::Value>,
32 T::Id: std::fmt::Display + From<String>,
33 {
34 let reference = HasOne::<T, E, E2>::new(foreign_key, build_target);
35 self.add_ref(relation, Box::new(reference));
36 self
37 }
38
39 pub fn with_many<E2: Entity<T::Value> + 'static>(
45 mut self,
46 relation: &str,
47 foreign_key: &str,
48 build_target: impl Fn(T) -> Table<T, E2> + Send + Sync + 'static,
49 ) -> Self
50 where
51 T::Value: Into<ciborium::Value> + From<ciborium::Value>,
52 T::Id: std::fmt::Display + From<String>,
53 {
54 let reference = HasMany::<T, E, E2>::new(foreign_key, build_target);
55 self.add_ref(relation, Box::new(reference));
56 self
57 }
58
59 pub(crate) fn add_ref(&mut self, relation: &str, reference: Box<dyn Reference>) {
60 self.add_ref_arc(relation, Arc::from(reference));
61 }
62
63 pub(crate) fn add_ref_arc(&mut self, relation: &str, reference: Arc<dyn Reference>) {
66 self.refs
67 .get_or_insert_with(IndexMap::new)
68 .insert(relation.to_string(), reference);
69 }
70
71 pub fn copy_relations_from<E2: Entity<T::Value> + 'static>(
76 &mut self,
77 other: &Table<T, E2>,
78 names: Option<&[&str]>,
79 ) {
80 let Some(refs) = &other.refs else {
81 return;
82 };
83 for (name, reference) in refs {
84 if names.is_some_and(|ns| !ns.contains(&name.as_str())) {
85 continue;
86 }
87 self.add_ref_arc(name, reference.clone());
88 }
89 }
90
91 pub fn references(&self) -> Vec<String> {
92 self.refs
93 .as_ref()
94 .map(|refs| refs.keys().cloned().collect())
95 .unwrap_or_default()
96 }
97
98 fn lookup_ref(&self, relation: &str) -> Result<&dyn Reference> {
99 let table_name = self.table_name();
100 let refs = self
101 .refs
102 .as_ref()
103 .ok_or_else(|| error!("No references defined on table", table = table_name))?;
104
105 let reference = refs.get(relation).ok_or_else(|| {
106 error!(
107 "Reference not found on table",
108 relation = relation,
109 table = table_name
110 )
111 })?;
112
113 Ok(reference.as_ref())
114 }
115
116 fn ref_shape(&self, relation: &str) -> Result<vantage_vista::Reference> {
121 let reference = self.lookup_ref(relation)?;
122 Ok(reference.vista_reference(relation, String::new(), &self.id_field_name()))
123 }
124
125 pub fn ref_cardinality(&self, relation: &str) -> Result<vantage_vista::ReferenceKind> {
127 Ok(self.ref_shape(relation)?.kind)
128 }
129
130 pub fn ref_foreign_key(&self, relation: &str) -> Result<String> {
136 let shape = self.ref_shape(relation)?;
137 let key = shape
138 .keys
139 .first()
140 .ok_or_else(|| error!("Reference has no join key", relation = relation))?;
141 Ok(match shape.kind {
142 vantage_vista::ReferenceKind::HasMany => key.to.clone().unwrap_or_default(),
143 _ => key.from.clone(),
144 })
145 }
146
147 pub fn ref_kinds(&self) -> Vec<(String, vantage_vista::ReferenceKind)> {
149 let Some(refs) = &self.refs else {
150 return Vec::new();
151 };
152 let source_id = self.id_field_name();
153 refs.iter()
154 .map(|(name, r)| {
155 let kind = r.vista_reference(name, String::new(), &source_id).kind;
156 (name.clone(), kind)
157 })
158 .collect()
159 }
160}