Skip to main content

sql_fun_sqlast/sem/
from_clause.rs

1use sql_fun_core::IVec;
2
3use crate::{
4    sem::{
5        AliasSpec, AnalysisError, AnalysisProblem, DataSource, Nullable, ParseContext, WithClause,
6        create_table::ColumnName, data_source::AliasName,
7    },
8    syn::{ListOpt, ScanToken},
9};
10
11/// semantic representation for `FROM` clause
12#[derive(Debug, Clone, Default, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
13pub struct FromClause(Vec<DataSource>);
14
15impl FromClause {
16    /// add data source
17    pub fn push(&mut self, source: DataSource) {
18        self.0.push(source);
19    }
20
21    /// analyze from-cluse [`crate::syn::NodeListOpt`]
22    pub fn analyze<TParseContext>(
23        mut context: TParseContext,
24        with_clause: &WithClause,
25        syn: crate::syn::NodeListOpt,
26        tokens: &IVec<ScanToken>,
27    ) -> Result<(FromClause, TParseContext), AnalysisError>
28    where
29        TParseContext: ParseContext,
30    {
31        let Some(nodes) = syn.as_inner() else {
32            AnalysisError::raise_unexpected_none("from_clause.as_inner")?
33        };
34        let mut from_clause = FromClause::default();
35        let mut existing_aliases = Vec::new();
36
37        for node in nodes {
38            let (source, new_context) = DataSource::analyze_from_clause_node(
39                context,
40                with_clause,
41                &from_clause,
42                node,
43                tokens,
44            )?;
45            context = new_context;
46
47            let aliases = source.get_aliases();
48            for alias in aliases {
49                if existing_aliases.contains(&alias) {
50                    context.report_problem(AnalysisProblem::duplicate_alias(alias.name()))?;
51                }
52                existing_aliases.push(alias);
53            }
54            from_clause.push(source);
55        }
56        Ok((from_clause, context))
57    }
58
59    /// get data-source by alias name
60    #[must_use]
61    pub fn resolve_alias(&self, alias_name: &AliasName) -> Option<(&DataSource, Nullable)> {
62        for source in &self.0 {
63            if let Some(resolved) = source.resolve_alias(alias_name) {
64                return Some(resolved);
65            }
66        }
67        None
68    }
69
70    /// find alias name by column name
71    pub fn find_alias_for_column<TParseContext>(
72        &self,
73        column: &ColumnName,
74        context: &TParseContext,
75        with_clause: &WithClause,
76    ) -> Result<Option<AliasSpec>, Vec<AliasSpec>>
77    where
78        TParseContext: ParseContext,
79    {
80        let mut aliases = Vec::new();
81
82        for source in &self.0 {
83            let mut results = source.get_aliases_for_column(column, context, with_clause);
84            aliases.append(&mut results);
85        }
86
87        if aliases.is_empty() {
88            Ok(None)
89        } else if aliases.len() == 1 {
90            Ok(Some(aliases[0].clone()))
91        } else {
92            Err(aliases)
93        }
94    }
95}