use alloc::vec::Vec;
use crate::{
expression::{parse_expression, Expression},
keywords::Keyword,
lexer::Token,
parser::{ParseError, Parser},
qualified_name::parse_qualified_name,
select::{parse_select_expr, parse_table_reference},
QualifiedName, SelectExpr, Span, Spanned, TableReference,
};
#[derive(Clone, Debug)]
pub enum DeleteFlag {
LowPriority(Span),
Quick(Span),
Ignore(Span),
}
impl Spanned for DeleteFlag {
fn span(&self) -> Span {
match &self {
DeleteFlag::LowPriority(v) => v.span(),
DeleteFlag::Quick(v) => v.span(),
DeleteFlag::Ignore(v) => v.span(),
}
}
}
#[derive(Clone, Debug)]
pub struct Delete<'a> {
pub delete_span: Span,
pub flags: Vec<DeleteFlag>,
pub from_span: Span,
pub tables: Vec<QualifiedName<'a>>,
pub using: Vec<TableReference<'a>>,
pub where_: Option<(Expression<'a>, Span)>,
pub returning: Option<(Span, Vec<SelectExpr<'a>>)>,
}
impl<'a> Spanned for Delete<'a> {
fn span(&self) -> Span {
self.delete_span
.join_span(&self.flags)
.join_span(&self.from_span)
.join_span(&self.tables)
.join_span(&self.using)
.join_span(&self.where_)
.join_span(&self.returning)
}
}
pub(crate) fn parse_delete<'a>(parser: &mut Parser<'a, '_>) -> Result<Delete<'a>, ParseError> {
let delete_span = parser.consume_keyword(Keyword::DELETE)?;
let mut flags = Vec::new();
loop {
match &parser.token {
Token::Ident(_, Keyword::LOW_PRIORITY) => flags.push(DeleteFlag::LowPriority(
parser.consume_keyword(Keyword::LOW_PRIORITY)?,
)),
Token::Ident(_, Keyword::QUICK) => {
flags.push(DeleteFlag::Quick(parser.consume_keyword(Keyword::QUICK)?))
}
Token::Ident(_, Keyword::IGNORE) => {
flags.push(DeleteFlag::Ignore(parser.consume_keyword(Keyword::IGNORE)?))
}
_ => break,
}
}
let mut tables = Vec::new();
let mut using = Vec::new();
let from_span = if let Some(from_span) = parser.skip_keyword(Keyword::FROM) {
loop {
tables.push(parse_qualified_name(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
from_span
} else {
loop {
tables.push(parse_qualified_name(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
let from_span = parser.consume_keyword(Keyword::FROM)?;
loop {
using.push(parse_table_reference(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
from_span
};
if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
if !using.is_empty() {
parser.err(
"Using not allowed in delete with table names before FROM",
&using_span,
);
}
loop {
using.push(parse_table_reference(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
}
let where_ = if let Some(span) = parser.skip_keyword(Keyword::WHERE) {
Some((parse_expression(parser, false)?, span))
} else {
None
};
let returning = if let Some(returning_span) = parser.skip_keyword(Keyword::RETURNING) {
let mut returning_exprs = Vec::new();
loop {
returning_exprs.push(parse_select_expr(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
Some((returning_span, returning_exprs))
} else {
None
};
Ok(Delete {
flags,
delete_span,
tables,
using,
from_span,
where_,
returning,
})
}