Skip to main content

databend_common_ast/ast/
common.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16use std::fmt::Formatter;
17
18use derive_visitor::Drive;
19use derive_visitor::DriveMut;
20use ethnum::i256;
21
22use super::quote::QuotedString;
23use crate::Span;
24use crate::ast::quote::QuotedIdent;
25
26// Identifier of table name or column name.
27#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
28pub struct Identifier {
29    pub span: Span,
30    pub name: String,
31    pub quote: Option<char>,
32    #[drive(skip)]
33    pub ident_type: IdentifierType,
34}
35
36#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
37pub enum IdentifierType {
38    #[default]
39    None,
40    Hole,
41    Variable,
42}
43
44impl Identifier {
45    pub fn is_quoted(&self) -> bool {
46        self.quote.is_some()
47    }
48
49    pub fn is_hole(&self) -> bool {
50        self.ident_type == IdentifierType::Hole
51    }
52
53    pub fn is_variable(&self) -> bool {
54        self.ident_type == IdentifierType::Variable
55    }
56
57    pub fn from_name(span: Span, name: impl Into<String>) -> Self {
58        Self {
59            span,
60            name: name.into(),
61            quote: None,
62            ident_type: IdentifierType::None,
63        }
64    }
65
66    pub fn from_name_with_quoted(span: Span, name: impl Into<String>, quote: Option<char>) -> Self {
67        Self {
68            span,
69            name: name.into(),
70            quote,
71            ident_type: IdentifierType::None,
72        }
73    }
74}
75
76impl Display for Identifier {
77    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
78        if self.is_hole() {
79            write!(f, "IDENTIFIER(:{})", self.name)
80        } else if self.is_variable() {
81            write!(f, "IDENTIFIER(${})", self.name)
82        } else if let Some(quote) = self.quote {
83            write!(f, "{}", QuotedIdent(&self.name, quote))
84        } else {
85            write!(f, "{}", self.name)
86        }
87    }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
91pub struct ColumnPosition {
92    pub span: Span,
93    pub pos: usize,
94    pub name: String,
95}
96
97impl ColumnPosition {
98    pub fn create(span: Span, pos: usize) -> ColumnPosition {
99        ColumnPosition {
100            pos,
101            name: format!("${}", pos),
102            span,
103        }
104    }
105    pub fn name(&self) -> String {
106        format!("${}", self.pos)
107    }
108}
109
110impl Display for ColumnPosition {
111    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
112        write!(f, "${}", self.pos)
113    }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
117pub enum ColumnID {
118    Name(Identifier),
119    Position(ColumnPosition),
120}
121
122impl ColumnID {
123    pub fn name(&self) -> &str {
124        match self {
125            ColumnID::Name(id) => &id.name,
126            ColumnID::Position(id) => &id.name,
127        }
128    }
129}
130
131impl Display for ColumnID {
132    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
133        match self {
134            ColumnID::Name(id) => write!(f, "{}", id),
135            ColumnID::Position(id) => write!(f, "{}", id),
136        }
137    }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
141pub struct DatabaseRef {
142    pub catalog: Option<Identifier>,
143    pub database: Identifier,
144}
145
146impl Display for DatabaseRef {
147    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
148        if let Some(catalog) = &self.catalog {
149            write!(f, "{}.", catalog)?;
150        }
151        write!(f, "{}", self.database)?;
152        Ok(())
153    }
154}
155
156#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
157pub struct TableRef {
158    pub catalog: Option<Identifier>,
159    pub database: Option<Identifier>,
160    pub table: Identifier,
161    pub branch: Option<Identifier>,
162}
163
164impl Display for TableRef {
165    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
166        assert!(self.catalog.is_none() || (self.catalog.is_some() && self.database.is_some()));
167        if let Some(catalog) = &self.catalog {
168            write!(f, "{}.", catalog)?;
169        }
170        if let Some(database) = &self.database {
171            write!(f, "{}.", database)?;
172        }
173        write!(f, "{}", self.table)?;
174
175        if let Some(branch) = &self.branch {
176            write!(f, "/{branch}")?;
177        }
178        Ok(())
179    }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
183pub struct ColumnRef {
184    pub database: Option<Identifier>,
185    pub table: Option<Identifier>,
186    pub column: ColumnID,
187}
188
189impl Display for ColumnRef {
190    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
191        assert!(self.database.is_none() || (self.database.is_some() && self.table.is_some()));
192
193        if f.alternate() {
194            write!(f, "{}", self.column)?;
195            return Ok(());
196        }
197
198        if let Some(database) = &self.database {
199            write!(f, "{}.", database)?;
200        }
201        if let Some(table) = &self.table {
202            write!(f, "{}.", table)?;
203        }
204        write!(f, "{}", self.column)?;
205        Ok(())
206    }
207}
208
209pub(crate) fn write_dot_separated_list(
210    f: &mut Formatter,
211    items: impl IntoIterator<Item = impl Display>,
212) -> std::fmt::Result {
213    for (i, item) in items.into_iter().enumerate() {
214        if i > 0 {
215            write!(f, ".")?;
216        }
217        write!(f, "{}", item)?;
218    }
219    Ok(())
220}
221
222/// Write input items into `a, b, c`
223pub(crate) fn write_comma_separated_list(
224    f: &mut Formatter,
225    items: impl IntoIterator<Item = impl Display>,
226) -> std::fmt::Result {
227    for (i, item) in items.into_iter().enumerate() {
228        if i > 0 {
229            write!(f, ", ")?;
230        }
231        write!(f, "{item}")?;
232    }
233    Ok(())
234}
235
236/// Write input items into `'a', 'b', 'c'`
237pub(crate) fn write_comma_separated_string_list(
238    f: &mut Formatter,
239    items: impl IntoIterator<Item = impl Display>,
240) -> std::fmt::Result {
241    for (i, item) in items.into_iter().enumerate() {
242        if i > 0 {
243            write!(f, ", ")?;
244        }
245        write!(f, "'{item}'")?;
246    }
247    Ok(())
248}
249
250/// Write input map items into `field_a=x, field_b=y`
251pub(crate) fn write_comma_separated_map(
252    f: &mut Formatter,
253    items: impl IntoIterator<Item = (impl Display, impl Display)>,
254) -> std::fmt::Result {
255    for (i, (k, v)) in items.into_iter().enumerate() {
256        if i > 0 {
257            write!(f, ", ")?;
258        }
259        write!(f, "{k} = {v}")?;
260    }
261    Ok(())
262}
263
264/// Write input map items into `field_a='x', field_b='y'`
265pub(crate) fn write_comma_separated_string_map(
266    f: &mut Formatter,
267    items: impl IntoIterator<Item = (impl Display, impl Display)>,
268) -> std::fmt::Result {
269    for (i, (k, v)) in items.into_iter().enumerate() {
270        if i > 0 {
271            write!(f, ", ")?;
272        }
273        write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
274    }
275    Ok(())
276}
277
278/// Write input map items into `field_a='x' field_b='y'`
279pub(crate) fn write_space_separated_string_map(
280    f: &mut Formatter,
281    items: impl IntoIterator<Item = (impl Display, impl Display)>,
282) -> std::fmt::Result {
283    for (i, (k, v)) in items.into_iter().enumerate() {
284        if i > 0 {
285            write!(f, " ")?;
286        }
287        write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
288    }
289    Ok(())
290}
291
292pub(crate) fn display_decimal_256(num: i256, scale: u8) -> impl Display {
293    struct Decimal256 {
294        num: i256,
295        scale: u8,
296    }
297
298    impl Display for Decimal256 {
299        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300            if self.scale == 0 {
301                write!(f, "{}", self.num)
302            } else {
303                let pow_scale = i256::from(10).pow(self.scale as u32);
304                // -1/10 = 0
305                if self.num >= 0 {
306                    write!(
307                        f,
308                        "{}.{:0>width$}",
309                        self.num / pow_scale,
310                        (self.num % pow_scale).abs(),
311                        width = self.scale as usize
312                    )
313                } else {
314                    write!(
315                        f,
316                        "-{}.{:0>width$}",
317                        -self.num / pow_scale,
318                        (self.num % pow_scale).abs(),
319                        width = self.scale as usize
320                    )
321                }
322            }
323        }
324    }
325
326    Decimal256 { num, scale }
327}