otter_sql/
identifier.rs

1//! Names used for tables, columns, schemas, DBs, etc.
2use std::fmt::Display;
3
4use arraystring::{typenum::U63, ArrayString};
5
6use sqlparser::ast::Ident;
7
8/// A fixed capacity copy-able string.
9pub type BoundedString = ArrayString<U63>;
10
11/// A name given to a schema. Uniquely identifies a single schema in a database.
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct SchemaRef(pub BoundedString);
14
15impl TryFrom<Vec<Ident>> for SchemaRef {
16    type Error = IdentifierError;
17
18    fn try_from(value: Vec<Ident>) -> Result<Self, Self::Error> {
19        match value.as_slice() {
20            [] => Err(IdentifierError {
21                idents: value,
22                reason: "Empty schema name",
23            }),
24            [schema_name] => Ok(SchemaRef(schema_name.value.as_str().into())),
25            _ => Err(IdentifierError {
26                idents: value,
27                reason: "More than 1 part in schema name.",
28            }),
29        }
30    }
31}
32
33/// Uniquely identifies a table in a database. The schema will be assumed to be the
34/// [`default_schema`](`crate::Database::default_schema`) if not specified.
35#[derive(Debug, Clone, Copy, PartialEq)]
36pub struct TableRef {
37    pub schema_name: Option<BoundedString>,
38    pub table_name: BoundedString,
39}
40
41impl TryFrom<Vec<Ident>> for TableRef {
42    type Error = IdentifierError;
43
44    fn try_from(value: Vec<Ident>) -> Result<Self, Self::Error> {
45        match value.as_slice() {
46            [] => Err(IdentifierError {
47                idents: value,
48                reason: "Empty table name",
49            }),
50            [table_name] => Ok(TableRef {
51                schema_name: None,
52                table_name: table_name.value.as_str().into(),
53            }),
54            [schema_name, table_name] => Ok(TableRef {
55                schema_name: Some(schema_name.value.as_str().into()),
56                table_name: table_name.value.as_str().into(),
57            }),
58            _ => Err(IdentifierError {
59                idents: value,
60                reason: "More than 2 parts in table name.",
61            }),
62        }
63    }
64}
65
66impl Display for TableRef {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        match self {
69            Self {
70                schema_name: None,
71                table_name,
72            } => write!(f, "{}", table_name),
73            Self {
74                schema_name: Some(schema_name),
75                table_name,
76            } => write!(f, "{}.{}", schema_name, table_name),
77        }
78    }
79}
80
81/// Uniquely identifies a column in a given table in a database.
82///
83/// The schema will be assumed to be the
84/// [`default_schema`](`crate::Database::default_schema`) if not specified.
85///
86/// The table will be the one specified in the `WHERE` clause of the query if not specified
87/// explicitly.
88#[derive(Debug, Clone, Copy, PartialEq)]
89pub struct ColumnRef {
90    pub schema_name: Option<BoundedString>,
91    pub table_name: Option<BoundedString>,
92    pub col_name: BoundedString,
93}
94
95impl Display for ColumnRef {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        match self {
98            Self {
99                schema_name: None,
100                table_name: None,
101                col_name,
102            } => write!(f, "{}", col_name),
103            Self {
104                schema_name: None,
105                table_name: Some(table_name),
106                col_name,
107            } => write!(f, "{}.{}", table_name, col_name),
108            Self {
109                schema_name: Some(schema_name),
110                table_name: Some(table_name),
111                col_name,
112            } => write!(f, "{}.{}.{}", schema_name, table_name, col_name),
113            // the below case does not occur
114            Self {
115                schema_name: Some(schema_name),
116                table_name: None,
117                col_name,
118            } => write!(f, "{}.{}", schema_name, col_name),
119        }
120    }
121}
122
123impl TryFrom<Vec<Ident>> for ColumnRef {
124    type Error = IdentifierError;
125
126    fn try_from(value: Vec<Ident>) -> Result<Self, Self::Error> {
127        match value.as_slice() {
128            [] => Err(IdentifierError {
129                idents: value,
130                reason: "Empty column name",
131            }),
132            [col_name] => Ok(ColumnRef {
133                schema_name: None,
134                table_name: None,
135                col_name: col_name.value.as_str().into(),
136            }),
137            [table_name, col_name] => Ok(ColumnRef {
138                schema_name: None,
139                table_name: Some(table_name.value.as_str().into()),
140                col_name: col_name.value.as_str().into(),
141            }),
142            [schema_name, table_name, col_name] => Ok(ColumnRef {
143                schema_name: Some(schema_name.value.as_str().into()),
144                table_name: Some(table_name.value.as_str().into()),
145                col_name: col_name.value.as_str().into(),
146            }),
147            _ => Err(IdentifierError {
148                idents: value,
149                reason: "More than 3 parts in column name.",
150            }),
151        }
152    }
153}
154
155/// Invalid identifier.
156#[derive(Debug, PartialEq)]
157pub struct IdentifierError {
158    idents: Vec<Ident>,
159    reason: &'static str,
160}
161
162impl Display for IdentifierError {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        write!(
165            f,
166            "IdentifierError: {} (Got: '{:?}')",
167            self.reason, self.idents
168        )
169    }
170}