Skip to content

Commit

Permalink
Implement Ping and Select commands
Browse files Browse the repository at this point in the history
  • Loading branch information
ndelvalle authored and gillchristian committed Apr 12, 2024
1 parent c213ad4 commit ac648fe
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 23 deletions.
72 changes: 49 additions & 23 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub mod get;
pub mod info;
pub mod keys;
pub mod module;
pub mod ping;
pub mod select;
pub mod set;
pub mod type_;

Expand All @@ -23,7 +25,7 @@ use crate::store::Store;
use crate::Error;

use client::Client;
use command::Command as Foo;
use command::Command as Command_;
use config::Config;
use dbsize::DBSize;
use del::Del;
Expand All @@ -32,39 +34,46 @@ use get::Get;
use info::Info;
use keys::Keys;
use module::Module;
use ping::Ping;
use select::Select;
use set::Set;
use type_::Type;

#[derive(Debug, PartialEq)]
pub enum Command {
Get(Get),
Set(Set),
DBsize(DBSize),
Del(Del),
Exists(Exists),
Get(Get),
Keys(Keys),
Info(Info),
Set(Set),
Type(Type),

Client(Client),
Module(Module),
Command(Foo),
Command(Command_),
Config(Config),
Exists(Exists),
DBsize(DBSize),
Type(Type),
Info(Info),
Module(Module),
Ping(Ping),
Select(Select),
}

impl Executable for Command {
fn exec(self, store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
match self {
Command::Get(cmd) => cmd.exec(store),
Command::Set(cmd) => cmd.exec(store),
Command::Del(cmd) => cmd.exec(store),
Command::Keys(cmd) => cmd.exec(store),
Command::Info(cmd) => cmd.exec(store),
Command::Client(cmd) => cmd.exec(store),
Command::Module(cmd) => cmd.exec(store),
Command::Command(cmd) => cmd.exec(store),
Command::Config(cmd) => cmd.exec(store),
Command::Exists(cmd) => cmd.exec(store),
Command::DBsize(cmd) => cmd.exec(store),
Command::Del(cmd) => cmd.exec(store),
Command::Exists(cmd) => cmd.exec(store),
Command::Get(cmd) => cmd.exec(store),
Command::Info(cmd) => cmd.exec(store),
Command::Keys(cmd) => cmd.exec(store),
Command::Module(cmd) => cmd.exec(store),
Command::Ping(cmd) => cmd.exec(store),
Command::Select(cmd) => cmd.exec(store),
Command::Set(cmd) => cmd.exec(store),
Command::Type(cmd) => cmd.exec(store),
}
}
Expand Down Expand Up @@ -92,17 +101,19 @@ impl TryFrom<Frame> for Command {
let command_name = parser.parse_command_name()?;

match &command_name[..] {
"get" => Get::try_from(parser).map(Command::Get),
"set" => Set::try_from(parser).map(Command::Set),
"client" => Client::try_from(parser).map(Command::Client),
"command" => Command_::try_from(parser).map(Command::Command),
"config" => Config::try_from(parser).map(Command::Config),
"dbsize" => DBSize::try_from(parser).map(Command::DBsize),
"del" => Del::try_from(parser).map(Command::Del),
"keys" => Keys::try_from(parser).map(Command::Keys),
"exists" => Exists::try_from(parser).map(Command::Exists),
"dbsize" => DBSize::try_from(parser).map(Command::DBsize),
"get" => Get::try_from(parser).map(Command::Get),
"info" => Info::try_from(parser).map(Command::Info),
"client" => Client::try_from(parser).map(Command::Client),
"keys" => Keys::try_from(parser).map(Command::Keys),
"module" => Module::try_from(parser).map(Command::Module),
"command" => Foo::try_from(parser).map(Command::Command),
"config" => Config::try_from(parser).map(Command::Config),
"ping" => Ping::try_from(parser).map(Command::Ping),
"select" => Select::try_from(parser).map(Command::Select),
"set" => Set::try_from(parser).map(Command::Set),
"type" => Type::try_from(parser).map(Command::Type),
name => Err(format!("protocol error; unknown command {:?}", name).into()),
}
Expand Down Expand Up @@ -152,6 +163,21 @@ impl CommandParser {
}
}

fn next_integer(&mut self) -> Result<i64, CommandParserError> {
let frame = self
.parts
.next()
.ok_or_else(|| CommandParserError::EndOfStream)?;

match frame {
Frame::Integer(i) => Ok(i),
frame => Err(CommandParserError::InvalidFrame {
expected: "integer".to_string(),
actual: frame,
}),
}
}

fn next_bytes(&mut self) -> Result<Bytes, CommandParserError> {
let frame = self
.parts
Expand Down
40 changes: 40 additions & 0 deletions src/commands/ping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use bytes::Bytes;
use std::sync::{Arc, Mutex};

use crate::commands::executable::Executable;
use crate::commands::{CommandParser, CommandParserError};
use crate::frame::Frame;
use crate::store::Store;
use crate::Error;

/// Returns PONG if no argument is provided, otherwise return a copy of the argument as a bulk.
///
/// Ref: <https://redis.io/docs/latest/commands/ping>
#[derive(Debug, PartialEq)]
pub struct Ping {
pub payload: Option<Bytes>,
}

impl Executable for Ping {
fn exec(self, _store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
let res = self
.payload
.map_or(Frame::Bulk(Bytes::from("PONG")), Frame::Bulk);

Ok(res)
}
}

impl TryFrom<&mut CommandParser> for Ping {
type Error = Error;

fn try_from(parser: &mut CommandParser) -> Result<Self, Self::Error> {
let payload = match parser.next_bytes() {
Ok(payload) => Some(payload),
Err(CommandParserError::EndOfStream) => None,
Err(e) => return Err(e.into()),
};

Ok(Self { payload })
}
}
34 changes: 34 additions & 0 deletions src/commands/select.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use bytes::Bytes;
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;

/// Select the Redis logical database having the specified zero-based numeric index. New
/// connections always use the database 0.
///
/// Ref: <https://redis.io/docs/latest/commands/select>
#[derive(Debug, PartialEq)]
pub struct Select {
/// The GUI clients we tested send this index value as bytes. Since we are not processing this
/// value, there is no need to convert it to a number for now.
pub index: Bytes,
}

impl Executable for Select {
fn exec(self, _store: Arc<Mutex<Store>>) -> Result<Frame, Error> {
Ok(Frame::Simple("OK".to_string()))
}
}

impl TryFrom<&mut CommandParser> for Select {
type Error = Error;

fn try_from(parser: &mut CommandParser) -> Result<Self, Self::Error> {
let index = parser.next_bytes()?;
Ok(Self { index })
}
}

0 comments on commit ac648fe

Please sign in to comment.