use std::sync::{Arc, Mutex};
use crate::commands::executable::Executable;
use crate::commands::CommandParser;
use crate::frame::Frame;
use crate::store::Store;
use crate::Error;
#[derive(Debug, PartialEq)]
pub struct IncrByFloat {
pub key: String,
pub increment: f64,
}
impl Executable for IncrByFloat {
fn exec(self, store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
let res = store.lock().unwrap().incr_by(&self.key, self.increment);
match res {
Ok(res) => Ok(Frame::Simple(res.to_string())),
Err(msg) => Ok(Frame::Error(msg.to_string())),
}
}
}
impl TryFrom<&mut CommandParser> for IncrByFloat {
type Error = Error;
fn try_from(parser: &mut CommandParser) -> Result<Self, Self::Error> {
let key = parser.next_string()?;
let increment = parser.next_float()?;
Ok(Self { key, increment })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::Command;
use bytes::Bytes;
#[test]
fn existing_key() {
let store = Arc::new(Mutex::new(Store::new()));
let frame = Frame::Array(vec![
Frame::Bulk(Bytes::from("INCRBYFLOAT")),
Frame::Bulk(Bytes::from("key1")),
Frame::Bulk(Bytes::from("0.1")),
]);
let cmd = Command::try_from(frame).unwrap();
assert_eq!(
cmd,
Command::IncrByFloat(IncrByFloat {
key: "key1".to_string(),
increment: 0.1,
})
);
store
.lock()
.unwrap()
.set(String::from("key1"), Bytes::from("10.50"));
let result = cmd.exec(store.clone()).unwrap();
assert_eq!(result, Frame::Simple("10.6".to_string()));
assert_eq!(
store.lock().unwrap().get("key1"),
Some(&Bytes::from("10.6"))
);
}
#[test]
fn non_existing_key() {
let store = Arc::new(Mutex::new(Store::new()));
let frame = Frame::Array(vec![
Frame::Bulk(Bytes::from("INCRBYFLOAT")),
Frame::Bulk(Bytes::from("key1")),
Frame::Integer(10),
]);
let cmd = Command::try_from(frame).unwrap();
assert_eq!(
cmd,
Command::IncrByFloat(IncrByFloat {
key: "key1".to_string(),
increment: 10.00,
})
);
let result = cmd.exec(store.clone()).unwrap();
assert_eq!(result, Frame::Simple("10".to_string()));
assert_eq!(store.lock().unwrap().get("key1"), Some(&Bytes::from("10")));
}
#[test]
fn invalid_key_type() {
let store = Arc::new(Mutex::new(Store::new()));
let frame = Frame::Array(vec![
Frame::Bulk(Bytes::from("INCRBYFLOAT")),
Frame::Bulk(Bytes::from("key1")),
Frame::Integer(10),
]);
let cmd = Command::try_from(frame).unwrap();
assert_eq!(
cmd,
Command::IncrByFloat(IncrByFloat {
key: "key1".to_string(),
increment: 10.00,
})
);
store
.lock()
.unwrap()
.set(String::from("key1"), Bytes::from("value"));
let result = cmd.exec(store.clone()).unwrap();
assert_eq!(
result,
Frame::Error("value is not of the correct type or out of range".to_string())
);
assert_eq!(
store.lock().unwrap().get("key1"),
Some(&Bytes::from("value"))
);
}
}