sql_from_models_parser/ast/
value.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13#[cfg(not(feature = "std"))]
14use alloc::string::String;
15use core::fmt;
16
17#[cfg(feature = "bigdecimal")]
18use bigdecimal::BigDecimal;
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22/// Primitive SQL values such as number and string
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub enum Value {
26    /// Numeric literal
27    #[cfg(not(feature = "bigdecimal"))]
28    Number(String, bool),
29    #[cfg(feature = "bigdecimal")]
30    Number(BigDecimal, bool),
31    /// 'string value'
32    SingleQuotedString(String),
33    /// N'string value'
34    NationalStringLiteral(String),
35    /// X'hex value'
36    HexStringLiteral(String),
37
38    DoubleQuotedString(String),
39    /// Boolean value true or false
40    Boolean(bool),
41    /// INTERVAL literals, roughly in the following format:
42    /// `INTERVAL '<value>' [ <leading_field> [ (<leading_precision>) ] ]
43    /// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]`,
44    /// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`.
45    ///
46    /// The parser does not validate the `<value>`, nor does it ensure
47    /// that the `<leading_field>` units >= the units in `<last_field>`,
48    /// so the user will have to reject intervals like `HOUR TO YEAR`.
49    Interval {
50        value: String,
51        leading_field: Option<DateTimeField>,
52        leading_precision: Option<u64>,
53        last_field: Option<DateTimeField>,
54        /// The seconds precision can be specified in SQL source as
55        /// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
56        /// will be `Second` and the `last_field` will be `None`),
57        /// or as `__ TO SECOND(x)`.
58        fractional_seconds_precision: Option<u64>,
59    },
60    /// `NULL` value
61    Null,
62}
63
64impl fmt::Display for Value {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        match self {
67            Value::Number(v, l) => write!(f, "{}{long}", v, long = if *l { "L" } else { "" }),
68            Value::DoubleQuotedString(v) => write!(f, "\"{}\"", v),
69            Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
70            Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
71            Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
72            Value::Boolean(v) => write!(f, "{}", v),
73            Value::Interval {
74                value,
75                leading_field: Some(DateTimeField::Second),
76                leading_precision: Some(leading_precision),
77                last_field,
78                fractional_seconds_precision: Some(fractional_seconds_precision),
79            } => {
80                // When the leading field is SECOND, the parser guarantees that
81                // the last field is None.
82                assert!(last_field.is_none());
83                write!(
84                    f,
85                    "INTERVAL '{}' SECOND ({}, {})",
86                    escape_single_quote_string(value),
87                    leading_precision,
88                    fractional_seconds_precision
89                )
90            }
91            Value::Interval {
92                value,
93                leading_field,
94                leading_precision,
95                last_field,
96                fractional_seconds_precision,
97            } => {
98                write!(f, "INTERVAL '{}'", escape_single_quote_string(value))?;
99                if let Some(leading_field) = leading_field {
100                    write!(f, " {}", leading_field)?;
101                }
102                if let Some(leading_precision) = leading_precision {
103                    write!(f, " ({})", leading_precision)?;
104                }
105                if let Some(last_field) = last_field {
106                    write!(f, " TO {}", last_field)?;
107                }
108                if let Some(fractional_seconds_precision) = fractional_seconds_precision {
109                    write!(f, " ({})", fractional_seconds_precision)?;
110                }
111                Ok(())
112            }
113            Value::Null => write!(f, "NULL"),
114        }
115    }
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Hash)]
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
120pub enum DateTimeField {
121    Year,
122    Month,
123    Day,
124    Hour,
125    Minute,
126    Second,
127}
128
129impl fmt::Display for DateTimeField {
130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131        f.write_str(match self {
132            DateTimeField::Year => "YEAR",
133            DateTimeField::Month => "MONTH",
134            DateTimeField::Day => "DAY",
135            DateTimeField::Hour => "HOUR",
136            DateTimeField::Minute => "MINUTE",
137            DateTimeField::Second => "SECOND",
138        })
139    }
140}
141
142pub struct EscapeSingleQuoteString<'a>(&'a str);
143
144impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        for c in self.0.chars() {
147            if c == '\'' {
148                write!(f, "\'\'")?;
149            } else {
150                write!(f, "{}", c)?;
151            }
152        }
153        Ok(())
154    }
155}
156
157pub fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
158    EscapeSingleQuoteString(s)
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
163pub enum TrimWhereField {
164    Both,
165    Leading,
166    Trailing,
167}
168
169impl fmt::Display for TrimWhereField {
170    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171        use TrimWhereField::*;
172        f.write_str(match self {
173            Both => "BOTH",
174            Leading => "LEADING",
175            Trailing => "TRAILING",
176        })
177    }
178}