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,
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) table_name: String,
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 table_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 table_name: self.table_name,
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 {
132 &self.table_name
133 }
134
135 pub fn set_table_name(&mut self, name: impl Into<String>) {
139 self.table_name = name.into();
140 }
141
142 pub fn data_source(&self) -> &T {
144 &self.data_source
145 }
146
147 pub(crate) fn conditions_mut(&mut self) -> &mut IndexMap<i64, T::Condition> {
149 &mut self.conditions
150 }
151
152 pub(crate) fn next_condition_id_mut(&mut self) -> &mut i64 {
154 &mut self.next_condition_id
155 }
156
157 pub fn title_field(&self) -> Option<&T::Column<T::AnyType>> {
159 self.title_field
160 .as_ref()
161 .and_then(|name| self.columns.get(name))
162 }
163
164 pub fn title_fields(&self) -> &[String] {
168 &self.title_fields
169 }
170
171 pub fn id_field(&self) -> Option<&T::Column<T::AnyType>> {
173 self.id_field
174 .as_ref()
175 .and_then(|name| self.columns.get(name))
176 }
177
178 pub fn set_id_field(&mut self, name: impl Into<String>) {
185 self.id_field = Some(name.into());
186 }
187
188 pub fn add_title_field(&mut self, name: impl Into<String>) {
192 let name = name.into();
193 if !self.title_fields.contains(&name) {
194 self.title_fields.push(name.clone());
195 }
196 if self.title_field.is_none() {
197 self.title_field = Some(name);
198 }
199 }
200
201 pub fn pagination(&self) -> Option<&Pagination> {
203 self.pagination.as_ref()
204 }
205}
206
207impl<T: TableSource, E: Entity<T::Value>> std::ops::Index<&str> for Table<T, E> {
208 type Output = T::Column<T::AnyType>;
209
210 fn index(&self, index: &str) -> &Self::Output {
211 &self.columns[index]
212 }
213}
214
215impl<T: TableSource, E: Entity<T::Value>> std::fmt::Debug for Table<T, E> {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 f.debug_struct("Table")
218 .field("table_name", &self.table_name)
219 .field("columns", &self.columns.keys().collect::<Vec<_>>())
220 .field("conditions_count", &self.conditions.len())
221 .field(
222 "refs_count",
223 &self.refs.as_ref().map(|r| r.len()).unwrap_or(0),
224 )
225 .field("expressions_count", &self.expressions.len())
226 .finish()
227 }
228}