proof_of_sql/base/database/
table_ref.rs

1use crate::base::database::error::ParseError;
2use alloc::{string::ToString, vec::Vec};
3use core::{
4    fmt,
5    fmt::{Display, Formatter},
6    str::FromStr,
7};
8use indexmap::Equivalent;
9use serde::{Deserialize, Serialize};
10use sqlparser::ast::Ident;
11
12/// Expression for an SQL table
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct TableRef {
15    schema_name: Option<Ident>,
16    table_name: Ident,
17}
18
19impl TableRef {
20    /// Creates a new table reference from schema and table names.
21    /// If the schema name is empty or None, only the table name is used.
22    #[must_use]
23    pub fn new(schema_name: impl AsRef<str>, table_name: impl AsRef<str>) -> Self {
24        let schema = schema_name.as_ref();
25        let table = table_name.as_ref();
26
27        Self {
28            schema_name: if schema.is_empty() {
29                None
30            } else {
31                Some(Ident::new(schema.to_string()))
32            },
33            table_name: Ident::new(table.to_string()),
34        }
35    }
36
37    /// Returns the identifier of the schema
38    /// # Panics
39    #[must_use]
40    pub fn schema_id(&self) -> Option<&Ident> {
41        self.schema_name.as_ref()
42    }
43
44    /// Returns the identifier of the table
45    /// # Panics
46    #[must_use]
47    pub fn table_id(&self) -> &Ident {
48        &self.table_name
49    }
50
51    /// Creates a new table reference from an optional schema and table name.
52    #[must_use]
53    pub fn from_names(schema_name: Option<&str>, table_name: &str) -> Self {
54        Self {
55            schema_name: schema_name.map(|s| Ident::new(s.to_string())),
56            table_name: Ident::new(table_name.to_string()),
57        }
58    }
59
60    /// Creates a `TableRef` directly from `Option<Ident>` for schema and `Ident` for table.
61    #[must_use]
62    pub fn from_idents(schema_name: Option<Ident>, table_name: Ident) -> Self {
63        Self {
64            schema_name,
65            table_name,
66        }
67    }
68
69    /// Creates a `TableRef` from a slice of string components.
70    pub fn from_strs<S: AsRef<str>>(components: &[S]) -> Result<Self, ParseError> {
71        match components.len() {
72            1 => Ok(Self::from_names(None, components[0].as_ref())),
73            2 => Ok(Self::from_names(
74                Some(components[0].as_ref()),
75                components[1].as_ref(),
76            )),
77            _ => Err(ParseError::InvalidTableReference {
78                table_reference: components
79                    .iter()
80                    .map(AsRef::as_ref)
81                    .collect::<Vec<_>>()
82                    .join(","),
83            }),
84        }
85    }
86}
87
88/// Creates a `TableRef` from a dot-separated string.
89impl TryFrom<&str> for TableRef {
90    type Error = ParseError;
91
92    fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
93        let components: Vec<_> = s.split('.').map(ToString::to_string).collect();
94        match components.len() {
95            1 => Ok(Self::from_names(None, &components[0])),
96            2 => Ok(Self::from_names(Some(&components[0]), &components[1])),
97            _ => Err(ParseError::InvalidTableReference {
98                table_reference: s.to_string(),
99            }),
100        }
101    }
102}
103
104impl FromStr for TableRef {
105    type Err = ParseError;
106
107    fn from_str(s: &str) -> Result<Self, Self::Err> {
108        Self::try_from(s)
109    }
110}
111
112impl Equivalent<TableRef> for &TableRef {
113    fn equivalent(&self, key: &TableRef) -> bool {
114        self.schema_name == key.schema_name && self.table_name == key.table_name
115    }
116}
117
118impl Display for TableRef {
119    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
120        if let Some(schema) = &self.schema_name {
121            write!(f, "{}.{}", schema.value, self.table_name.value)
122        } else {
123            write!(f, "{}", self.table_name.value)
124        }
125    }
126}
127
128impl Serialize for TableRef {
129    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
130    where
131        S: serde::Serializer,
132    {
133        serializer.serialize_str(&self.to_string())
134    }
135}
136impl<'d> Deserialize<'d> for TableRef {
137    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
138    where
139        D: serde::Deserializer<'d>,
140    {
141        let string = alloc::string::String::deserialize(deserializer)?;
142        TableRef::from_str(&string).map_err(serde::de::Error::custom)
143    }
144}