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, table::hooks::Hooks,
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 pub(super) hooks: Hooks<T>,
55}
56
57impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
58 pub fn new(table_name: impl Into<String>, data_source: T) -> Self {
60 Self {
61 data_source,
62 _phantom: PhantomData,
63 source: T::Source::from_name(table_name.into()),
64 columns: IndexMap::new(),
65 conditions: IndexMap::new(),
66 next_condition_id: 1,
67 order_by: IndexMap::new(),
68 next_order_id: 1,
69 refs: None,
70 contained: Vec::new(),
71 expressions: IndexMap::new(),
72 pagination: None,
73 title_field: None,
74 title_fields: Vec::new(),
75 id_field: None,
76 invariants: IndexMap::new(),
77 hooks: Hooks::default(),
78 }
79 }
80
81 pub fn into_entity<E2: Entity<T::Value>>(self) -> Table<T, E2> {
87 Table {
88 data_source: self.data_source,
89 _phantom: PhantomData,
90 source: self.source,
91 columns: self.columns,
92 conditions: self.conditions,
93 next_condition_id: self.next_condition_id,
94 order_by: self.order_by,
95 next_order_id: self.next_order_id,
96 refs: self.refs,
97 contained: self.contained,
98 expressions: self.expressions,
99 pagination: self.pagination,
100 title_field: self.title_field,
101 title_fields: self.title_fields,
102 id_field: self.id_field,
103 invariants: self.invariants,
104 hooks: self.hooks,
105 }
106 }
107
108 pub(crate) fn as_entity_erased(&self) -> &Table<T, EmptyEntity> {
115 unsafe { &*(self as *const Table<T, E> as *const Table<T, EmptyEntity>) }
118 }
119
120 pub fn vista_references(&self) -> Vec<vantage_vista::Reference> {
125 self.refs
126 .as_ref()
127 .map(|refs| {
128 refs.iter()
129 .map(|(name, r)| {
130 vantage_vista::Reference::new(
131 name.clone(),
132 r.target_type_name().to_string(),
133 r.cardinality(),
134 r.foreign_key().to_string(),
135 )
136 })
137 .collect()
138 })
139 .unwrap_or_default()
140 }
141
142 pub fn vista_contained(&self) -> Vec<vantage_vista::ContainedSpec> {
147 self.contained.iter().map(|c| c.spec()).collect()
148 }
149
150 pub fn contained_relation(
152 &self,
153 name: &str,
154 ) -> Option<&crate::references::ContainedRelation<T>> {
155 self.contained.iter().find(|c| c.name() == name)
156 }
157
158 pub fn with<F>(mut self, func: F) -> Self
160 where
161 F: FnOnce(&mut Self),
162 {
163 func(&mut self);
164 self
165 }
166
167 pub fn table_name(&self) -> &str {
171 self.source.name()
172 }
173
174 pub fn source(&self) -> &T::Source {
176 &self.source
177 }
178
179 pub fn set_table_name(&mut self, name: impl Into<String>) {
186 self.source = T::Source::from_name(name.into());
187 }
188
189 pub fn data_source(&self) -> &T {
191 &self.data_source
192 }
193
194 pub fn title_field(&self) -> Option<&T::Column<T::AnyType>> {
196 self.title_field
197 .as_ref()
198 .and_then(|name| self.columns.get(name))
199 }
200
201 pub fn title_fields(&self) -> &[String] {
205 &self.title_fields
206 }
207
208 pub fn id_field(&self) -> Option<&T::Column<T::AnyType>> {
210 self.id_field
211 .as_ref()
212 .and_then(|name| self.columns.get(name))
213 }
214
215 pub fn set_id_field(&mut self, name: impl Into<String>) {
222 self.id_field = Some(name.into());
223 }
224
225 pub fn add_title_field(&mut self, name: impl Into<String>) {
229 let name = name.into();
230 if !self.title_fields.contains(&name) {
231 self.title_fields.push(name.clone());
232 }
233 if self.title_field.is_none() {
234 self.title_field = Some(name);
235 }
236 }
237
238 pub fn pagination(&self) -> Option<&Pagination> {
240 self.pagination.as_ref()
241 }
242
243 pub fn invariants(&self) -> &IndexMap<String, T::Value> {
247 &self.invariants
248 }
249
250 pub fn add_invariant(&mut self, column: impl Into<String>, value: T::Value) {
254 self.invariants.insert(column.into(), value);
255 }
256
257 pub fn with_invariant(mut self, column: impl Into<String>, value: T::Value) -> Self {
259 self.add_invariant(column, value);
260 self
261 }
262}
263
264impl<T: TableSource, E: Entity<T::Value>> std::ops::Index<&str> for Table<T, E> {
265 type Output = T::Column<T::AnyType>;
266
267 fn index(&self, index: &str) -> &Self::Output {
268 &self.columns[index]
269 }
270}
271
272impl<T: TableSource, E: Entity<T::Value>> std::fmt::Debug for Table<T, E> {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 f.debug_struct("Table")
275 .field("table_name", &self.table_name())
276 .field("columns", &self.columns.keys().collect::<Vec<_>>())
277 .field("conditions_count", &self.conditions.len())
278 .field(
279 "refs_count",
280 &self.refs.as_ref().map(|r| r.len()).unwrap_or(0),
281 )
282 .field("expressions_count", &self.expressions.len())
283 .finish()
284 }
285}