proof_of_sql/base/database/
table_ref.rs1use 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 proof_of_sql_parser::{impl_serde_from_str, ResourceId};
10use sqlparser::ast::Ident;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct TableRef {
15 schema_name: Option<Ident>,
16 table_name: Ident,
17}
18
19impl TableRef {
20 #[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 #[allow(clippy::get_first)]
40 #[must_use]
41 pub fn schema_id(&self) -> Option<&Ident> {
42 self.schema_name.as_ref()
43 }
44
45 #[must_use]
48 pub fn table_id(&self) -> &Ident {
49 &self.table_name
50 }
51
52 #[must_use]
54 pub fn from_names(schema_name: Option<&str>, table_name: &str) -> Self {
55 Self {
56 schema_name: schema_name.map(|s| Ident::new(s.to_string())),
57 table_name: Ident::new(table_name.to_string()),
58 }
59 }
60
61 #[must_use]
63 pub fn from_idents(schema_name: Option<Ident>, table_name: Ident) -> Self {
64 Self {
65 schema_name,
66 table_name,
67 }
68 }
69
70 pub fn from_strs<S: AsRef<str>>(components: &[S]) -> Result<Self, ParseError> {
72 match components.len() {
73 1 => Ok(Self::from_names(None, components[0].as_ref())),
74 2 => Ok(Self::from_names(
75 Some(components[0].as_ref()),
76 components[1].as_ref(),
77 )),
78 _ => Err(ParseError::InvalidTableReference {
79 table_reference: components
80 .iter()
81 .map(AsRef::as_ref)
82 .collect::<Vec<_>>()
83 .join(","),
84 }),
85 }
86 }
87}
88
89impl TryFrom<&str> for TableRef {
91 type Error = ParseError;
92
93 fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
94 let components: Vec<_> = s.split('.').map(ToString::to_string).collect();
95 match components.len() {
96 1 => Ok(Self::from_names(None, &components[0])),
97 2 => Ok(Self::from_names(Some(&components[0]), &components[1])),
98 _ => Err(ParseError::InvalidTableReference {
99 table_reference: s.to_string(),
100 }),
101 }
102 }
103}
104
105impl From<ResourceId> for TableRef {
107 fn from(id: ResourceId) -> Self {
108 TableRef {
109 schema_name: Some(Ident::from(id.schema())),
110 table_name: Ident::from(id.object_name()),
111 }
112 }
113}
114
115impl FromStr for TableRef {
116 type Err = ParseError;
117
118 fn from_str(s: &str) -> Result<Self, Self::Err> {
119 Self::try_from(s)
120 }
121}
122
123impl Equivalent<TableRef> for &TableRef {
124 fn equivalent(&self, key: &TableRef) -> bool {
125 self.schema_name == key.schema_name && self.table_name == key.table_name
126 }
127}
128
129impl Display for TableRef {
130 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
131 if let Some(schema) = &self.schema_name {
132 write!(f, "{}.{}", schema.value, self.table_name.value)
133 } else {
134 write!(f, "{}", self.table_name.value)
135 }
136 }
137}
138
139impl_serde_from_str!(TableRef);