Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
Expand Down
46 changes: 35 additions & 11 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,43 @@ impl Client {
}

/// Sends a GETEX command to the Redis server.
#[allow(unused_variables)]
pub async fn get_ex(&mut self, key: &str, seconds: i64) -> Result<Option<Vec<u8>>> {
todo!("GETEX command is not implemented yet");
// let frame: Frame = GetEx::new(key, seconds).into_stream();
///
/// # Description
/// The GETEX command retrieves the value of a key stored on the Redis server and sets an expiry time.
///
/// # Arguments
///
/// * `key` - A required key to send to the server
/// * `expiry` - An optional expiry time to set
///
/// # Returns
///
/// * `Ok(Some(String))` if the key to GETEX exists
/// * `Ok(None)` if the key to GETEX does not exist
/// * `Err(RedisError)` if an error occurs
///
/// # Examples
///
/// ```ignore
/// use async_redisx::{Client, Expiry};
///
/// #[tokio::main]
/// async fn main() {
/// let mut client = Client::connect("127.0.0.1:6379").await.unwrap();
/// let resp = client.get_ex("mykey", Some(Expirt::EX(1_u64))).await?;
/// }
/// ```
pub async fn get_ex(&mut self, key: &str, expiry: Option<Expiry>) -> Result<Option<Vec<u8>>> {
let frame: Frame = GetEx::new(key, expiry).into_stream();

// self.conn.write_frame(&frame).await?;
self.conn.write_frame(&frame).await?;

// match self.read_response().await? {
// Response::Simple(data) => Ok(Some(data)),
// Response::Null => Ok(None),
// Response::Error(err) => Err(err),
// _ => Err(RedisError::UnexpectedResponseType),
// }
match self.read_response().await? {
Response::Simple(data) => Ok(Some(data)),
Response::Null => Ok(None),
Response::Error(err) => Err(err),
_ => Err(RedisError::UnexpectedResponseType),
}
}

/// Sends a MGET command to the Redis server.
Expand Down
118 changes: 118 additions & 0 deletions src/cmd/getex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/// A Redis GETEX command.
use crate::cmd::Command;
use crate::frame::Frame;
use bytes::Bytes;

#[derive(Debug)]
pub enum Expiry {
EX(u64),
PX(u64),
EXAT(u64),
PXAT(u64),
PERSIST,
}

#[derive(Debug)]
pub struct GetEx {
key: String,
expiry: Option<Expiry>,
}

impl GetEx {
/// Creates a new GetEx command.
///
/// # Arguments
///
/// * `key` - The key to get from the Redis server
/// * `expiry` - The expiry time for the key
///
/// # Returns
///
/// A new GetEx command
///
/// # Examples
///
/// ```ignore
/// let getex = GetEx::new("mykey");
/// ```
pub fn new(key: &str, expiry: Option<Expiry>) -> Self {
Self {
key: key.to_string(),
expiry,
}
}
}

impl Command for GetEx {
fn into_stream(self) -> Frame {
let mut frame: Frame = Frame::array();
frame
.push_frame_to_array(Frame::BulkString("GETEX".into()))
.unwrap();
frame
.push_frame_to_array(Frame::BulkString(Bytes::from(self.key)))
.unwrap();

if let Some(expiry) = self.expiry {
match expiry {
Expiry::EX(seconds) => {
frame
.push_frame_to_array(Frame::BulkString("EX".into()))
.unwrap();
frame
.push_frame_to_array(Frame::Integer(seconds as i64))
.unwrap();
}
Expiry::PX(milliseconds) => {
frame
.push_frame_to_array(Frame::BulkString("PX".into()))
.unwrap();
frame
.push_frame_to_array(Frame::Integer(milliseconds as i64))
.unwrap();
}
Expiry::EXAT(timestamp) => {
frame
.push_frame_to_array(Frame::BulkString("EXAT".into()))
.unwrap();
frame
.push_frame_to_array(Frame::Integer(timestamp as i64))
.unwrap();
}
Expiry::PXAT(timestamp) => {
frame
.push_frame_to_array(Frame::BulkString("PXAT".into()))
.unwrap();
frame
.push_frame_to_array(Frame::Integer(timestamp as i64))
.unwrap();
}
Expiry::PERSIST => {
frame
.push_frame_to_array(Frame::BulkString("PERSIST".into()))
.unwrap();
}
}
}
frame
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_get() {
let getex = GetEx::new("mykey", None);
let frame = getex.into_stream();

assert_eq!(
frame,
Frame::Array(vec![
Frame::BulkString("GETEX".into()),
Frame::BulkString("mykey".into()),
])
)
}
}
3 changes: 3 additions & 0 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub use ping::Ping;
mod get;
pub use get::Get;

mod getex;
pub use getex::{Expiry, GetEx};

mod set;
pub use set::Set;

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod frame;
pub use frame::Frame;

mod cmd;
pub use cmd::Expiry;

mod client;
pub use client::Client;
Expand Down