Modifier support for Custom Datatype (#680)

* feat: add support for custom types with argument

* refactor: add support for number and string as type arguments

* fix: ignore CustomWithArgs when parsing TypedString

* refactor: merge CustomWithArgs into Custom

* refactor: rename arguments to modifiers
This commit is contained in:
Ning Sun 2022-10-21 03:27:15 +08:00 committed by GitHub
parent 2c266a437c
commit 914810d366
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 4 deletions

View file

@ -129,7 +129,7 @@ pub enum DataType {
/// Bytea
Bytea,
/// Custom type such as enums
Custom(ObjectName),
Custom(ObjectName, Vec<String>),
/// Arrays
Array(Box<DataType>),
/// Enums
@ -217,7 +217,13 @@ impl fmt::Display for DataType {
DataType::String => write!(f, "STRING"),
DataType::Bytea => write!(f, "BYTEA"),
DataType::Array(ty) => write!(f, "{}[]", ty),
DataType::Custom(ty) => write!(f, "{}", ty),
DataType::Custom(ty, modifiers) => {
if modifiers.is_empty() {
write!(f, "{}", ty)
} else {
write!(f, "{}({})", ty, modifiers.join(", "))
}
}
DataType::Enum(vals) => {
write!(f, "ENUM(")?;
for (i, v) in vals.iter().enumerate() {

View file

@ -3661,7 +3661,11 @@ impl<'a> Parser<'a> {
_ => {
self.prev_token();
let type_name = self.parse_object_name()?;
Ok(DataType::Custom(type_name))
if let Some(modifiers) = self.parse_optional_type_modifiers()? {
Ok(DataType::Custom(type_name, modifiers))
} else {
Ok(DataType::Custom(type_name, vec![]))
}
}
},
unexpected => self.expected("a data type name", unexpected),
@ -3907,6 +3911,31 @@ impl<'a> Parser<'a> {
}
}
pub fn parse_optional_type_modifiers(&mut self) -> Result<Option<Vec<String>>, ParserError> {
if self.consume_token(&Token::LParen) {
let mut modifiers = Vec::new();
loop {
match self.next_token() {
Token::Word(w) => modifiers.push(w.to_string()),
Token::Number(n, _) => modifiers.push(n),
Token::SingleQuotedString(s) => modifiers.push(s),
Token::Comma => {
continue;
}
Token::RParen => {
break;
}
unexpected => self.expected("type modifiers", unexpected)?,
}
}
Ok(Some(modifiers))
} else {
Ok(None)
}
}
pub fn parse_delete(&mut self) -> Result<Statement, ParserError> {
self.expect_keyword(Keyword::FROM)?;
let table_name = self.parse_table_factor()?;
@ -5540,7 +5569,7 @@ mod tests {
#[cfg(test)]
mod test_parse_data_type {
use crate::ast::{
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo,
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, ObjectName, TimezoneInfo,
};
use crate::dialect::{AnsiDialect, GenericDialect};
use crate::test_utils::TestedDialects;
@ -5717,6 +5746,36 @@ mod tests {
test_parse_data_type!(dialect, "CLOB(20)", DataType::Clob(Some(20)));
}
#[test]
fn test_parse_custom_types() {
let dialect = TestedDialects {
dialects: vec![Box::new(GenericDialect {}), Box::new(AnsiDialect {})],
};
test_parse_data_type!(
dialect,
"GEOMETRY",
DataType::Custom(ObjectName(vec!["GEOMETRY".into()]), vec![])
);
test_parse_data_type!(
dialect,
"GEOMETRY(POINT)",
DataType::Custom(
ObjectName(vec!["GEOMETRY".into()]),
vec!["POINT".to_string()]
)
);
test_parse_data_type!(
dialect,
"GEOMETRY(POINT, 4326)",
DataType::Custom(
ObjectName(vec!["GEOMETRY".into()]),
vec!["POINT".to_string(), "4326".to_string()]
)
);
}
#[test]
fn test_ansii_exact_numeric_types() {
// Exact numeric types: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type>