Skip to content

Commit

Permalink
feat+test: get_ex with multiple expiry options
Browse files Browse the repository at this point in the history
  • Loading branch information
arpandaze committed Jun 2, 2022
1 parent 9402ab7 commit 7845dd6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 4 deletions.
14 changes: 11 additions & 3 deletions src/commands.rs
Expand Up @@ -3,7 +3,7 @@
use crate::cmd::{cmd, Cmd, Iter};
use crate::connection::{Connection, ConnectionLike, Msg};
use crate::pipeline::Pipeline;
use crate::types::{FromRedisValue, NumericBehavior, RedisResult, ToRedisArgs, RedisWrite};
use crate::types::{FromRedisValue, NumericBehavior, RedisResult, ToRedisArgs, RedisWrite, Expiry};

#[cfg(feature = "cluster")]
use crate::cluster_pipeline::ClusterPipeline;
Expand Down Expand Up @@ -398,8 +398,16 @@ implement_commands! {
}

/// Get the value of a key and set expiration
fn get_ex<K: ToRedisArgs>(key: K, seconds: usize) {
cmd("GETEX").arg(key).arg("EX").arg(seconds)
fn get_ex<K: ToRedisArgs>(key: K, expire_at: Expiry) {
let (option, time_arg) = match expire_at {
Expiry::EX(sec) => ("EX", Some(sec)),
Expiry::PX(ms) => ("PX", Some(ms)),
Expiry::EXAT(timestamp_sec) => ("EXAT", Some(timestamp_sec)),
Expiry::PXAT(timestamp_ms) => ("PXAT", Some(timestamp_ms)),
Expiry::PERSIST => ("PERSIST", None),
};

cmd("GETEX").arg(key).arg(option).arg(time_arg)
}

/// Get the value of a key and delete it
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Expand Up @@ -372,6 +372,8 @@ pub use crate::pipeline::Pipeline;
#[cfg_attr(docsrs, doc(cfg(feature = "script")))]
pub use crate::script::{Script, ScriptInvocation};

// preserve grouping and order
#[rustfmt::skip]
pub use crate::types::{
// utility functions
from_redis_value,
Expand All @@ -385,6 +387,7 @@ pub use crate::types::{
// utility types
InfoDict,
NumericBehavior,
Expiry,

// error and result types
RedisError,
Expand Down
14 changes: 14 additions & 0 deletions src/types.rs
Expand Up @@ -25,6 +25,20 @@ macro_rules! invalid_type_error_inner {
};
}

/// Helper enum that is used to define expiry time
pub enum Expiry {
/// EX seconds -- Set the specified expire time, in seconds.
EX(usize),
/// PX milliseconds -- Set the specified expire time, in milliseconds.
PX(usize),
/// EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.
EXAT(usize),
/// PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.
PXAT(usize),
/// PERSIST -- Remove the time to live associated with the key.
PERSIST,
}

/// Helper enum that is used in some situations to describe
/// the behavior of arguments in a numeric context.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
Expand Down
52 changes: 51 additions & 1 deletion tests/test_basic.rs
@@ -1,7 +1,8 @@
#![allow(clippy::let_unit_value)]

use redis::{
Commands, ConnectionInfo, ConnectionLike, ControlFlow, ErrorKind, PubSubCommands, RedisResult,
Commands, ConnectionInfo, ConnectionLike, ControlFlow, ErrorKind, Expiry, PubSubCommands,
RedisResult,
};

use std::collections::{BTreeMap, BTreeSet};
Expand Down Expand Up @@ -64,6 +65,55 @@ fn test_incr() {
assert_eq!(redis::cmd("INCR").arg("foo").query(&mut con), Ok(43usize));
}

#[test]
fn test_getdel() {
let ctx = TestContext::new();
let mut con = ctx.connection();

redis::cmd("SET").arg("foo").arg(42).execute(&mut con);

assert_eq!(con.get_del("foo"), Ok(42usize));

assert_eq!(
redis::cmd("GET").arg("foo").query(&mut con),
Ok(None::<usize>)
);
}

#[test]
fn test_getex() {
let ctx = TestContext::new();
let mut con = ctx.connection();

redis::cmd("SET").arg("foo").arg(42usize).execute(&mut con);

// Return of get_ex must match set value
let ret_value = con.get_ex::<_, usize>("foo", Expiry::EX(1)).unwrap();
assert_eq!(ret_value, 42usize);

// Get before expiry time must also return value
sleep(Duration::from_millis(100));
let delayed_get = con.get::<_, usize>("foo").unwrap();
assert_eq!(delayed_get, 42usize);

// Get after expiry time mustn't return value
sleep(Duration::from_secs(1));
let after_expire_get = con.get::<_, Option<usize>>("foo").unwrap();
assert_eq!(after_expire_get, None);

// Persist option test prep
redis::cmd("SET").arg("foo").arg(420usize).execute(&mut con);

// Return of get_ex with persist option must match set value
let ret_value = con.get_ex::<_, usize>("foo", Expiry::PERSIST).unwrap();
assert_eq!(ret_value, 420usize);

// Get after persist get_ex must return value
sleep(Duration::from_millis(200));
let delayed_get = con.get::<_, usize>("foo").unwrap();
assert_eq!(delayed_get, 420usize);
}

#[test]
fn test_info() {
let ctx = TestContext::new();
Expand Down

0 comments on commit 7845dd6

Please sign in to comment.