use std::fmt;
use std::str;
use nom::bytes::complete::{tag, tag_no_case};
use nom::character::complete::{multispace0, multispace1};
use nom::combinator::{map, opt};
use nom::multi::many0;
use nom::sequence::{pair, terminated, tuple};
use nom::IResult;
use base::error::ParseSQLError;
use base::{CommonParser, DisplayUtil};
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Table {
pub name: String,
pub alias: Option<String>,
pub schema: Option<String>,
}
impl Table {
pub fn table_list(i: &str) -> IResult<&str, Vec<Table>, ParseSQLError<&str>> {
many0(terminated(
Table::schema_table_reference,
opt(CommonParser::ws_sep_comma),
))(i)
}
pub fn schema_table_reference(i: &str) -> IResult<&str, Table, ParseSQLError<&str>> {
map(
tuple((
opt(pair(CommonParser::sql_identifier, tag("."))),
CommonParser::sql_identifier,
opt(CommonParser::as_alias),
)),
|tup| Table {
name: String::from(tup.1),
alias: tup.2.map(String::from),
schema: tup.0.map(|(schema, _)| String::from(schema)),
},
)(i)
}
pub fn table_reference(i: &str) -> IResult<&str, Table, ParseSQLError<&str>> {
map(
pair(CommonParser::sql_identifier, opt(CommonParser::as_alias)),
|tup| Table {
name: String::from(tup.0),
alias: tup.1.map(String::from),
schema: None,
},
)(i)
}
pub fn without_alias(i: &str) -> IResult<&str, Table, ParseSQLError<&str>> {
map(
tuple((
opt(pair(CommonParser::sql_identifier, tag("."))),
CommonParser::sql_identifier,
)),
|tup| Table {
name: String::from(tup.1),
alias: None,
schema: tup.0.map(|(schema, _)| String::from(schema)),
},
)(i)
}
pub fn schema_table_reference_to_schema_table_reference(
i: &str,
) -> IResult<&str, (Table, Table), ParseSQLError<&str>> {
map(
tuple((
Self::schema_table_reference,
multispace0,
tag_no_case("TO"),
multispace1,
Self::schema_table_reference,
)),
|(from, _, _, _, to)| (from, to),
)(i)
}
}
impl fmt::Display for Table {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref schema) = self.schema {
write!(f, "{}.", DisplayUtil::escape_if_keyword(schema))?;
}
write!(f, "{}", DisplayUtil::escape_if_keyword(&self.name))?;
if let Some(ref alias) = self.alias {
write!(f, " AS {}", DisplayUtil::escape_if_keyword(alias))?;
}
Ok(())
}
}
impl<'a> From<&'a str> for Table {
fn from(t: &str) -> Table {
Table {
name: String::from(t),
alias: None,
schema: None,
}
}
}
impl<'a> From<(&'a str, &'a str)> for Table {
fn from(t: (&str, &str)) -> Table {
Table {
name: String::from(t.1),
alias: None,
schema: Some(String::from(t.0)),
}
}
}