use crate::base::database::error::ParseError;
use alloc::{string::ToString, vec::Vec};
use core::{
fmt,
fmt::{Display, Formatter},
str::FromStr,
};
use indexmap::Equivalent;
use serde::{Deserialize, Serialize};
use sqlparser::ast::Ident;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TableRef {
schema_name: Option<Ident>,
table_name: Ident,
}
impl TableRef {
#[must_use]
pub fn new(schema_name: impl AsRef<str>, table_name: impl AsRef<str>) -> Self {
let schema = schema_name.as_ref();
let table = table_name.as_ref();
Self {
schema_name: if schema.is_empty() {
None
} else {
Some(Ident::new(schema.to_string()))
},
table_name: Ident::new(table.to_string()),
}
}
#[must_use]
pub fn schema_id(&self) -> Option<&Ident> {
self.schema_name.as_ref()
}
#[must_use]
pub fn table_id(&self) -> &Ident {
&self.table_name
}
#[must_use]
pub fn from_names(schema_name: Option<&str>, table_name: &str) -> Self {
Self {
schema_name: schema_name.map(|s| Ident::new(s.to_string())),
table_name: Ident::new(table_name.to_string()),
}
}
#[must_use]
pub fn from_idents(schema_name: Option<Ident>, table_name: Ident) -> Self {
Self {
schema_name,
table_name,
}
}
pub fn from_strs<S: AsRef<str>>(components: &[S]) -> Result<Self, ParseError> {
match components.len() {
1 => Ok(Self::from_names(None, components[0].as_ref())),
2 => Ok(Self::from_names(
Some(components[0].as_ref()),
components[1].as_ref(),
)),
_ => Err(ParseError::InvalidTableReference {
table_reference: components
.iter()
.map(AsRef::as_ref)
.collect::<Vec<_>>()
.join(","),
}),
}
}
}
impl TryFrom<&str> for TableRef {
type Error = ParseError;
fn try_from(s: &str) -> Result<Self, <Self as TryFrom<&str>>::Error> {
let components: Vec<_> = s.split('.').map(ToString::to_string).collect();
match components.len() {
1 => Ok(Self::from_names(None, &components[0])),
2 => Ok(Self::from_names(Some(&components[0]), &components[1])),
_ => Err(ParseError::InvalidTableReference {
table_reference: s.to_string(),
}),
}
}
}
impl FromStr for TableRef {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl Equivalent<TableRef> for &TableRef {
fn equivalent(&self, key: &TableRef) -> bool {
self.schema_name == key.schema_name && self.table_name == key.table_name
}
}
impl Display for TableRef {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(schema) = &self.schema_name {
write!(f, "{}.{}", schema.value, self.table_name.value)
} else {
write!(f, "{}", self.table_name.value)
}
}
}
impl Serialize for TableRef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'d> Deserialize<'d> for TableRef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'d>,
{
let string = alloc::string::String::deserialize(deserializer)?;
TableRef::from_str(&string).map_err(serde::de::Error::custom)
}
}