toasty_core/stmt/
source.rs

1use super::{Association, SourceTable, SourceTableId, TableFactor, TableRef, TableWithJoins};
2use crate::{
3    schema::{
4        app::{ModelId, ModelRoot},
5        db::TableId,
6    },
7    stmt::ExprArg,
8};
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum Source {
12    /// Source is a model
13    Model(SourceModel),
14
15    /// Source is a database table (lowered)
16    Table(SourceTable),
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub struct SourceModel {
21    /// The source model
22    pub model: ModelId,
23
24    /// Selecting via an association
25    pub via: Option<Association>,
26}
27
28impl Source {
29    /// Create a source from a table with joins, providing explicit table refs
30    pub fn table_with_joins(tables: Vec<TableRef>, from_item: TableWithJoins) -> Self {
31        let source_table = SourceTable::new(tables, from_item);
32        Self::Table(source_table)
33    }
34
35    pub fn is_model(&self) -> bool {
36        matches!(self, Self::Model(_))
37    }
38
39    pub fn as_model(&self) -> Option<&SourceModel> {
40        match self {
41            Self::Model(source) => Some(source),
42            _ => None,
43        }
44    }
45
46    #[track_caller]
47    pub fn as_model_unwrap(&self) -> &SourceModel {
48        self.as_model()
49            .expect("expected SourceModel; actual={self:#?}")
50    }
51
52    pub fn model_id(&self) -> Option<ModelId> {
53        self.as_model().map(|source_model| source_model.model)
54    }
55
56    pub fn model_id_unwrap(&self) -> ModelId {
57        self.as_model_unwrap().model
58    }
59
60    pub fn is_table(&self) -> bool {
61        matches!(self, Self::Table(_))
62    }
63
64    pub fn table(table: impl Into<TableRef>) -> Self {
65        let table_ref = table.into();
66        let source_table = SourceTable::new(
67            vec![table_ref],
68            TableWithJoins {
69                relation: TableFactor::Table(SourceTableId(0)),
70                joins: vec![],
71            },
72        );
73        Self::Table(source_table)
74    }
75
76    pub fn as_source_table(&self) -> &SourceTable {
77        match self {
78            Self::Table(source) => source,
79            _ => todo!(),
80        }
81    }
82}
83
84impl From<&ModelRoot> for Source {
85    fn from(value: &ModelRoot) -> Self {
86        Self::from(value.id)
87    }
88}
89
90impl From<ModelId> for Source {
91    fn from(value: ModelId) -> Self {
92        Self::Model(SourceModel {
93            model: value,
94            via: None,
95        })
96    }
97}
98
99impl From<TableId> for Source {
100    fn from(value: TableId) -> Self {
101        Self::table(value)
102    }
103}
104
105impl From<TableRef> for Source {
106    fn from(value: TableRef) -> Self {
107        Self::table(value)
108    }
109}
110
111impl From<ExprArg> for Source {
112    fn from(value: ExprArg) -> Self {
113        Source::Table(SourceTable::from(value))
114    }
115}