Skip to content
This repository has been archived by the owner on Mar 18, 2022. It is now read-only.

Commit

Permalink
Merge pull request #49 from tbmreza/add-commands
Browse files Browse the repository at this point in the history
Add commands
  • Loading branch information
evoxmusic authored May 26, 2021
2 parents 26588eb + acd3370 commit 64f3cd7
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 56 deletions.
5 changes: 5 additions & 0 deletions clients/python/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@
for _ in range(20):
assert redis.ping()

redis.set('n', 8)
assert redis.incr('n') == 9
assert redis.decr('n') == 8

redis.set('key', 'value')
assert redis.get('key') == b'value'
assert redis.type('key') == b'string'

assert redis.get('key2') is None
assert redis.get('not existing key') is None
Expand Down
16 changes: 15 additions & 1 deletion redisless/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub enum Command {
Incr(Key),
IncrBy(Key, i64),
Exists(Key),
Type(Key),
Ttl(Key),
Pttl(Key),
Info,
Expand Down Expand Up @@ -208,13 +209,26 @@ impl Command {
}
b"INCRBY" | b"incrby" | b"IncrBy" => {
let key = get_bytes_vec(v.get(1))?;
let increment = get_bytes_vec(v.get(2)).and_then(parse_increment)?;
let increment = get_bytes_vec(v.get(2)).and_then(parse_variation)?;
Ok(IncrBy(key, increment))
}
b"DECR" | b"decr" | b"Decr" => {
let key = get_bytes_vec(v.get(1))?;
Ok(IncrBy(key, -1))
}
b"DECRBY" | b"decrby" | b"DecrBy" => {
let key = get_bytes_vec(v.get(1))?;
let decrement = get_bytes_vec(v.get(2)).and_then(parse_variation)?;
Ok(IncrBy(key, -decrement))
}
b"EXISTS" | b"exists" | b"Exists" => {
let key = get_bytes_vec(v.get(1))?;
Ok(Exists(key))
}
b"TYPE" | b"type" | b"Type" => {
let key = get_bytes_vec(v.get(1))?;
Ok(Type(key))
}
b"TTL" | b"ttl" | b"Ttl" => {
let key = get_bytes_vec(v.get(1))?;
Ok(Ttl(key))
Expand Down
2 changes: 1 addition & 1 deletion redisless/src/command/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn parse_duration(bytes: Vec<u8>) -> Result<u64, RedisCommandError> {
Ok(duration.parse::<u64>()?)
}

pub fn parse_increment(bytes: Vec<u8>) -> Result<i64, RedisCommandError> {
pub fn parse_variation(bytes: Vec<u8>) -> Result<i64, RedisCommandError> {
let delta = std::str::from_utf8(&bytes[..])?;
Ok(delta.parse::<i64>()?)
}
104 changes: 50 additions & 54 deletions redisless/src/server/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,49 @@
use redis::{cmd, Commands, RedisResult};
use redis::{Commands, Connection, RedisResult};
use std::{thread::sleep, time::Duration};

use crate::server::ServerState;
use crate::storage::in_memory::InMemoryStorage;
use crate::Server;

#[test]
#[serial]
fn test_redis_implementation() {
let port = 3366;
fn get_redis_client_connection(port: u16) -> (Server, Connection) {
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));

let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
(server, redis_client.get_connection().unwrap())
}
#[test]
#[serial]
fn test_incr_decr_commands() {
let (server, mut con) = get_redis_client_connection(3365);

let _: () = con.set("some_number", "12").unwrap();
let _: () = con.incr("some_number", 1).unwrap();
let some_number: u32 = con.get("some_number").unwrap();
assert_eq!(some_number, 13_u32);

let _: () = con.set("n", "100").unwrap();
let _: () = con.decr("n", 1).unwrap();
let n: u32 = con.get("n").unwrap();
assert_eq!(n, 99_u32);

let _: () = con.set("0", "12").unwrap();
let _: () = con.incr("0", 500).unwrap();
let value: u32 = con.get("0").unwrap();
assert_eq!(value, 512_u32);

let _: () = con.set("63", "89").unwrap();
let _: () = con.decr("63", 10).unwrap();
let value: u32 = con.get("63").unwrap();
assert_eq!(value, 79_u32);

assert_eq!(server.stop(), Some(ServerState::Stopped));
}

#[test]
#[serial]
fn test_redis_implementation() {
let (server, mut con) = get_redis_client_connection(3366);

let _: () = con.set("key", "value").unwrap();
let exists: bool = con.exists("key").unwrap();
Expand Down Expand Up @@ -48,9 +79,7 @@ fn test_redis_implementation() {
assert_eq!(x, "value3");

let _: () = con.set("intkey", "10").unwrap();
let _ = con
.send_packed_command(cmd("INCR").arg("intkey").get_packed_command().as_slice())
.unwrap();
let _: () = con.incr("intkey", 1).unwrap();

let x: u32 = con.get("intkey").unwrap();
assert_eq!(x, 11u32);
Expand Down Expand Up @@ -78,11 +107,7 @@ fn test_redis_implementation() {
#[test]
#[serial]
fn expire_and_ttl() {
let port = 3359;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3369);

let ttl: i32 = con.ttl("key").unwrap();
assert_eq!(ttl, -2);
Expand All @@ -99,7 +124,7 @@ fn expire_and_ttl() {
let ret_val: u32 = con.pexpire("key", duration).unwrap();
assert_eq!(ret_val, 1);
let ttl: i32 = con.pttl("key").unwrap();
assert!(ttl <= duration as i32 && duration as i32 - 3 < ttl);
assert!(ttl <= duration as i32 && duration as i32 - 30 < ttl);
let ttl: i32 = con.ttl("key").unwrap();
assert_eq!(ttl, (duration / 1000) as i32);
sleep(Duration::from_millis(duration as u64));
Expand All @@ -115,7 +140,7 @@ fn expire_and_ttl() {
let ret_val: u32 = con.pexpire("key", duration).unwrap();
assert_eq!(ret_val, 1);
let ttl: i32 = con.pttl("key").unwrap();
assert!(ttl <= duration as i32 && duration as i32 - 3 < ttl);
assert!(ttl <= duration as i32 && duration as i32 - 30 < ttl);
sleep(Duration::from_millis(duration as u64));
let x: Option<String> = con.get("key").ok();
assert_eq!(x, None);
Expand Down Expand Up @@ -147,12 +172,7 @@ fn expire_and_ttl() {
#[test]
#[serial]
fn get_set() {
let port = 3332;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));

let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3332);

let _: String = con.set("key1", "valueA").unwrap();
let x: String = con.getset("key1", "valueB").unwrap();
Expand All @@ -176,12 +196,7 @@ fn get_set() {
#[test]
#[serial]
fn dbsize() {
let port = 3332;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));

let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3331);

let x: u64 = redis::cmd("DBSIZE").query(&mut con).unwrap(); //con.dbsize().unwrap();
assert_eq!(x, 0);
Expand All @@ -200,12 +215,7 @@ fn dbsize() {
#[test]
#[serial]
fn mset() {
// make these first 5 lines into a macro?
let port = 3343;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3343);

let key_value_pairs = &[("key0", "val0"), ("key1", "val1"), ("key2", "val2")][..];

Expand All @@ -222,11 +232,7 @@ fn mset() {
#[test]
#[serial]
fn mset_nx() {
let port = 3342;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3342);

let key_value_pairs = &[("key0", "val0"), ("key1", "val1"), ("key2", "val2")][..];

Expand Down Expand Up @@ -256,11 +262,7 @@ fn mset_nx() {
#[test]
#[serial]
fn mget() {
let port = 3346;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3345);

let key_value_pairs = &[("key0", "val0"), ("key1", "val1"), ("key2", "val2")][..];

Expand All @@ -287,11 +289,7 @@ fn mget() {
#[test]
#[serial]
fn hset() {
let port = 3347;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3347);

let key_value_pairs = &[("fkey0", "val0"), ("fkey1", "val1"), ("fkey2", "val2")][..];
let _: () = con
Expand All @@ -307,6 +305,8 @@ fn hset() {
assert_eq!(x, None);
let x: Option<String> = con.hget("key1", "fkey3").ok();
assert_eq!(x, None);

assert_eq!(server.stop(), Some(ServerState::Stopped));
}

#[test]
Expand All @@ -328,11 +328,7 @@ fn start_and_stop_server_multiple_times() {

#[test]
fn append() {
let port = 3346;
let server = Server::new(InMemoryStorage::new(), port);
assert_eq!(server.start(), Some(ServerState::Started));
let redis_client = redis::Client::open(format!("redis://127.0.0.1:{}/", port)).unwrap();
let mut con = redis_client.get_connection().unwrap();
let (server, mut con) = get_redis_client_connection(3346);

let _: String = con.set("key1", "value1").unwrap();
let len: usize = con.append("key1", "value1").unwrap();
Expand Down
5 changes: 5 additions & 0 deletions redisless/src/server/util/run_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ pub fn run_command_and_get_response<T: Storage>(
}
}
}
Command::Type(k) => {
let mut s = lock_then_release(storage);
let value_type = s.type_of(k.as_slice());
RedisResponse::single(SimpleString(value_type.to_vec()))
}
Command::Exists(k) => {
let exists = lock_then_release(storage).contains(&k);
let exists: i64 = match exists {
Expand Down
23 changes: 23 additions & 0 deletions redisless/src/storage/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,29 @@ impl Storage for InMemoryStorage {
}
}

fn type_of(&mut self, key: &[u8]) -> &[u8] {
let t = match self.meta(key) {
Some(RedisMeta {
data_type: RedisType::String,
..
}) => "string",
Some(RedisMeta {
data_type: RedisType::List,
..
}) => "list",
Some(RedisMeta {
data_type: RedisType::Set,
..
}) => "set",
Some(RedisMeta {
data_type: RedisType::Hash,
..
}) => "hash",
None => "none",
};
t.as_bytes()
}

fn hwrite(&mut self, key: &[u8], value: HashMap<RedisString, RedisString>) {
let meta = RedisMeta::new(RedisType::Hash, None);
self.data_mapper.insert(key.to_vec(), meta);
Expand Down
1 change: 1 addition & 0 deletions redisless/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub trait Storage {
fn read(&mut self, key: &[u8]) -> Option<&[u8]>;
fn remove(&mut self, key: &[u8]) -> u32;
fn contains(&mut self, key: &[u8]) -> bool;
fn type_of(&mut self, key: &[u8]) -> &[u8];
fn hwrite(&mut self, key: &[u8], value: HashMap<RedisString, RedisString>);
fn hread(&mut self, key: &[u8], field_key: &[u8]) -> Option<&[u8]>;
fn size(&self) -> u64;
Expand Down

0 comments on commit 64f3cd7

Please sign in to comment.