-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python: add BZPOPMIN and BZPOPMAX commands #1399
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ pub(crate) enum ExpectedReturnType { | |
ArrayOfArraysOfDoubleOrNull, | ||
ArrayOfKeyValuePairs, | ||
ZMPopReturnType, | ||
KeyWithMemberAndScore, | ||
} | ||
|
||
pub(crate) fn convert_to_expected_type( | ||
|
@@ -320,6 +321,28 @@ pub(crate) fn convert_to_expected_type( | |
) | ||
.into()), | ||
}, | ||
// Used by BZPOPMIN/BZPOPMAX, which return an array consisting of the key of the sorted set that was popped, the popped member, and its score. | ||
// RESP2 returns the score as a string, but RESP3 returns the score as a double. Here we convert string scores into type double. | ||
ExpectedReturnType::KeyWithMemberAndScore => match value { | ||
Value::Nil => Ok(value), | ||
Value::Array(ref array) if array.len() == 3 && matches!(array[2], Value::Double(_)) => { | ||
Ok(value) | ||
} | ||
Value::Array(mut array) | ||
if array.len() == 3 | ||
&& matches!(array[2], Value::BulkString(_) | Value::SimpleString(_)) => | ||
{ | ||
array[2] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this only convert the third argument to double? Can there be more arguments with more keys where the timeout is greater than the third argument? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
replay can be one of the following: Nil reply: when no element could be popped and the timeout expired. so when its an array replay, which means we popped an element, we want to convert just the score from string to double There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha, thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. np |
||
convert_to_expected_type(array[2].clone(), Some(ExpectedReturnType::Double))?; | ||
Ok(Value::Array(array)) | ||
} | ||
_ => Err(( | ||
ErrorKind::TypeError, | ||
"Response couldn't be converted to an array containing a key, member, and score", | ||
format!("(response was {:?})", value), | ||
) | ||
.into()), | ||
}, | ||
} | ||
} | ||
|
||
|
@@ -454,6 +477,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option<ExpectedReturnType> { | |
b"ZRANK" | b"ZREVRANK" => cmd | ||
.position(b"WITHSCORE") | ||
.map(|_| ExpectedReturnType::ZRankReturnType), | ||
b"BZPOPMIN" | b"BZPOPMAX" => Some(ExpectedReturnType::KeyWithMemberAndScore), | ||
b"SPOP" => { | ||
if cmd.arg_idx(2).is_some() { | ||
Some(ExpectedReturnType::Set) | ||
|
@@ -815,6 +839,70 @@ mod tests { | |
)); | ||
} | ||
|
||
#[test] | ||
fn convert_bzpopmin_bzpopmax() { | ||
assert!(matches!( | ||
expected_type_for_cmd( | ||
redis::cmd("BZPOPMIN") | ||
.arg("myzset1") | ||
.arg("myzset2") | ||
.arg("1") | ||
), | ||
Some(ExpectedReturnType::KeyWithMemberAndScore) | ||
)); | ||
|
||
assert!(matches!( | ||
expected_type_for_cmd( | ||
redis::cmd("BZPOPMAX") | ||
.arg("myzset1") | ||
.arg("myzset2") | ||
.arg("1") | ||
), | ||
Some(ExpectedReturnType::KeyWithMemberAndScore) | ||
)); | ||
|
||
let array_with_double_score = Value::Array(vec![ | ||
Value::BulkString(b"key1".to_vec()), | ||
Value::BulkString(b"member1".to_vec()), | ||
Value::Double(2.0), | ||
]); | ||
let result = convert_to_expected_type( | ||
array_with_double_score.clone(), | ||
Some(ExpectedReturnType::KeyWithMemberAndScore), | ||
) | ||
.unwrap(); | ||
assert_eq!(array_with_double_score, result); | ||
|
||
let array_with_string_score = Value::Array(vec![ | ||
Value::BulkString(b"key1".to_vec()), | ||
Value::BulkString(b"member1".to_vec()), | ||
Value::BulkString(b"2.0".to_vec()), | ||
]); | ||
let result = convert_to_expected_type( | ||
array_with_string_score.clone(), | ||
Some(ExpectedReturnType::KeyWithMemberAndScore), | ||
) | ||
.unwrap(); | ||
assert_eq!(array_with_double_score, result); | ||
|
||
let converted_nil_value = | ||
convert_to_expected_type(Value::Nil, Some(ExpectedReturnType::KeyWithMemberAndScore)) | ||
.unwrap(); | ||
assert_eq!(Value::Nil, converted_nil_value); | ||
|
||
let array_with_unexpected_length = Value::Array(vec![ | ||
Value::BulkString(b"key1".to_vec()), | ||
Value::BulkString(b"member1".to_vec()), | ||
Value::Double(2.0), | ||
Value::Double(2.0), | ||
]); | ||
assert!(convert_to_expected_type( | ||
array_with_unexpected_length, | ||
Some(ExpectedReturnType::KeyWithMemberAndScore) | ||
) | ||
.is_err()); | ||
} | ||
|
||
#[test] | ||
fn convert_zank_zrevrank_only_if_withsocres_is_included() { | ||
assert!(matches!( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come this wasn't included in the Java implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ig it was forgotten, good catch:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah its because the conversion is needed for RESP2 responses. The Java wrapper doesn't support RESP2 yet but Python does