use super::{Error, MetaTracker, ParserInner, Result};
use crate::{
ast::{Node, OrderBy, OrderDirection, OrderExpr, OrderNulls, OrderNullsPosition},
parser::expression::ParseExprContext,
scanner::{Keyword, Reserved, Token, TokenType},
};
impl<'s, M> ParserInner<'s, M>
where
M: MetaTracker<'s>,
{
pub(super) fn parse_order_by_required(&mut self) -> Result<OrderBy<'s, M::NodeId>> {
let order_token = expect_token!(|t = self.next_token()| "the ORDER (BY) keyword" match {
TokenType::Keyword(Keyword::ORDER) => Node((), self.meta_tracker.on_node_start(t.loc)),
});
self.parse_order_by_impl(order_token)
}
pub(super) fn parse_order_by(&mut self) -> Result<Option<OrderBy<'s, M::NodeId>>> {
let order_token = if let Some(Token {
ttype: TokenType::Keyword(Keyword::ORDER),
loc,
}) = self.peek_token()?
{
let loc = *loc;
self.consume_token()?;
Node((), self.meta_tracker.on_node_start(loc))
} else {
return Ok(None);
};
self.parse_order_by_impl(order_token).map(Some)
}
fn parse_order_by_impl(
&mut self,
order_token: Node<(), M::NodeId>,
) -> Result<OrderBy<'s, M::NodeId>> {
let siblings_token = if let Some(Token {
ttype: TokenType::Identifier(_, Some(Reserved::SIBLINGS)),
loc,
}) = self.peek_token()?
{
let loc = *loc;
self.consume_token()?;
Some(Node((), self.meta_tracker.on_node_start(loc)))
} else {
None
};
let by_token = expect_token!(|t = self.next_token()| "the BY keyword" match {
TokenType::Keyword(Keyword::BY) => Node((), self.meta_tracker.on_node_start(t.loc)),
});
let mut expressions = vec![self.parse_order_expr()?];
while let Some(Token {
ttype: TokenType::Comma,
..
}) = self.peek_token()?
{
self.consume_token()?;
self.meta_tracker.on_node_end();
expressions.push(self.parse_order_expr()?);
}
Ok(OrderBy {
order_token,
siblings_token,
by_token,
expressions,
})
}
fn parse_order_expr(&mut self) -> Result<OrderExpr<'s, M::NodeId>> {
let expr = self
.expr_parser()
.with_context(ParseExprContext::for_order_by())
.parse()?;
let direction = if let Some(Token {
ttype: TokenType::Keyword(kw @ Keyword::ASC | kw @ Keyword::DESC),
loc,
}) = self.peek_token()?
{
let dir = if matches!(kw, Keyword::ASC) {
OrderDirection::Asc
} else {
OrderDirection::Desc
};
let loc = *loc;
self.consume_token()?;
Some(Node(dir, self.meta_tracker.on_node_start(loc)))
} else {
None
};
let nulls = if let Some(Token {
ttype: TokenType::Identifier(_, Some(Reserved::NULLS)),
loc,
}) = self.peek_token()?
{
let loc = *loc;
self.consume_token()?;
let nulls_token = Node((), self.meta_tracker.on_node_start(loc));
let position = match self.next_token()? {
Some(
ref t @ Token {
ttype: TokenType::Identifier(_, Some(reserved)),
loc,
},
) => {
let pos = match reserved {
Reserved::FIRST => OrderNullsPosition::First,
Reserved::LAST => OrderNullsPosition::Last,
_ => return Err(Error::unexpected_token(t, "the FIRST or LAST keyword")),
};
let pos_id = self.meta_tracker.on_node_start(loc);
Node(pos, pos_id)
}
Some(t) => return Err(Error::unexpected_token(t, "the FIRST or LAST keyword")),
None => return unexpected_eof_err!(self, "the FIRST or LAST keyword"),
};
Some(OrderNulls {
nulls_token,
position,
})
} else {
None
};
Ok(OrderExpr {
expr,
direction,
nulls,
})
}
}