1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use indexmap::IndexMap;
5use vantage_expressions::Expression;
6use vantage_types::Entity;
7
8use crate::{
9 pagination::Pagination, references::Reference, sorting::SortDirection,
10 traits::table_source::TableSource, traits::table_source_spec::TableSourceSpec,
11};
12
13pub type ExpressionFn<T, E> =
15 Arc<dyn Fn(&Table<T, E>) -> Expression<<T as TableSource>::Value> + Send + Sync>;
16
17#[derive(Clone)]
18pub struct Table<T, E>
19where
20 T: TableSource,
21 E: Entity<T::Value>,
22{
23 pub(super) data_source: T,
24 pub(super) _phantom: PhantomData<E>,
25 pub(super) source: T::Source,
26 pub(super) columns: IndexMap<String, T::Column<T::AnyType>>,
27 pub(super) conditions: IndexMap<i64, T::Condition>,
28 pub(super) next_condition_id: i64,
29 pub(super) order_by: IndexMap<i64, (T::Condition, SortDirection)>,
30 pub(super) next_order_id: i64,
31 pub(super) refs: Option<IndexMap<String, Arc<dyn Reference>>>,
32 pub(super) contained: Vec<crate::references::ContainedRelation<T>>,
33 pub(super) expressions: IndexMap<String, ExpressionFn<T, E>>,
34 pub(super) pagination: Option<Pagination>,
35 pub(super) title_field: Option<String>,
36 pub(super) title_fields: Vec<String>,
37 pub(super) id_field: Option<String>,
38}
39
40impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
41 pub fn new(table_name: impl Into<String>, data_source: T) -> Self {
43 Self {
44 data_source,
45 _phantom: PhantomData,
46 source: T::Source::from_name(table_name.into()),
47 columns: IndexMap::new(),
48 conditions: IndexMap::new(),
49 next_condition_id: 1,
50 order_by: IndexMap::new(),
51 next_order_id: 1,
52 refs: None,
53 contained: Vec::new(),
54 expressions: IndexMap::new(),
55 pagination: None,
56 title_field: None,
57 title_fields: Vec::new(),
58 id_field: None,
59 }
60 }
61
62 pub fn into_entity<E2: Entity<T::Value>>(self) -> Table<T, E2> {
64 Table {
65 data_source: self.data_source,
66 _phantom: PhantomData,
67 source: self.source,
68 columns: self.columns,
69 conditions: self.conditions,
70 next_condition_id: self.next_condition_id,
71 order_by: self.order_by,
72 next_order_id: self.next_order_id,
73 refs: self.refs,
74 contained: self.contained,
75 expressions: IndexMap::new(),
76 pagination: self.pagination,
77 title_field: self.title_field,
78 title_fields: self.title_fields,
79 id_field: self.id_field,
80 }
81 }
82
83 pub fn vista_references(&self) -> Vec<vantage_vista::Reference> {
88 self.refs
89 .as_ref()
90 .map(|refs| {
91 refs.iter()
92 .map(|(name, r)| {
93 vantage_vista::Reference::new(
94 name.clone(),
95 r.target_type_name().to_string(),
96 r.cardinality(),
97 r.foreign_key().to_string(),
98 )
99 })
100 .collect()
101 })
102 .unwrap_or_default()
103 }
104
105 pub fn vista_contained(&self) -> Vec<vantage_vista::ContainedSpec> {
110 self.contained.iter().map(|c| c.spec()).collect()
111 }
112
113 pub fn contained_relation(
115 &self,
116 name: &str,
117 ) -> Option<&crate::references::ContainedRelation<T>> {
118 self.contained.iter().find(|c| c.name() == name)
119 }
120
121 pub fn with<F>(mut self, func: F) -> Self
123 where
124 F: FnOnce(&mut Self),
125 {
126 func(&mut self);
127 self
128 }
129
130 pub fn table_name(&self) -> &str {
134 self.source.name()
135 }
136
137 pub fn source(&self) -> &T::Source {
139 &self.source
140 }
141
142 pub fn set_table_name(&mut self, name: impl Into<String>) {
149 self.source = T::Source::from_name(name.into());
150 }
151
152 pub fn data_source(&self) -> &T {
154 &self.data_source
155 }
156
157 pub(crate) fn conditions_mut(&mut self) -> &mut IndexMap<i64, T::Condition> {
159 &mut self.conditions
160 }
161
162 pub(crate) fn next_condition_id_mut(&mut self) -> &mut i64 {
164 &mut self.next_condition_id
165 }
166
167 pub fn title_field(&self) -> Option<&T::Column<T::AnyType>> {
169 self.title_field
170 .as_ref()
171 .and_then(|name| self.columns.get(name))
172 }
173
174 pub fn title_fields(&self) -> &[String] {
178 &self.title_fields
179 }
180
181 pub fn id_field(&self) -> Option<&T::Column<T::AnyType>> {
183 self.id_field
184 .as_ref()
185 .and_then(|name| self.columns.get(name))
186 }
187
188 pub fn set_id_field(&mut self, name: impl Into<String>) {
195 self.id_field = Some(name.into());
196 }
197
198 pub fn add_title_field(&mut self, name: impl Into<String>) {
202 let name = name.into();
203 if !self.title_fields.contains(&name) {
204 self.title_fields.push(name.clone());
205 }
206 if self.title_field.is_none() {
207 self.title_field = Some(name);
208 }
209 }
210
211 pub fn pagination(&self) -> Option<&Pagination> {
213 self.pagination.as_ref()
214 }
215}
216
217impl<T: TableSource, E: Entity<T::Value>> std::ops::Index<&str> for Table<T, E> {
218 type Output = T::Column<T::AnyType>;
219
220 fn index(&self, index: &str) -> &Self::Output {
221 &self.columns[index]
222 }
223}
224
225impl<T: TableSource, E: Entity<T::Value>> std::fmt::Debug for Table<T, E> {
226 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227 f.debug_struct("Table")
228 .field("table_name", &self.table_name())
229 .field("columns", &self.columns.keys().collect::<Vec<_>>())
230 .field("conditions_count", &self.conditions.len())
231 .field(
232 "refs_count",
233 &self.refs.as_ref().map(|r| r.len()).unwrap_or(0),
234 )
235 .field("expressions_count", &self.expressions.len())
236 .finish()
237 }
238}