1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use indexmap::IndexMap;
5use vantage_expressions::Expression;
6use vantage_types::{EmptyEntity, 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> =
22 Arc<dyn Fn(&Table<T, EmptyEntity>) -> Expression<<T as TableSource>::Value> + Send + Sync>;
23
24#[derive(Clone)]
25pub struct Table<T, E>
26where
27 T: TableSource,
28 E: Entity<T::Value>,
29{
30 pub(super) data_source: T,
31 pub(super) _phantom: PhantomData<E>,
32 pub(super) source: T::Source,
33 pub(super) columns: IndexMap<String, T::Column<T::AnyType>>,
34 pub(super) conditions: IndexMap<i64, T::Condition>,
35 pub(super) next_condition_id: i64,
36 pub(super) order_by: IndexMap<i64, (T::Condition, SortDirection)>,
37 pub(super) next_order_id: i64,
38 pub(super) refs: Option<IndexMap<String, Arc<dyn Reference>>>,
39 pub(super) contained: Vec<crate::references::ContainedRelation<T>>,
40 pub(super) expressions: IndexMap<String, ExpressionFn<T>>,
41 pub(super) pagination: Option<Pagination>,
42 pub(super) title_field: Option<String>,
43 pub(super) title_fields: Vec<String>,
44 pub(super) id_field: Option<String>,
45 pub(super) invariants: IndexMap<String, T::Value>,
53}
54
55impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
56 pub fn new(table_name: impl Into<String>, data_source: T) -> Self {
58 Self {
59 data_source,
60 _phantom: PhantomData,
61 source: T::Source::from_name(table_name.into()),
62 columns: IndexMap::new(),
63 conditions: IndexMap::new(),
64 next_condition_id: 1,
65 order_by: IndexMap::new(),
66 next_order_id: 1,
67 refs: None,
68 contained: Vec::new(),
69 expressions: IndexMap::new(),
70 pagination: None,
71 title_field: None,
72 title_fields: Vec::new(),
73 id_field: None,
74 invariants: IndexMap::new(),
75 }
76 }
77
78 pub fn into_entity<E2: Entity<T::Value>>(self) -> Table<T, E2> {
84 Table {
85 data_source: self.data_source,
86 _phantom: PhantomData,
87 source: self.source,
88 columns: self.columns,
89 conditions: self.conditions,
90 next_condition_id: self.next_condition_id,
91 order_by: self.order_by,
92 next_order_id: self.next_order_id,
93 refs: self.refs,
94 contained: self.contained,
95 expressions: self.expressions,
96 pagination: self.pagination,
97 title_field: self.title_field,
98 title_fields: self.title_fields,
99 id_field: self.id_field,
100 invariants: self.invariants,
101 }
102 }
103
104 pub(crate) fn as_entity_erased(&self) -> &Table<T, EmptyEntity> {
111 unsafe { &*(self as *const Table<T, E> as *const Table<T, EmptyEntity>) }
114 }
115
116 pub fn vista_references(&self) -> Vec<vantage_vista::Reference> {
121 self.refs
122 .as_ref()
123 .map(|refs| {
124 refs.iter()
125 .map(|(name, r)| {
126 vantage_vista::Reference::new(
127 name.clone(),
128 r.target_type_name().to_string(),
129 r.cardinality(),
130 r.foreign_key().to_string(),
131 )
132 })
133 .collect()
134 })
135 .unwrap_or_default()
136 }
137
138 pub fn vista_contained(&self) -> Vec<vantage_vista::ContainedSpec> {
143 self.contained.iter().map(|c| c.spec()).collect()
144 }
145
146 pub fn contained_relation(
148 &self,
149 name: &str,
150 ) -> Option<&crate::references::ContainedRelation<T>> {
151 self.contained.iter().find(|c| c.name() == name)
152 }
153
154 pub fn with<F>(mut self, func: F) -> Self
156 where
157 F: FnOnce(&mut Self),
158 {
159 func(&mut self);
160 self
161 }
162
163 pub fn table_name(&self) -> &str {
167 self.source.name()
168 }
169
170 pub fn source(&self) -> &T::Source {
172 &self.source
173 }
174
175 pub fn set_table_name(&mut self, name: impl Into<String>) {
182 self.source = T::Source::from_name(name.into());
183 }
184
185 pub fn data_source(&self) -> &T {
187 &self.data_source
188 }
189
190 pub fn title_field(&self) -> Option<&T::Column<T::AnyType>> {
192 self.title_field
193 .as_ref()
194 .and_then(|name| self.columns.get(name))
195 }
196
197 pub fn title_fields(&self) -> &[String] {
201 &self.title_fields
202 }
203
204 pub fn id_field(&self) -> Option<&T::Column<T::AnyType>> {
206 self.id_field
207 .as_ref()
208 .and_then(|name| self.columns.get(name))
209 }
210
211 pub fn set_id_field(&mut self, name: impl Into<String>) {
218 self.id_field = Some(name.into());
219 }
220
221 pub fn add_title_field(&mut self, name: impl Into<String>) {
225 let name = name.into();
226 if !self.title_fields.contains(&name) {
227 self.title_fields.push(name.clone());
228 }
229 if self.title_field.is_none() {
230 self.title_field = Some(name);
231 }
232 }
233
234 pub fn pagination(&self) -> Option<&Pagination> {
236 self.pagination.as_ref()
237 }
238
239 pub fn invariants(&self) -> &IndexMap<String, T::Value> {
243 &self.invariants
244 }
245
246 pub fn add_invariant(&mut self, column: impl Into<String>, value: T::Value) {
250 self.invariants.insert(column.into(), value);
251 }
252
253 pub fn with_invariant(mut self, column: impl Into<String>, value: T::Value) -> Self {
255 self.add_invariant(column, value);
256 self
257 }
258}
259
260impl<T: TableSource, E: Entity<T::Value>> std::ops::Index<&str> for Table<T, E> {
261 type Output = T::Column<T::AnyType>;
262
263 fn index(&self, index: &str) -> &Self::Output {
264 &self.columns[index]
265 }
266}
267
268impl<T: TableSource, E: Entity<T::Value>> std::fmt::Debug for Table<T, E> {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 f.debug_struct("Table")
271 .field("table_name", &self.table_name())
272 .field("columns", &self.columns.keys().collect::<Vec<_>>())
273 .field("conditions_count", &self.conditions.len())
274 .field(
275 "refs_count",
276 &self.refs.as_ref().map(|r| r.len()).unwrap_or(0),
277 )
278 .field("expressions_count", &self.expressions.len())
279 .finish()
280 }
281}