use sqlparser::ast::Statement;
use sqlparser::dialect::Dialect;
use sqlparser::parser::{Parser, ParserError};
use sqlparser::tokenizer::{Token, Tokenizer};
#[derive(Debug)]
struct CustomPlaceholderDialect;
fn parse_placeholder_tokens(tokens: Vec<Token>) -> Vec<Token> {
let mut result = Vec::new();
let mut iter = tokens.into_iter().peekable();
while let Some(token) = iter.next() {
match token {
Token::Colon => {
if let Some(Token::LBrace) = iter.peek() {
iter.next(); let mut placeholder = ":{".to_string();
while let Some(token) = iter.next() {
match token {
Token::RBrace => {
iter.next(); placeholder.push('}');
break;
}
Token::Word(id) => placeholder.push_str(&id.value),
_ => placeholder.push_str(&token.to_string()),
}
}
result.push(Token::Placeholder(placeholder));
} else {
result.push(token);
}
}
_ => result.push(token),
}
}
result
}
pub fn parse_sql(sql: &str, dialect: &dyn Dialect) -> Result<Vec<Statement>, ParserError> {
let mut tokenizer = Tokenizer::new(dialect, sql);
let tokens = tokenizer.tokenize()?;
let tokens = parse_placeholder_tokens(tokens);
let parser = Parser::new(dialect);
let statements = parser.with_tokens(tokens).parse_statements()?;
Ok(statements)
}
#[cfg(test)]
mod test {
use super::*;
use sqlparser::dialect::Dialect;
use sqlparser::dialect::GenericDialect;
use sqlparser::dialect::MySqlDialect;
use sqlparser::dialect::PostgreSqlDialect;
use sqlparser::dialect::SQLiteDialect;
use sqlparser::keywords::Keyword::{NoKeyword, AND, ID, NAME};
use sqlparser::parser::Parser;
use sqlparser::tokenizer::Whitespace::Space;
use sqlparser::tokenizer::Word;
fn test_dialect_placeholder<'a>(dialect: &'a dyn Dialect) {
let sql = "name=:{name}";
let mut tokenizer = Tokenizer::new(dialect, sql);
let tokens = tokenizer.tokenize().unwrap();
let tokens = parse_placeholder_tokens(tokens);
let expected = vec![
Token::Word(Word {
value: "name".to_string(),
quote_style: None,
keyword: NAME,
}),
Token::Eq,
Token::Placeholder(":{name}".to_string()),
];
assert_eq!(expected, tokens);
}
#[test]
fn test_custom_placeholder() {
test_dialect_placeholder(&PostgreSqlDialect {});
test_dialect_placeholder(&MySqlDialect {});
test_dialect_placeholder(&SQLiteDialect {});
}
fn test_parser_dialect<'a>(dialect: &'a dyn Dialect) {
let sql = "SELECT name FROM users WHERE id=:{id} AND name=:{name} OR age=:{age}";
let statements = parse_sql(sql, dialect).unwrap();
assert_eq!(statements.len(), 1);
let expected: Vec<Statement> = vec![];
let parsed_sql = statements.first().unwrap().to_string();
assert_eq!(parsed_sql, "SELECT name FROM users WHERE id = :{id} AND name = :{name} OR age = :{age}");
}
#[test]
fn test_parse_sql() {
test_parser_dialect(&PostgreSqlDialect {});
test_parser_dialect(&MySqlDialect {});
test_parser_dialect(&SQLiteDialect {});
}
}