Skip to main content

sql_fun_sqlast/sem/
create_view.rs

1use sql_fun_core::IVec;
2
3use crate::{
4    sem::{
5        AlterView, AstAndContextPair,
6        alter_table::AlterObjSubCommand,
7        create_table::{ColumnDefinition, ColumnName},
8    },
9    syn::{Opt, ScanToken},
10};
11
12use super::{AnalysisError, FullName, ParseContext, SelectStatement, SemAst, analyze_select};
13
14/// analyzed [`crate::syn::ViewStmt`]
15#[derive(Debug, Clone)]
16pub struct CreateView {
17    name: FullName,
18    query: SelectStatement,
19    alter_statements: Vec<AlterView>,
20    owner: Option<String>,
21    materialized: bool,
22}
23
24impl CreateView {
25    /// create instance
26    #[must_use]
27    pub fn new(
28        name: &FullName,
29        query: &SelectStatement,
30        alter_statements: &[AlterView],
31        owner: &Option<String>,
32        materialized: bool,
33    ) -> Self {
34        Self {
35            name: name.clone(),
36            query: query.clone(),
37            alter_statements: alter_statements.to_owned(),
38            owner: owner.clone(),
39            materialized,
40        }
41    }
42
43    /// name of view
44    #[must_use]
45    pub fn name(&self) -> &FullName {
46        &self.name
47    }
48
49    /// get result set column
50    #[must_use]
51    pub fn get_column_def(&self, column_name: &ColumnName) -> Option<ColumnDefinition> {
52        self.query.get_result_column_def(column_name)
53    }
54
55    /// test column existing
56    #[must_use]
57    pub fn has_column(&self, column: &ColumnName) -> bool {
58        self.query.has_column(column)
59    }
60
61    /// apply `ALTER VIEW`
62    pub fn apply_alter(&mut self, alter_view: &AlterView) -> Result<(), AnalysisError> {
63        self.alter_statements.push(alter_view.clone());
64
65        for cmd in alter_view.commands() {
66            match cmd {
67                AlterObjSubCommand::ChangeOwner(new_owner) => self.owner = Some(new_owner.clone()),
68                _ => todo!(),
69            }
70        }
71
72        Ok(())
73    }
74
75    /// view is materialized
76    #[must_use]
77    pub fn is_materialized(&self) -> bool {
78        self.materialized
79    }
80}
81
82/// analyze [`crate::syn::ViewStmt`]
83#[tracing::instrument(skip(context))]
84pub fn analyze_create_view<TParseContext>(
85    context: TParseContext,
86    parent_schema: &Option<String>,
87    syn: crate::syn::ViewStmt,
88    tokens: &IVec<ScanToken>,
89) -> Result<AstAndContextPair<TParseContext>, AnalysisError>
90where
91    TParseContext: ParseContext,
92{
93    let Some(view) = syn.get_view().as_inner() else {
94        AnalysisError::raise_unexpected_none("view_stmt.view")?
95    };
96    let _materialized = syn.get_options();
97
98    let Some(query) = syn.get_query().as_select_stmt().as_inner() else {
99        AnalysisError::raise_unexpected_none("view_stmt.query")?
100    };
101
102    let AstAndContextPair(select, context) = analyze_select(context, query, tokens)?;
103    let SemAst::SelectStatement(stmt) = select else {
104        AnalysisError::raise_unexpected_none("select_statement")?
105    };
106    let name = FullName::try_from(view)?;
107    let create_view = CreateView::new(&name, &stmt, &[], &Default::default(), false);
108    let context = context.apply_create_view(&create_view)?;
109    Ok(AstAndContextPair::new(
110        SemAst::CreateView(create_view),
111        context,
112    ))
113}