sqltk_parser/ast/helpers/
stmt_data_loading.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to loading and unloading syntax, like one available in Snowflake which
19//! contains: STAGE ddl operations, PUT upload or COPY INTO
20//! See [this page](https://docs.snowflake.com/en/sql-reference/commands-data-loading) for more details.
21
22#[cfg(not(feature = "std"))]
23use alloc::string::String;
24#[cfg(not(feature = "std"))]
25use alloc::vec::Vec;
26use core::fmt;
27use core::fmt::Formatter;
28
29#[cfg(feature = "serde")]
30use serde::{Deserialize, Serialize};
31
32use crate::ast::Ident;
33#[cfg(feature = "visitor")]
34use sqltk_parser_derive::{Visit, VisitMut};
35
36#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
39pub struct StageParamsObject {
40    pub url: Option<String>,
41    pub encryption: DataLoadingOptions,
42    pub endpoint: Option<String>,
43    pub storage_integration: Option<String>,
44    pub credentials: DataLoadingOptions,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
50pub struct DataLoadingOptions {
51    pub options: Vec<DataLoadingOption>,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
57pub enum DataLoadingOptionType {
58    STRING,
59    BOOLEAN,
60    ENUM,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
66pub struct DataLoadingOption {
67    pub option_name: String,
68    pub option_type: DataLoadingOptionType,
69    pub value: String,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
75pub struct StageLoadSelectItem {
76    pub alias: Option<Ident>,
77    pub file_col_num: i32,
78    pub element: Option<Ident>,
79    pub item_as: Option<Ident>,
80}
81
82impl fmt::Display for StageParamsObject {
83    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84        let url = &self.url.as_ref();
85        let storage_integration = &self.storage_integration.as_ref();
86        let endpoint = &self.endpoint.as_ref();
87
88        if url.is_some() {
89            write!(f, " URL='{}'", url.unwrap())?;
90        }
91        if storage_integration.is_some() {
92            write!(f, " STORAGE_INTEGRATION={}", storage_integration.unwrap())?;
93        }
94        if endpoint.is_some() {
95            write!(f, " ENDPOINT='{}'", endpoint.unwrap())?;
96        }
97        if !self.credentials.options.is_empty() {
98            write!(f, " CREDENTIALS=({})", self.credentials)?;
99        }
100        if !self.encryption.options.is_empty() {
101            write!(f, " ENCRYPTION=({})", self.encryption)?;
102        }
103
104        Ok(())
105    }
106}
107
108impl fmt::Display for DataLoadingOptions {
109    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
110        if !self.options.is_empty() {
111            let mut first = false;
112            for option in &self.options {
113                if !first {
114                    first = true;
115                } else {
116                    f.write_str(" ")?;
117                }
118                write!(f, "{}", option)?;
119            }
120        }
121        Ok(())
122    }
123}
124
125impl fmt::Display for DataLoadingOption {
126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127        match self.option_type {
128            DataLoadingOptionType::STRING => {
129                write!(f, "{}='{}'", self.option_name, self.value)?;
130            }
131            DataLoadingOptionType::ENUM => {
132                // single quote is omitted
133                write!(f, "{}={}", self.option_name, self.value)?;
134            }
135            DataLoadingOptionType::BOOLEAN => {
136                // single quote is omitted
137                write!(f, "{}={}", self.option_name, self.value)?;
138            }
139        }
140        Ok(())
141    }
142}
143
144impl fmt::Display for StageLoadSelectItem {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        if self.alias.is_some() {
147            write!(f, "{}.", self.alias.as_ref().unwrap())?;
148        }
149        write!(f, "${}", self.file_col_num)?;
150        if self.element.is_some() {
151            write!(f, ":{}", self.element.as_ref().unwrap())?;
152        }
153        if self.item_as.is_some() {
154            write!(f, " AS {}", self.item_as.as_ref().unwrap())?;
155        }
156        Ok(())
157    }
158}