From ceb9fbf7200b2765392cf0a2bf9aacf7b1e3d395 Mon Sep 17 00:00:00 2001 From: Murugesh-R Date: Tue, 10 Aug 2021 19:39:52 +0530 Subject: [PATCH] Add support for SUNION, SINTER and SDIFF commands --- redisless/src/command/mod.rs | 41 +++++++++++ redisless/src/server/tests/mod.rs | 21 ++++++ redisless/src/server/util/run_command.rs | 90 ++++++++++++++++++++++++ 3 files changed, 152 insertions(+) diff --git a/redisless/src/command/mod.rs b/redisless/src/command/mod.rs index 9a77da5..6ef0607 100644 --- a/redisless/src/command/mod.rs +++ b/redisless/src/command/mod.rs @@ -51,6 +51,9 @@ pub enum Command { SAdd(Key, SetValues), SCard(Key), SRem(Key, SetValues), + SUnion(Keys), + SInter(Keys), + SDiff(Keys), Del(Key), Incr(Key), IncrBy(Key, i64), @@ -338,7 +341,45 @@ impl Command { } Ok(SRem(key, values_set)) } + b"SUNION" | b"SUnion" | b"Sunion" | b"sunion" => { + let keys = &v[1..]; + if keys.is_empty() { + return Err(ArgNumber); + } + let mut keys_vec = Keys::with_capacity(keys.len()); + for key in keys { + let key = get_bytes_vec(Some(key))?; + keys_vec.push(key); + } + Ok(SUnion(keys_vec)) + } + b"SINTER" | b"SInter" | b"Sinter" | b"sinter" => { + let keys = &v[1..]; + if keys.is_empty() { + return Err(ArgNumber); + } + + let mut keys_vec = Keys::with_capacity(keys.len()); + for key in keys { + let key = get_bytes_vec(Some(key))?; + keys_vec.push(key); + } + Ok(SInter(keys_vec)) + } + b"SDIFF" | b"SDiff" | b"Sdiff" | b"sdiff" => { + let keys = &v[1..]; + if keys.is_empty() { + return Err(ArgNumber); + } + + let mut keys_vec = Keys::with_capacity(keys.len()); + for key in keys { + let key = get_bytes_vec(Some(key))?; + keys_vec.push(key); + } + Ok(SDiff(keys_vec)) + } b"DEL" | b"del" | b"Del" => { let key = get_bytes_vec(v.get(1))?; Ok(Del(key)) diff --git a/redisless/src/server/tests/mod.rs b/redisless/src/server/tests/mod.rs index 0b55d89..09a2f5c 100644 --- a/redisless/src/server/tests/mod.rs +++ b/redisless/src/server/tests/mod.rs @@ -499,6 +499,27 @@ fn sadd_scard_srem() { assert_eq!(server.stop(), Some(ServerState::Stopped)); } +#[test] +#[serial] +fn sunion_sinter_sdiff() { + let (server, mut con) = get_redis_client_connection(3358); + let values = &["val1", "val2", "val3", "val4"][..]; + let values2 = &["val4", "val5", "val6"][..]; + let values3 = &["val1", "val4", "val7"][..]; + let _: i64 = con.sadd("setkey1", values).unwrap(); + let _: i64 = con.sadd("setkey2", values2).unwrap(); + let _: i64 = con.sadd("setkey3", values3).unwrap(); + let keys = &["setkey1", "setkey2", "nokey", "setkey3"][..]; + + let x: Vec = con.sunion(keys).unwrap(); + assert_eq!(x.len(), 7); + let y: Vec = con.sinter(keys).unwrap(); + assert_eq!(y.len(), 1); + let z: Vec = con.sdiff(keys).unwrap(); + assert_eq!(z.len(), 2); + assert_eq!(server.stop(), Some(ServerState::Stopped)); +} + #[test] #[serial] fn start_and_stop_server() { diff --git a/redisless/src/server/util/run_command.rs b/redisless/src/server/util/run_command.rs index 1da775d..2526643 100644 --- a/redisless/src/server/util/run_command.rs +++ b/redisless/src/server/util/run_command.rs @@ -499,6 +499,96 @@ pub fn run_command_and_get_response( storage.swrite(&key, vals); RedisResponse::single(Integer(rem)) } + Command::SUnion(keys_vec) => { + let mut storage = lock_then_release(storage); + let mut keys = vec![]; + for key in keys_vec { + let keytype = storage.type_of(&key); + if keytype == "none".as_bytes() { + continue; + } + if keytype != "set".as_bytes() { + return RedisResponse::error(RedisCommandError::WrongTypeOperation); + } + keys.push(key.to_vec()); + } + let mut responses = Vec::::new(); + if keys.is_empty() { + return RedisResponse::array(responses); + } + let mut result: HashSet<_> = storage.sread(&keys[0]).unwrap().to_owned(); + let mut val: HashSet<_>; + keys.remove(0); + for key in keys { + val = storage.sread(&key).unwrap().to_owned(); + result = result.union(&val).cloned().collect(); + } + for elem in result { + let response = RedisResponseType::SimpleString(elem); + responses.push(response); + } + RedisResponse::array(responses) + } + Command::SInter(keys_vec) => { + let mut storage = lock_then_release(storage); + let mut keys = vec![]; + for key in keys_vec { + let keytype = storage.type_of(&key); + if keytype == "none".as_bytes() { + continue; + } + if keytype != "set".as_bytes() { + return RedisResponse::error(RedisCommandError::WrongTypeOperation); + } + keys.push(key.to_vec()); + } + let mut responses = Vec::::new(); + if keys.is_empty() { + return RedisResponse::array(responses); + } + let mut result: HashSet<_> = storage.sread(&keys[0]).unwrap().to_owned(); + let mut val: HashSet<_>; + keys.remove(0); + for key in keys { + val = storage.sread(&key).unwrap().to_owned(); + result = result.intersection(&val).cloned().collect(); + } + for elem in result { + let response = RedisResponseType::SimpleString(elem); + responses.push(response); + } + RedisResponse::array(responses) + } + Command::SDiff(keys_vec) => { + let mut storage = lock_then_release(storage); + let mut keys = vec![]; + for key in keys_vec { + let keytype = storage.type_of(&key); + if keytype == "none".as_bytes() { + continue; + } + if keytype != "set".as_bytes() { + return RedisResponse::error(RedisCommandError::WrongTypeOperation); + } + keys.push(key.to_vec()); + } + let mut responses = Vec::::new(); + if keys.is_empty() { + return RedisResponse::array(responses); + } + let mut result: HashSet<_> = storage.sread(&keys[0]).unwrap().to_owned(); + let mut val: HashSet<_>; + keys.remove(0); + for key in keys { + val = storage.sread(&key).unwrap().to_owned(); + result = result.difference(&val).cloned().collect(); + } + for elem in result { + let response = RedisResponseType::SimpleString(elem); + responses.push(response); + } + RedisResponse::array(responses) + } Command::Del(k) => { let d = lock_then_release(storage).remove(k.as_slice()); RedisResponse::single(Integer(d as i64))