use redis::Cmd;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConditionalChange {
OnlyIfExists,
OnlyIfDoesNotExist,
}
impl ConditionalChange {
pub(crate) fn add_to(&self, cmd: &mut Cmd) {
match self {
ConditionalChange::OnlyIfExists => cmd.arg("XX"),
ConditionalChange::OnlyIfDoesNotExist => cmd.arg("NX"),
};
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExpirySet {
Seconds(u64),
Milliseconds(u64),
UnixSeconds(u64),
UnixMilliseconds(u64),
KeepExisting,
Persist,
}
impl ExpirySet {
pub(crate) fn add_to(&self, cmd: &mut Cmd) {
match self {
ExpirySet::Seconds(v) => {
cmd.arg("EX").arg(v);
}
ExpirySet::Milliseconds(v) => {
cmd.arg("PX").arg(v);
}
ExpirySet::UnixSeconds(v) => {
cmd.arg("EXAT").arg(v);
}
ExpirySet::UnixMilliseconds(v) => {
cmd.arg("PXAT").arg(v);
}
ExpirySet::KeepExisting => {
cmd.arg("KEEPTTL");
}
ExpirySet::Persist => {
cmd.arg("PERSIST");
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExpireOptions {
HasNoExpiry,
HasExistingExpiry,
NewExpiryGreaterThanCurrent,
NewExpiryLessThanCurrent,
}
impl ExpireOptions {
pub(crate) fn add_to(&self, cmd: &mut Cmd) {
match self {
ExpireOptions::HasNoExpiry => cmd.arg("NX"),
ExpireOptions::HasExistingExpiry => cmd.arg("XX"),
ExpireOptions::NewExpiryGreaterThanCurrent => cmd.arg("GT"),
ExpireOptions::NewExpiryLessThanCurrent => cmd.arg("LT"),
};
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FunctionRestorePolicy {
#[default]
Append,
Flush,
Replace,
}
impl FunctionRestorePolicy {
pub(crate) fn as_arg(&self) -> &'static str {
match self {
FunctionRestorePolicy::Append => "APPEND",
FunctionRestorePolicy::Flush => "FLUSH",
FunctionRestorePolicy::Replace => "REPLACE",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClientPauseMode {
All,
Write,
}
impl ClientPauseMode {
pub(crate) fn as_arg(&self) -> &'static str {
match self {
ClientPauseMode::All => "ALL",
ClientPauseMode::Write => "WRITE",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HashFieldConditionalChange {
OnlyIfAllExist,
OnlyIfNoneExist,
}
impl HashFieldConditionalChange {
pub(crate) fn as_arg(&self) -> &'static str {
match self {
HashFieldConditionalChange::OnlyIfAllExist => "FXX",
HashFieldConditionalChange::OnlyIfNoneExist => "FNX",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MigrateOptions {
pub copy: bool,
pub replace: bool,
pub password: Option<String>,
pub username: Option<String>,
}
impl MigrateOptions {
pub(crate) fn add_to(&self, cmd: &mut Cmd) {
if self.copy {
cmd.arg("COPY");
}
if self.replace {
cmd.arg("REPLACE");
}
match (&self.username, &self.password) {
(Some(u), Some(p)) => {
cmd.arg("AUTH2").arg(u).arg(p);
}
(None, Some(p)) => {
cmd.arg("AUTH").arg(p);
}
_ => {}
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RestoreOptions {
pub replace: bool,
pub absttl: bool,
pub idletime: Option<i64>,
pub frequency: Option<i64>,
}
impl RestoreOptions {
pub(crate) fn add_to(&self, cmd: &mut Cmd) {
if self.replace {
cmd.arg("REPLACE");
}
if self.absttl {
cmd.arg("ABSTTL");
}
if let Some(i) = self.idletime {
cmd.arg("IDLETIME").arg(i);
}
if let Some(f) = self.frequency {
cmd.arg("FREQ").arg(f);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrderBy {
Asc,
Desc,
}
impl OrderBy {
pub(crate) fn as_arg(&self) -> &'static str {
match self {
OrderBy::Asc => "ASC",
OrderBy::Desc => "DESC",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limit {
pub offset: i64,
pub count: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjectType {
String,
List,
Set,
ZSet,
Hash,
Stream,
}
impl ObjectType {
pub(crate) fn to_redis(self) -> redis::ObjectType {
match self {
ObjectType::String => redis::ObjectType::String,
ObjectType::List => redis::ObjectType::List,
ObjectType::Set => redis::ObjectType::Set,
ObjectType::ZSet => redis::ObjectType::ZSet,
ObjectType::Hash => redis::ObjectType::Hash,
ObjectType::Stream => redis::ObjectType::Stream,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FlushMode {
#[default]
Sync,
Async,
}
impl FlushMode {
pub(crate) fn as_arg(&self) -> &'static str {
match self {
FlushMode::Sync => "SYNC",
FlushMode::Async => "ASYNC",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn args_of(cmd: &Cmd) -> Vec<String> {
cmd.args_iter()
.filter_map(|a| match a {
redis::Arg::Simple(bytes) => Some(String::from_utf8_lossy(bytes).into_owned()),
redis::Arg::Cursor => None,
})
.collect()
}
#[test]
fn conditional_change_args() {
let mut cmd = Cmd::new();
ConditionalChange::OnlyIfExists.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["XX"]);
let mut cmd = Cmd::new();
ConditionalChange::OnlyIfDoesNotExist.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["NX"]);
}
#[test]
fn expiry_set_args() {
let mut cmd = Cmd::new();
ExpirySet::Seconds(60).add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["EX", "60"]);
let mut cmd = Cmd::new();
ExpirySet::Milliseconds(1500).add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["PX", "1500"]);
let mut cmd = Cmd::new();
ExpirySet::KeepExisting.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["KEEPTTL"]);
let mut cmd = Cmd::new();
ExpirySet::Persist.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["PERSIST"]);
}
#[test]
fn expire_options_args() {
let cases = [
(ExpireOptions::HasNoExpiry, "NX"),
(ExpireOptions::HasExistingExpiry, "XX"),
(ExpireOptions::NewExpiryGreaterThanCurrent, "GT"),
(ExpireOptions::NewExpiryLessThanCurrent, "LT"),
];
for (opt, expected) in cases {
let mut cmd = Cmd::new();
opt.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec![expected]);
}
}
#[test]
fn simple_enum_args() {
assert_eq!(OrderBy::Asc.as_arg(), "ASC");
assert_eq!(OrderBy::Desc.as_arg(), "DESC");
assert_eq!(FlushMode::Sync.as_arg(), "SYNC");
assert_eq!(FlushMode::Async.as_arg(), "ASYNC");
}
#[test]
fn restore_options_args() {
let mut cmd = Cmd::new();
RestoreOptions::default().add_to(&mut cmd);
assert!(args_of(&cmd).is_empty());
let opts = RestoreOptions {
replace: true,
absttl: true,
idletime: Some(100),
frequency: Some(5),
};
let mut cmd = Cmd::new();
opts.add_to(&mut cmd);
assert_eq!(
args_of(&cmd),
vec!["REPLACE", "ABSTTL", "IDLETIME", "100", "FREQ", "5"]
);
}
#[test]
fn migrate_options_args() {
let mut cmd = Cmd::new();
MigrateOptions::default().add_to(&mut cmd);
assert!(args_of(&cmd).is_empty());
let opts = MigrateOptions {
copy: true,
replace: true,
password: Some("pw".into()),
username: None,
};
let mut cmd = Cmd::new();
opts.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["COPY", "REPLACE", "AUTH", "pw"]);
let opts = MigrateOptions {
copy: false,
replace: false,
password: Some("pw".into()),
username: Some("user".into()),
};
let mut cmd = Cmd::new();
opts.add_to(&mut cmd);
assert_eq!(args_of(&cmd), vec!["AUTH2", "user", "pw"]);
}
#[test]
fn misc_option_args() {
assert_eq!(ClientPauseMode::All.as_arg(), "ALL");
assert_eq!(ClientPauseMode::Write.as_arg(), "WRITE");
assert_eq!(FunctionRestorePolicy::Append.as_arg(), "APPEND");
assert_eq!(FunctionRestorePolicy::Flush.as_arg(), "FLUSH");
assert_eq!(FunctionRestorePolicy::Replace.as_arg(), "REPLACE");
assert_eq!(HashFieldConditionalChange::OnlyIfAllExist.as_arg(), "FXX");
assert_eq!(HashFieldConditionalChange::OnlyIfNoneExist.as_arg(), "FNX");
}
}