Skip to content

Commit

Permalink
feature: add map and hmap command execute
Browse files Browse the repository at this point in the history
  • Loading branch information
luffy2025 committed Dec 1, 2024
1 parent 9237346 commit 1b68a7c
Show file tree
Hide file tree
Showing 17 changed files with 500 additions and 83 deletions.
166 changes: 166 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.93"
bytes = "1.8.0"
dashmap = "6.1.0"
enum_dispatch = "0.3.13"
lazy_static = "1.5.0"
thiserror = "2.0.3"
106 changes: 106 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::RespFrame;
use dashmap::DashMap;
use std::ops::Deref;
use std::sync::Arc;

pub struct Backend(Arc<BackendInner>);

pub struct BackendInner {
map: DashMap<String, RespFrame>,
hmap: DashMap<String, DashMap<String, RespFrame>>,
}

impl Deref for Backend {
type Target = BackendInner;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Backend {
pub fn new() -> Self {
Self::default()
}
}

impl Default for Backend {
fn default() -> Self {
Self(Arc::new(BackendInner::default()))
}
}

impl Default for BackendInner {
fn default() -> Self {
Self::new()
}
}

impl BackendInner {
pub fn new() -> Self {
Self {
map: DashMap::new(),
hmap: DashMap::new(),
}
}

pub fn get(&self, key: &str) -> Option<RespFrame> {
self.map.get(key).map(|v| v.value().clone())
}

pub fn set(&self, key: String, value: RespFrame) {
self.map.insert(key, value);
}

pub fn hget(&self, key: &str, field: &str) -> Option<RespFrame> {
self.hmap
.get(key)
.and_then(|v| v.get(field).map(|v| v.value().clone()))
}

pub fn hset(&self, key: String, field: String, value: RespFrame) {
let hmap = self.hmap.entry(key).or_default();
hmap.insert(field, value);
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::BulkString;
use anyhow::Result;

#[test]
fn test_backend_map() -> Result<()> {
let backend = Backend::new();

// test set key
backend.set("hello".into(), BulkString::new("world").into());

// test exist key
let v = backend.get("hello");
assert_eq!(v, Some(BulkString::new(b"world").into()));

// test not exist key
let v_not_exist = backend.get("not_exist_key");
assert_eq!(v_not_exist, None);
Ok(())
}

#[test]
fn test_backend_hmap() -> Result<()> {
let backend = Backend::new();
backend.hset(
"key".into(),
"field".into(),
BulkString::new("value").into(),
);

let value = backend.hget("key", "field");
assert_eq!(value, Some(BulkString::new("value").into()));

let value = backend.hget("key", "not_exist_field");
assert_eq!(value, None);
Ok(())
}
}
10 changes: 7 additions & 3 deletions src/cmd/get.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cmd::{extract_args, validate_command, CommandError, Executor};
use crate::backend::Backend;
use crate::cmd::{extract_args, validate_command, CommandError, Executor, RESP_EMPTY};
use crate::{RespArray, RespFrame};

#[allow(dead_code)]
Expand All @@ -7,8 +8,11 @@ pub struct Get {
}

impl Executor for Get {
fn execute(&self) -> Result<RespFrame, CommandError> {
todo!()
fn execute(self, backend: &Backend) -> Result<RespFrame, CommandError> {
match backend.get(&self.key) {
Some(value) => Ok(value),
None => Ok(RESP_EMPTY.clone()),
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/cmd/hget.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cmd::{extract_args, validate_command, CommandError, Executor};
use crate::backend::Backend;
use crate::cmd::{extract_args, validate_command, CommandError, Executor, RESP_EMPTY};
use crate::{RespArray, RespFrame};

#[allow(dead_code)]
Expand All @@ -8,8 +9,11 @@ pub struct HGet {
}

impl Executor for HGet {
fn execute(&self) -> Result<RespFrame, CommandError> {
todo!()
fn execute(self, backend: &Backend) -> Result<RespFrame, CommandError> {
match backend.hget(&self.key, &self.field) {
Some(value) => Ok(value),
None => Ok(RESP_EMPTY.clone()),
}
}
}

Expand Down
Loading

0 comments on commit 1b68a7c

Please sign in to comment.