#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) enum LockMode {
#[default]
None,
ForUpdate,
ForUpdateNowait,
ForUpdateSkipLocked,
ForShare,
ForShareNowait,
ForShareSkipLocked,
}
impl LockMode {
pub(crate) fn push_tail(self, acc: &mut crate::pg::accumulator::SqlAccumulator) {
match self {
LockMode::None => {}
LockMode::ForUpdate => {
acc.push_sql(" FOR UPDATE");
}
LockMode::ForUpdateNowait => {
acc.push_sql(" FOR UPDATE NOWAIT");
}
LockMode::ForUpdateSkipLocked => {
acc.push_sql(" FOR UPDATE SKIP LOCKED");
}
LockMode::ForShare => {
acc.push_sql(" FOR SHARE");
}
LockMode::ForShareNowait => {
acc.push_sql(" FOR SHARE NOWAIT");
}
LockMode::ForShareSkipLocked => {
acc.push_sql(" FOR SHARE SKIP LOCKED");
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pg::accumulator::SqlAccumulator;
#[test]
fn none_emits_no_tail() {
let mut acc = SqlAccumulator::new("");
LockMode::None.push_tail(&mut acc);
assert_eq!(acc.sql(), "");
}
#[test]
fn for_update_emits_bare_clause() {
let mut acc = SqlAccumulator::new("");
LockMode::ForUpdate.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR UPDATE");
}
#[test]
fn for_update_nowait_emits_nowait() {
let mut acc = SqlAccumulator::new("");
LockMode::ForUpdateNowait.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR UPDATE NOWAIT");
}
#[test]
fn for_update_skip_locked_emits_skip_locked() {
let mut acc = SqlAccumulator::new("");
LockMode::ForUpdateSkipLocked.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR UPDATE SKIP LOCKED");
}
#[test]
fn for_share_emits_bare_clause() {
let mut acc = SqlAccumulator::new("");
LockMode::ForShare.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR SHARE");
}
#[test]
fn for_share_nowait_emits_nowait() {
let mut acc = SqlAccumulator::new("");
LockMode::ForShareNowait.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR SHARE NOWAIT");
}
#[test]
fn for_share_skip_locked_emits_skip_locked() {
let mut acc = SqlAccumulator::new("");
LockMode::ForShareSkipLocked.push_tail(&mut acc);
assert_eq!(acc.sql().trim(), "FOR SHARE SKIP LOCKED");
}
#[test]
fn for_share_tails_use_distinct_keywords_from_for_update() {
for (mode, expected) in [
(LockMode::ForShare, "FOR SHARE"),
(LockMode::ForShareNowait, "FOR SHARE NOWAIT"),
(LockMode::ForShareSkipLocked, "FOR SHARE SKIP LOCKED"),
] {
let mut acc = SqlAccumulator::new("");
mode.push_tail(&mut acc);
let sql = acc.sql().trim().to_owned();
assert_eq!(sql, expected, "wrong tail for {mode:?}");
assert!(
!sql.contains("FOR UPDATE"),
"FOR SHARE tail must not contain FOR UPDATE — got {sql:?} for {mode:?}"
);
}
}
#[test]
fn default_is_none() {
assert_eq!(LockMode::default(), LockMode::None);
}
}