use std::io;
use kevy_resp::Reply;
use kevy_resp_client::RespClient;
use crate::{Connection, string, unexpected};
pub struct Transaction<'a> {
client: &'a mut RespClient,
live: bool,
}
impl std::fmt::Debug for Transaction<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Transaction")
.field("live", &self.live)
.finish_non_exhaustive()
}
}
impl Connection {
pub fn multi(&mut self) -> io::Result<Transaction<'_>> {
match self {
Self::Embedded(_) => Err(io::Error::new(
io::ErrorKind::Unsupported,
"MULTI/EXEC is not implemented for the embedded backend; \
call Connection methods directly (each is atomic on its own lock)",
)),
Self::Remote(client) => match client.request(&[b"MULTI".to_vec()])? {
Reply::Simple(s) if s == b"OK" => Ok(Transaction {
client,
live: true,
}),
Reply::Error(e) => Err(io::Error::other(string(e))),
other => Err(unexpected(other)),
},
}
}
}
impl<'a> Transaction<'a> {
pub fn queue(&mut self, parts: &[&[u8]]) -> io::Result<()> {
if parts.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Transaction::queue needs at least a verb",
));
}
let argv: Vec<Vec<u8>> = parts.iter().map(|p| p.to_vec()).collect();
match self.client.request(&argv)? {
Reply::Simple(s) if s == b"QUEUED" => Ok(()),
Reply::Error(e) => Err(io::Error::other(string(e))),
other => Err(unexpected(other)),
}
}
pub fn exec(mut self) -> io::Result<Vec<Reply>> {
self.live = false;
match self.client.request(&[b"EXEC".to_vec()])? {
Reply::Array(items) => Ok(items),
Reply::Nil => Ok(Vec::new()),
Reply::Error(e) => Err(io::Error::other(string(e))),
other => Err(unexpected(other)),
}
}
pub fn discard(mut self) -> io::Result<()> {
self.live = false;
match self.client.request(&[b"DISCARD".to_vec()])? {
Reply::Simple(s) if s == b"OK" => Ok(()),
Reply::Error(e) => Err(io::Error::other(string(e))),
other => Err(unexpected(other)),
}
}
}
impl Drop for Transaction<'_> {
fn drop(&mut self) {
if self.live {
let _ = self.client.request(&[b"DISCARD".to_vec()]);
}
}
}