Skip to content

Commit

Permalink
feat: implement hmget with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
kindywu committed May 8, 2024
1 parent 9192594 commit ab3982a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/backend/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ use crate::RespFrame;

#[derive(Debug)]
pub struct Store {
pub(crate) hmap: DashMap<String, DashMap<String, RespFrame>>,
pub(crate) hset: DashMap<String, DashSet<RespFrame>>,
}

impl Default for Store {
fn default() -> Self {
Self {
hmap: DashMap::<String, DashMap<String, RespFrame>>::new(),
hset: DashMap::<String, DashSet<RespFrame>>::new(),
}
}
Expand Down
64 changes: 51 additions & 13 deletions src/cmd/hmget.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Backend, BulkString, CommandError, CommandExecutor, RespArray, RespFrame, RespNull};
use crate::{Backend, CommandError, CommandExecutor, RespArray, RespFrame, SimpleError};

use super::{extract_args, validate_command};

Expand All @@ -9,16 +9,27 @@ pub struct HmGet {
}

impl CommandExecutor for HmGet {
fn execute(self, _backend: &Backend) -> RespFrame {
// println!("{:?}", self);
fn execute(self, backend: &Backend) -> RespFrame {
let mut result = RespArray::new(vec![]);
for member in self.members.iter() {
match member.as_str() {
"field1" => result.push(Some(BulkString::new("field1".to_string())).into()),
"field2" => result.push(Some(BulkString::new("field2".to_string())).into()),
_ => result.push(RespFrame::Null(RespNull {})),

match backend.hmap.get(&self.key) {
Some(item) => {
let map = item.value();
for member in self.members {
match map.get(&member) {
Some(value) => result.push(value.value().clone()),
None => result.push(RespFrame::BulkString(None)),
}
}
}
}
None => {
return RespFrame::Error(SimpleError::new(format!(
"key {} is not exist",
&self.key
)))
}
};

RespFrame::Array(Some(result))
}
}
Expand Down Expand Up @@ -61,6 +72,33 @@ mod tests {

#[test]
fn test_hmget() -> Result<()> {
let backend = &Backend::new();
let frame: RespFrame = Some(RespArray::new(vec![
Some(BulkString::new("hset".to_string())).into(),
Some(BulkString::new("myhash".to_string())).into(),
Some(BulkString::new("field1".to_string())).into(),
Some(BulkString::new("value1".to_string())).into(),
]))
.into();

let sadd = Command::try_from(frame)?;
let ret = sadd.execute(backend);

assert_eq!(ret, 1.into());

let frame: RespFrame = Some(RespArray::new(vec![
Some(BulkString::new("hset".to_string())).into(),
Some(BulkString::new("myhash".to_string())).into(),
Some(BulkString::new("field2".to_string())).into(),
Some(BulkString::new("value2".to_string())).into(),
]))
.into();

let sadd = Command::try_from(frame)?;
let ret = sadd.execute(backend);

assert_eq!(ret, 1.into());

let frame: RespFrame = Some(RespArray::new(vec![
Some(BulkString::new("hmget".to_string())).into(),
Some(BulkString::new("myhash".to_string())).into(),
Expand All @@ -71,14 +109,14 @@ mod tests {
.into();

let sadd = Command::try_from(frame)?;
let ret = sadd.execute(&Backend::new());
let ret = sadd.execute(backend);

assert_eq!(
ret,
Some(RespArray::new(vec![
Some(BulkString::new("field1".to_string())).into(),
Some(BulkString::new("field2".to_string())).into(),
RespNull::new().into(),
Some(BulkString::new("value1".to_string())).into(),
Some(BulkString::new("value2".to_string())).into(),
RespFrame::BulkString(None),
]))
.into()
);
Expand Down
68 changes: 68 additions & 0 deletions src/cmd/hset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::{Backend, CommandError, CommandExecutor, RespArray, RespFrame};

use super::{extract_args, validate_command};

#[derive(Debug)]
pub struct HSet {
key: String,
field: String,
value: RespFrame,
}

impl CommandExecutor for HSet {
fn execute(self, backend: &Backend) -> RespFrame {
let hmap = backend.hmap.entry(self.key).or_default();
match hmap.insert(self.field, self.value) {
Some(_) => 0.into(), //update
None => 1.into(), //insert
}
}
}

impl TryFrom<RespArray> for HSet {
type Error = CommandError;
fn try_from(value: RespArray) -> Result<Self, Self::Error> {
validate_command(&value, &["hset"], 3, super::ArgsCheckRule::Equal)?;

let mut args = extract_args(value, 1)?.into_iter();
match (args.next(), args.next(), args.next()) {
(
Some(RespFrame::BulkString(Some(key))),
Some(RespFrame::BulkString(Some(field))),
Some(value),
) => Ok(HSet {
key: String::from_utf8(key.0)?,
field: String::from_utf8(field.0)?,
value,
}),
_ => Err(CommandError::InvalidArgument(
"Invalid key, field or value".to_string(),
)),
}
}
}

#[cfg(test)]
mod tests {
use crate::{Backend, BulkString, Command, RespArray, RespFrame};

use super::*;
use anyhow::Result;

#[test]
fn test_hset() -> Result<()> {
let frame: RespFrame = Some(RespArray::new(vec![
Some(BulkString::new("hset".to_string())).into(),
Some(BulkString::new("myhash".to_string())).into(),
Some(BulkString::new("field1".to_string())).into(),
Some(BulkString::new("value".to_string())).into(),
]))
.into();

let sadd = Command::try_from(frame)?;
let ret = sadd.execute(&Backend::new());

assert_eq!(ret, 1.into());
Ok(())
}
}
6 changes: 5 additions & 1 deletion src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod echo;
mod hmget;
mod hset;
mod sadd;
mod sismember;
mod unrecognized;
Expand All @@ -12,7 +13,8 @@ use thiserror::Error;
use crate::{Backend, RespArray, RespError, RespFrame, SimpleString};

use self::{
echo::Echo, hmget::HmGet, sadd::SAdd, sismember::SisMember, unrecognized::Unrecognized,
echo::Echo, hmget::HmGet, hset::HSet, sadd::SAdd, sismember::SisMember,
unrecognized::Unrecognized,
};

lazy_static! {
Expand Down Expand Up @@ -43,6 +45,7 @@ pub enum Command {
SAdd(SAdd),
SisMember(SisMember),
HmGet(HmGet),
HSet(HSet),
// unrecognized command
Unrecognized(Unrecognized),
}
Expand All @@ -69,6 +72,7 @@ impl TryFrom<RespArray> for Command {
Some(RespFrame::BulkString(ref cmd)) => match cmd {
Some(cmd) => match cmd.as_ref() {
b"echo" => Ok(Echo::try_from(v)?.into()),
b"hset" => Ok(HSet::try_from(v)?.into()),
b"hmget" => Ok(HmGet::try_from(v)?.into()),
b"sadd" => Ok(SAdd::try_from(v)?.into()),
b"sismember" => Ok(SisMember::try_from(v)?.into()),
Expand Down

0 comments on commit ab3982a

Please sign in to comment.