Skip to main content

qusql_type/
type_.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
13use alloc::{
14    borrow::Cow,
15    boxed::Box,
16    fmt::{Display, Write},
17    sync::Arc,
18    vec::Vec,
19};
20use qusql_parse::Span;
21
22/// Canonical base type of a type
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum BaseType {
25    /// There are no constraint of the value
26    Any,
27    /// The value must be boolean
28    Bool,
29    /// The value must be a binary blob
30    Bytes,
31    Date,
32    DateTime,
33    /// The value must be some kind of float
34    Float,
35    /// The value must be some kind of integer
36    Integer,
37    String,
38    Time,
39    TimeStamp,
40    TimeInterval,
41    Uuid,
42}
43
44impl Display for BaseType {
45    fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
46        match self {
47            BaseType::Any => f.write_str("any"),
48            BaseType::Bool => f.write_str("bool"),
49            BaseType::Bytes => f.write_str("bytes"),
50            BaseType::Date => f.write_str("date"),
51            BaseType::DateTime => f.write_str("datetime"),
52            BaseType::Float => f.write_str("float"),
53            BaseType::Integer => f.write_str("integer"),
54            BaseType::String => f.write_str("string"),
55            BaseType::Time => f.write_str("time"),
56            BaseType::TimeStamp => f.write_str("timestamp"),
57            BaseType::TimeInterval => f.write_str("timeinterval"),
58            BaseType::Uuid => f.write_str("uuid"),
59        }
60    }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum ArgType {
65    Normal,
66    ListHack,
67}
68
69/// Represent the type of a value
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub enum Type<'a> {
72    // This type is used internally and should not escape to the user
73    #[doc(hidden)]
74    Args(BaseType, Arc<Vec<(usize, ArgType, Span)>>),
75    Base(BaseType),
76    Enum(Arc<Vec<Cow<'a, str>>>),
77    F32,
78    F64,
79    I16,
80    I24,
81    I32,
82    I64,
83    I8,
84    Invalid,
85    JSON,
86    Geometry,
87    /// A PostgreSQL range type. The inner type is the element type (e.g. `I32` for
88    /// `int4range`, `I64` for `int8range`, `Base(Date)` for `daterange`, ...).
89    Range(Box<Type<'a>>),
90    /// A PostgreSQL multirange type. The inner type is the element type.
91    MultiRange(Box<Type<'a>>),
92    Array(Box<Type<'a>>),
93    Set(Arc<Vec<Cow<'a, str>>>),
94    U16,
95    U24,
96    U32,
97    U64,
98    U8,
99    // This type is used internally and should not escape to the user
100    #[doc(hidden)]
101    Null,
102}
103
104impl<'a> Display for Type<'a> {
105    fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
106        match self {
107            Type::Args(t, a) => {
108                write!(f, "args({t}")?;
109                for (a, _, _) in a.iter() {
110                    write!(f, ", {a}")?;
111                }
112                f.write_char(')')
113            }
114            Type::Base(t) => t.fmt(f),
115            Type::F32 => f.write_str("f32"),
116            Type::F64 => f.write_str("f64"),
117            Type::I16 => f.write_str("i16"),
118            Type::I24 => f.write_str("i24"),
119            Type::I32 => f.write_str("i32"),
120            Type::I64 => f.write_str("i64"),
121            Type::I8 => f.write_str("i8"),
122            Type::Invalid => f.write_str("invalid"),
123            Type::JSON => f.write_str("json"),
124            Type::Geometry => f.write_str("geometry"),
125            Type::Range(inner) => write!(f, "range({inner})"),
126            Type::MultiRange(inner) => write!(f, "multirange({inner})"),
127            Type::Array(inner) => {
128                inner.fmt(f)?;
129                f.write_str("[]")
130            }
131            Type::U16 => f.write_str("u16"),
132            Type::U24 => f.write_str("u24"),
133            Type::U32 => f.write_str("u32"),
134            Type::U64 => f.write_str("u64"),
135            Type::U8 => f.write_str("u8"),
136            Type::Null => f.write_str("null"),
137            Type::Enum(v) => {
138                f.write_str("enum(")?;
139                for (i, v) in v.iter().enumerate() {
140                    if i != 0 {
141                        f.write_str(", ")?;
142                    }
143                    write!(f, "'{v}'")?
144                }
145                f.write_char(')')
146            }
147            Type::Set(v) => {
148                f.write_str("set(")?;
149                for (i, v) in v.iter().enumerate() {
150                    if i != 0 {
151                        f.write_str(", ")?;
152                    }
153                    write!(f, "'{v}'")?
154                }
155                f.write_char(')')
156            }
157        }
158    }
159}
160
161impl<'a> Type<'a> {
162    /// Compute the canonical base type
163    pub fn base(&self) -> BaseType {
164        match self {
165            Type::Args(t, _) => *t,
166            Type::Base(t) => *t,
167            Type::Enum(_) => BaseType::String,
168            Type::F32 => BaseType::Float,
169            Type::F64 => BaseType::Float,
170            Type::I16 => BaseType::Integer,
171            Type::I24 => BaseType::Integer,
172            Type::I32 => BaseType::Integer,
173            Type::I64 => BaseType::Integer,
174            Type::I8 => BaseType::Integer,
175            Type::Invalid => BaseType::Any,
176            Type::JSON => BaseType::Any,
177            Type::Geometry => BaseType::Any,
178            Type::Range(_) => BaseType::Any,
179            Type::MultiRange(_) => BaseType::Any,
180            Type::Array(_) => BaseType::Any,
181            Type::Null => BaseType::Any,
182            Type::Set(_) => BaseType::String,
183            Type::U16 => BaseType::Integer,
184            Type::U24 => BaseType::Integer,
185            Type::U32 => BaseType::Integer,
186            Type::U64 => BaseType::Integer,
187            Type::U8 => BaseType::Integer,
188        }
189    }
190}
191
192impl<'a> From<BaseType> for Type<'a> {
193    fn from(t: BaseType) -> Self {
194        Type::Base(t)
195    }
196}
197
198/// Represent a type with not_null information
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct FullType<'a> {
201    pub t: Type<'a>,
202    pub not_null: bool,
203    pub list_hack: bool,
204}
205
206impl<'a> FullType<'a> {
207    pub(crate) fn new(t: impl Into<Type<'a>>, not_null: bool) -> Self {
208        Self {
209            t: t.into(),
210            not_null,
211            list_hack: false,
212        }
213    }
214
215    /// Construct a new invalid type
216    pub fn invalid() -> Self {
217        Self {
218            t: Type::Invalid,
219            not_null: false,
220            list_hack: false,
221        }
222    }
223}
224
225impl<'a> core::ops::Deref for FullType<'a> {
226    type Target = Type<'a>;
227
228    fn deref(&self) -> &Self::Target {
229        &self.t
230    }
231}
232
233impl<'a> Display for FullType<'a> {
234    fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
235        self.t.fmt(f)?;
236        if self.list_hack {
237            f.write_str(" list_hack")?;
238        }
239        if self.not_null {
240            f.write_str(" not null")?;
241        }
242        Ok(())
243    }
244}