use crate::parser::error::ParseErrorKind;
use crate::parser::greedy_parse;
use crate::parser::dialect::*;
use crate::parser::ParseError;
use sqlparser::ast::Statement;
use sqlparser::tokenizer::{Token, Tokenizer};
use std::fmt::{self, Write};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)]
pub struct ActionableStatement {
pub tokens: Vec<Token>,
pub statement: Statement,
}
impl ActionableStatement {
pub fn new(dialect: ReferenceToStaticDialect, tokens: Vec<Token>) -> Result<Self, ParseError> {
if let Some(statement) = greedy_parse(dialect, tokens.clone()) {
Ok(ActionableStatement { tokens, statement })
} else {
Err(ParseError { kind: ParseErrorKind::Tokens(tokens) })
}
}
}
impl fmt::Display for ActionableStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut statement = String::new();
for token in self {
write!(statement, "{}", token)?;
}
let ends_with_semicolon = self
.into_iter()
.last()
.is_some_and(|t| matches!(t, Token::SemiColon));
if ends_with_semicolon {
write!(f, "{}", statement)?;
} else {
write!(f, "{};", statement)?;
}
Ok(())
}
}
impl IntoIterator for ActionableStatement {
type Item = Token;
type IntoIter = std::vec::IntoIter<Token>;
fn into_iter(self) -> Self::IntoIter {
self.tokens.into_iter()
}
}
impl<'a> IntoIterator for &'a ActionableStatement {
type Item = &'a Token;
type IntoIter = std::slice::Iter<'a, Token>;
fn into_iter(self) -> Self::IntoIter {
self.tokens.iter()
}
}
#[derive(Debug, Clone)]
pub struct StatementCollection {
inner: Vec<ActionableStatement>,
pub dialect: ReferenceToStaticDialect,
}
impl StatementCollection {
pub fn new(dialect: ReferenceToStaticDialect) -> Self {
StatementCollection {
inner: vec![],
dialect,
}
}
pub fn parse_sql(&mut self, sql: &str) -> Result<Self, ParseError> {
let mut tokenizer = Tokenizer::new(&*self.dialect, sql);
let tokens = tokenizer
.tokenize()
.map_err(|err| ParseError {
kind: ParseErrorKind::Tokenizer(err)
})?;
let mut current_tokens = vec![];
for token in tokens {
current_tokens.push(token.clone());
if token == Token::SemiColon {
if let Ok(stmt) = ActionableStatement::new(self.dialect, current_tokens) {
self.inner.push(stmt);
}
current_tokens = vec![]; }
}
if !current_tokens.is_empty()
&& let Ok(stmt) = ActionableStatement::new(self.dialect, current_tokens) {
self.inner.push(stmt);
}
Ok(self.clone())
}
pub fn to_strings(&self) -> Vec<String> {
self.iter()
.map(|stmt| stmt.into_iter().map(Token::to_string).collect())
.collect()
}
pub fn checksum(&self) -> u64 {
let mut hasher = DefaultHasher::new();
for tokens in self.iter() {
for token in tokens {
token.hash(&mut hasher);
}
}
hasher.finish()
}
}
impl IntoIterator for StatementCollection {
type Item = ActionableStatement;
type IntoIter = std::vec::IntoIter<ActionableStatement>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a> IntoIterator for &'a StatementCollection {
type Item = &'a ActionableStatement;
type IntoIter = std::slice::Iter<'a, ActionableStatement>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl Deref for StatementCollection {
type Target = Vec<ActionableStatement>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for StatementCollection {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl fmt::Display for StatementCollection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut output = String::new();
for statement in self {
write!(output, "{}", statement)?;
}
write!(f, "{}", output)?;
Ok(())
}
}