use super::{MetaTracker, ParserInner, Result};
use crate::{
ast::{ForUpdate, ForUpdateLockOptions, ForUpdateOfColumns, Node},
parser::parse_comma_separated,
scanner::{Keyword, Reserved, Token, TokenType},
};
impl<'s, M> ParserInner<'s, M>
where
M: MetaTracker<'s>,
{
pub(super) fn parse_for_update(&mut self) -> Result<Option<ForUpdate<'s, M::NodeId>>> {
if let Some(Token {
ttype: TokenType::Keyword(Keyword::FOR),
loc,
}) = self.peek_token()?
{
let for_token = {
let loc = *loc;
self.consume_token()?;
Node((), self.meta_tracker.on_node_start(loc))
};
let update_token = expect_token!(|t = self.next_token()| "the UPDATE keyword" match {
TokenType::Keyword(Keyword::UPDATE) => Node((), self.meta_tracker.on_node_start(t.loc)),
});
let of_columns = if let Some(Token {
ttype: TokenType::Keyword(Keyword::OF),
loc,
}) = self.peek_token()?
{
let of_token = {
let loc = *loc;
self.consume_token()?;
Node((), self.meta_tracker.on_node_start(loc))
};
let columns = parse_comma_separated(self, |parser| parser.parse_identifier())?;
Some(ForUpdateOfColumns { of_token, columns })
} else {
None
};
let lock_opts = if let Some(t) = self.peek_token()? {
match t.ttype {
TokenType::Keyword(Keyword::NOWAIT) => {
let loc = t.loc;
self.consume_token()?;
let nowait_token = Node((), self.meta_tracker.on_node_start(loc));
Some(ForUpdateLockOptions::NoWait { nowait_token })
}
TokenType::Identifier(_, Some(reserved)) => match reserved {
Reserved::WAIT => {
let wait_token = {
let loc = t.loc;
self.consume_token()?;
Node((), self.meta_tracker.on_node_start(loc))
};
let duration = self.parse_integer_node()?;
Some(ForUpdateLockOptions::Wait {
wait_token,
duration,
})
}
Reserved::SKIP => {
let skip_token = {
let loc = t.loc;
self.consume_token()?;
Node((), self.meta_tracker.on_node_start(loc))
};
let locked_token = expect_reserved!(|t = self.next_token()| "the LOCKED keyword" match {
Reserved::LOCKED => Node((), self.meta_tracker.on_node_start(t.loc)),
});
Some(ForUpdateLockOptions::Skip {
skip_token,
locked_token,
})
}
_ => None,
},
_ => None,
}
} else {
None
};
Ok(Some(ForUpdate {
for_token,
update_token,
of_columns,
lock_opts,
}))
} else {
Ok(None)
}
}
fn parse_integer_node(&mut self) -> Result<Node<&'s str, M::NodeId>> {
expect_token!(|t = self.next_token()| "an integer" match {
TokenType::Integer(s) => Ok(Node(s, self.meta_tracker.on_node_start(t.loc))),
})
}
}