use crate::ast::Node;
use crate::str::SqlError;
macro_rules! must {
($expr:expr) => {
$expr
.as_ref()
.ok_or_else(|| SqlError::Missing(stringify!($expr).into()))?
};
}
macro_rules! node {
($expr:expr, $ty:path) => {
match &$expr {
$ty(elem) => elem,
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! const_integer {
($expr:expr) => {
match &$expr {
Node::A_Const(value) => match &value {
crate::ast::ConstValue::Integer(value) => value,
unexpected => return Err(SqlError::UnexpectedConstValue(unexpected.name())),
},
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! const_string {
($expr:expr) => {
match &$expr {
Node::A_Const(value) => match &value {
crate::ast::ConstValue::String(value) => value,
unexpected => return Err(SqlError::UnexpectedConstValue(unexpected.name())),
},
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! iter_only {
($expr:expr, $ty:path) => {
$expr.iter().filter_map(|n| match n {
$ty(elem) => Some(elem),
_ => None,
})
};
}
macro_rules! bool_value {
($expr:expr) => {
match &$expr {
Node::Boolean { boolval: value } => value,
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! int_value {
($expr:expr) => {
match &$expr {
Node::Integer { ival: value } => value,
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! string_value {
($expr:expr) => {
match &$expr {
Node::String { sval: Some(value) } => value,
unexpected => return Err(SqlError::UnexpectedNodeType(unexpected.name())),
}
};
}
macro_rules! unsupported {
($expr:expr) => {
return Err(SqlError::Unsupported(format!("{:?}", $expr)))
};
}
pub(in crate::str) fn join_strings(
buffer: &mut String,
nodes: &[Node],
delim: &str,
) -> Result<(), SqlError> {
for (index, node) in nodes.iter().enumerate() {
if index > 0 {
buffer.push_str(delim);
}
if let Node::String { sval: Some(value) } = node {
buffer.push_str("e_identifier(value));
} else {
return Err(SqlError::UnexpectedNodeType(node.name()));
}
}
Ok(())
}
pub(in crate::str) fn quote_identifier(ident: &str) -> String {
if ident.is_empty() {
return String::new();
}
let chars = ident.chars().collect::<Vec<_>>();
let safe = chars
.iter()
.all(|c| c.is_lowercase() || c.is_ascii_digit() || *c == '_')
&& !chars[0].is_ascii_digit();
if safe && !is_keyword(ident) {
ident.to_string()
} else {
format!("\"{}\"", ident)
}
}
pub(in crate::str) fn persistence_from_code(code: char) -> Option<&'static str> {
match code {
'p' => None,
'u' => Some("UNLOGGED"),
't' => Some("TEMPORARY"),
_ => None,
}
}
pub(in crate::str) fn node_vec_to_string_vec(nodes: &[Node]) -> Vec<&String> {
nodes
.iter()
.filter_map(|n| match n {
Node::String { sval: Some(value) } => Some(value),
_ => None,
})
.collect::<Vec<_>>()
}
pub(in crate::str) fn is_operator(op: &str) -> bool {
for char in op.chars() {
match char {
'~' | '!' | '@' | '#' | '^' | '&' | '|' | '`' | '?' | '+' | '-' | '*' | '/' | '%'
| '<' | '>' | '=' => {}
_ => return false,
}
}
true
}
pub(in crate::str) fn is_keyword(ident: &str) -> bool {
matches!(
&ident.to_ascii_lowercase()[..],
"all"
| "analyse"
| "analyze"
| "and"
| "any"
| "array"
| "as"
| "asc"
| "asymmetric"
| "authorization"
| "binary"
| "both"
| "case"
| "cast"
| "check"
| "collate"
| "collation"
| "column"
| "concurrently"
| "constraint"
| "create"
| "cross"
| "current_catalog"
| "current_date"
| "current_role"
| "current_schema"
| "current_time"
| "current_timestamp"
| "current_user"
| "default"
| "deferrable"
| "desc"
| "distinct"
| "do"
| "else"
| "end"
| "except"
| "false"
| "fetch"
| "for"
| "foreign"
| "freeze"
| "from"
| "full"
| "grant"
| "group"
| "having"
| "ilike"
| "in"
| "initially"
| "inner"
| "intersect"
| "into"
| "is"
| "isnull"
| "join"
| "lateral"
| "leading"
| "left"
| "like"
| "limit"
| "localtime"
| "localtimestamp"
| "natural"
| "not"
| "notnull"
| "null"
| "offset"
| "on"
| "only"
| "or"
| "order"
| "outer"
| "overlaps"
| "placing"
| "primary"
| "references"
| "returning"
| "right"
| "select"
| "session_user"
| "similar"
| "some"
| "symmetric"
| "table"
| "tablesample"
| "then"
| "to"
| "trailing"
| "true"
| "union"
| "unique"
| "user"
| "using"
| "variadic"
| "verbose"
| "when"
| "where"
| "window"
| "with"
)
}
pub(in crate::str) fn non_reserved_word_or_sconst(
buffer: &mut String,
val: &str,
) -> Result<(), SqlError> {
if val.is_empty() {
buffer.push_str("''");
} else if val.len() >= 64 {
use crate::str::SqlBuilder;
crate::str::ext::StringLiteral(val).build(buffer)?;
} else {
buffer.push_str("e_identifier(val));
}
Ok(())
}