From f37078157ddd390ae86d77a6aa4ef61caada67d3 Mon Sep 17 00:00:00 2001
From: GuilhermeStrice <15857393+GuilhermeStrice@users.noreply.github.com>
Date: Wed, 9 Jul 2025 19:31:34 +0100
Subject: [PATCH] add project
---
CommandTests/01_setup.sh | 11 +
CommandTests/02_basic_string_tests.sh | 46 ++
CommandTests/03_hash_tests.sh | 62 ++
CommandTests/04_geo_tests.sh | 35 +
CommandTests/05_bit_tests.sh | 62 ++
CommandTests/06_module_tests.sh | 25 +
CommandTests/07_list_tests.sh | 70 ++
CommandTests/08_set_tests.sh | 72 ++
CommandTests/09_sorted_set_tests.sh | 82 ++
CommandTests/10_cleanup.sh | 4 +
CommandTests/README.md | 0
CommandTests/run_all_tests.sh | 53 ++
Commands/AdvancedStringCommands.cs | 302 ++++++++
Commands/BitCommands.cs | 207 +++++
Commands/ConnectionCommands.cs | 160 ++++
Commands/DatabaseCommands.cs | 121 +++
Commands/GeoCommands.cs | 242 ++++++
Commands/HashCommands.cs | 583 ++++++++++++++
Commands/HyperLogLogCommands.cs | 117 +++
Commands/InstanceCommands.cs | 126 +++
Commands/InstanceOptions.cs | 13 +
Commands/KeyCommands.cs | 227 ++++++
Commands/ListCommands.cs | 528 +++++++++++++
Commands/ModuleCommands.cs | 99 +++
Commands/PubSubCommands.cs | 119 +++
Commands/ScriptingCommands.cs | 156 ++++
Commands/ServerCommands.cs | 296 +++++++
Commands/SetCommands.cs | 573 ++++++++++++++
Commands/SortedSetCommands.cs | 836 ++++++++++++++++++++
Commands/StatusCommand.cs | 46 ++
Commands/StreamCommands.cs | 154 ++++
Commands/StringCommands.cs | 201 +++++
Commands/TransactionCommands.cs | 134 ++++
Models/Config.cs | 108 +++
Program.cs | 87 +++
README.md | 462 +++++++++++
RedisManager.csproj | 16 +
RedisManagerClient.cs | 79 ++
RedisManagerService.ApplyCustomConfig.cs | 31 +
RedisManagerService.cs | 931 +++++++++++++++++++++++
ServiceTest/start_daemon_with_config.sh | 14 +
ServiceTest/string_command_test.sh | 18 +
Utils/Output.cs | 60 ++
Utils/RedisUtils.cs | 112 +++
44 files changed, 7680 insertions(+)
create mode 100755 CommandTests/01_setup.sh
create mode 100755 CommandTests/02_basic_string_tests.sh
create mode 100755 CommandTests/03_hash_tests.sh
create mode 100755 CommandTests/04_geo_tests.sh
create mode 100755 CommandTests/05_bit_tests.sh
create mode 100755 CommandTests/06_module_tests.sh
create mode 100755 CommandTests/07_list_tests.sh
create mode 100755 CommandTests/08_set_tests.sh
create mode 100755 CommandTests/09_sorted_set_tests.sh
create mode 100755 CommandTests/10_cleanup.sh
create mode 100644 CommandTests/README.md
create mode 100755 CommandTests/run_all_tests.sh
create mode 100644 Commands/AdvancedStringCommands.cs
create mode 100644 Commands/BitCommands.cs
create mode 100644 Commands/ConnectionCommands.cs
create mode 100644 Commands/DatabaseCommands.cs
create mode 100644 Commands/GeoCommands.cs
create mode 100644 Commands/HashCommands.cs
create mode 100644 Commands/HyperLogLogCommands.cs
create mode 100644 Commands/InstanceCommands.cs
create mode 100644 Commands/InstanceOptions.cs
create mode 100644 Commands/KeyCommands.cs
create mode 100644 Commands/ListCommands.cs
create mode 100644 Commands/ModuleCommands.cs
create mode 100644 Commands/PubSubCommands.cs
create mode 100644 Commands/ScriptingCommands.cs
create mode 100644 Commands/ServerCommands.cs
create mode 100644 Commands/SetCommands.cs
create mode 100644 Commands/SortedSetCommands.cs
create mode 100644 Commands/StatusCommand.cs
create mode 100644 Commands/StreamCommands.cs
create mode 100644 Commands/StringCommands.cs
create mode 100644 Commands/TransactionCommands.cs
create mode 100644 Models/Config.cs
create mode 100644 Program.cs
create mode 100644 RedisManager.csproj
create mode 100644 RedisManagerClient.cs
create mode 100644 RedisManagerService.ApplyCustomConfig.cs
create mode 100644 RedisManagerService.cs
create mode 100644 ServiceTest/start_daemon_with_config.sh
create mode 100755 ServiceTest/string_command_test.sh
create mode 100644 Utils/Output.cs
create mode 100644 Utils/RedisUtils.cs
diff --git a/CommandTests/01_setup.sh b/CommandTests/01_setup.sh
new file mode 100755
index 0000000..1a001e9
--- /dev/null
+++ b/CommandTests/01_setup.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+echo "=== Redis Manager Test Setup ==="
+echo "Verifying existing Redis instances..."
+
+# List instances to verify
+echo "Listing configured instances:"
+dotnet run -- list-instances
+
+echo "Setup complete!"
+echo ""
diff --git a/CommandTests/02_basic_string_tests.sh b/CommandTests/02_basic_string_tests.sh
new file mode 100755
index 0000000..d59d3ad
--- /dev/null
+++ b/CommandTests/02_basic_string_tests.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+echo "=== Basic String Commands Test ==="
+
+echo "1. Testing SET and GET..."
+dotnet run -- set "test:string" "Hello World" -i default
+dotnet run -- get "test:string" -i default
+
+echo ""
+echo "2. Testing APPEND..."
+dotnet run -- append "test:string" " - Appended!" -i default
+dotnet run -- get "test:string" -i default
+
+echo ""
+echo "3. Testing INCR/DECR..."
+dotnet run -- set "test:counter" "10" -i default
+dotnet run -- incr "test:counter" -i default
+dotnet run -- incrby "test:counter" "5" -i default
+dotnet run -- decr "test:counter" -i default
+dotnet run -- get "test:counter" -i default
+
+echo ""
+echo "4. Testing INCRBYFLOAT..."
+dotnet run -- set "test:float" "10.5" -i default
+dotnet run -- incrbyfloat "test:float" "2.3" -i default
+dotnet run -- get "test:float" -i default
+
+echo ""
+echo "5. Testing GETRANGE/SETRANGE..."
+dotnet run -- set "test:range" "Hello World" -i default
+dotnet run -- getrange "test:range" "0" "4" -i default
+dotnet run -- setrange "test:range" "6" "Redis" -i default
+dotnet run -- get "test:range" -i default
+
+echo ""
+echo "6. Testing STRLEN..."
+dotnet run -- strlen "test:range" -i default
+
+echo ""
+echo "7. Testing MGET/MSET..."
+dotnet run -- mset --pairs key1=value1,key2=value2,key3=value3 -i default
+dotnet run -- mget key1 key2 key3 -i default
+
+echo ""
+echo "Basic String Commands Test Complete!"
+echo ""
diff --git a/CommandTests/03_hash_tests.sh b/CommandTests/03_hash_tests.sh
new file mode 100755
index 0000000..5db942a
--- /dev/null
+++ b/CommandTests/03_hash_tests.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+echo "=== Testing Hash Commands ==="
+
+# Test HSET and HGET
+echo "Testing HSET and HGET..."
+dotnet run -- hset user:1000 name "John Doe" -i localhost
+dotnet run -- hset user:1000 email "john@example.com" -i localhost
+dotnet run -- hset user:1000 age "30" -i localhost
+
+dotnet run -- hget user:1000 name -i localhost
+dotnet run -- hget user:1000 email -i localhost
+dotnet run -- hget user:1000 age -i localhost
+
+# Test HGETALL
+echo "Testing HGETALL..."
+dotnet run -- hgetall user:1000 -i localhost
+
+# Test HKEYS and HVALS
+echo "Testing HKEYS and HVALS..."
+dotnet run -- hkeys user:1000 -i localhost
+dotnet run -- hvals user:1000 -i localhost
+
+# Test HEXISTS
+echo "Testing HEXISTS..."
+dotnet run -- hexists user:1000 name -i localhost
+dotnet run -- hexists user:1000 phone -i localhost
+
+# Test HLEN
+echo "Testing HLEN..."
+dotnet run -- hlen user:1000 -i localhost
+
+# Test HINCRBY and HINCRBYFLOAT
+echo "Testing HINCRBY and HINCRBYFLOAT..."
+dotnet run -- hset user:1000 score "100" -i localhost
+dotnet run -- hincrby user:1000 score "10" -i localhost
+dotnet run -- hincrbyfloat user:1000 score "5.5" -i localhost
+
+# Test HMSET and HMGET
+echo "Testing HMSET and HMGET..."
+dotnet run -- hmset user:1001 name "Jane Smith" email "jane@example.com" age "25" -i localhost
+dotnet run -- hmget user:1001 name email age -i localhost
+
+# Test HSETNX
+echo "Testing HSETNX..."
+dotnet run -- hsetnx user:1000 name "New Name" -i localhost
+dotnet run -- hsetnx user:1000 phone "123-456-7890" -i localhost
+
+# Test HSTRLEN
+echo "Testing HSTRLEN..."
+dotnet run -- hstrlen user:1000 name -i localhost
+
+# Test HDEL
+echo "Testing HDEL..."
+dotnet run -- hdel user:1000 age -i localhost
+dotnet run -- hgetall user:1000 -i localhost
+
+# Test HSCAN
+echo "Testing HSCAN..."
+dotnet run -- hscan user:1000 0 -i localhost
+
+echo "Hash tests completed!"
diff --git a/CommandTests/04_geo_tests.sh b/CommandTests/04_geo_tests.sh
new file mode 100755
index 0000000..3f41ddc
--- /dev/null
+++ b/CommandTests/04_geo_tests.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+echo "=== Geo Commands Test ==="
+
+echo "1. Testing GEOADD..."
+dotnet run -- geoadd cities 2.3522 48.8566 London 2.2945 48.8584 Paris 13.4050 52.5200 Berlin 12.4964 41.9028 Rome -i localhost
+
+echo ""
+echo "2. Testing GEOHASH..."
+dotnet run -- geohash cities London Paris -i localhost
+
+echo ""
+echo "3. Testing GEOPOS..."
+dotnet run -- geopos cities London Berlin Rome -i localhost
+
+echo ""
+echo "4. Testing GEODIST..."
+dotnet run -- geodist cities London Paris --unit km -i localhost
+dotnet run -- geodist cities London Berlin --unit mi -i localhost
+
+echo ""
+echo "5. Testing GEORADIUS..."
+dotnet run -- georadius cities 2.3522 48.8566 1000 --unit km -i localhost
+
+echo ""
+echo "6. Testing GEOHASH with multiple members..."
+dotnet run -- geohash cities London Paris Berlin Rome -i localhost
+
+echo ""
+echo "7. Testing GEOPOS with multiple members..."
+dotnet run -- geopos cities London Paris Berlin Rome -i localhost
+
+echo ""
+echo "Geo Commands Test Complete!"
+echo ""
diff --git a/CommandTests/05_bit_tests.sh b/CommandTests/05_bit_tests.sh
new file mode 100755
index 0000000..a2f0caf
--- /dev/null
+++ b/CommandTests/05_bit_tests.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+echo "=== Bit Commands Test ==="
+
+echo "1. Testing SETBIT and GETBIT..."
+dotnet run -- setbit flags 0 1 -i localhost
+dotnet run -- setbit flags 1 1 -i localhost
+dotnet run -- setbit flags 2 0 -i localhost
+dotnet run -- setbit flags 3 1 -i localhost
+dotnet run -- getbit flags 0 -i localhost
+dotnet run -- getbit flags 1 -i localhost
+dotnet run -- getbit flags 2 -i localhost
+dotnet run -- getbit flags 3 -i localhost
+
+echo ""
+echo "2. Testing BITCOUNT..."
+dotnet run -- bitcount flags -i localhost
+
+echo ""
+echo "3. Testing BITPOS..."
+dotnet run -- bitpos flags 1 -i localhost
+dotnet run -- bitpos flags 0 -i localhost
+
+echo ""
+echo "4. Testing BITFIELD..."
+dotnet run -- bitfield numbers SET u8 0 255 GET u8 0 -i localhost
+
+dotnet run -- bitfield numbers SET i16 8 32767 GET i16 8 -i localhost
+
+dotnet run -- bitfield numbers INCRBY u8 0 1 GET u8 0 -i localhost
+
+echo ""
+echo "5. Testing BITOP..."
+dotnet run -- setbit flags1 0 1 -i localhost
+dotnet run -- setbit flags1 1 0 -i localhost
+dotnet run -- setbit flags2 0 0 -i localhost
+dotnet run -- setbit flags2 1 1 -i localhost
+dotnet run -- bitop AND result flags1 flags2 -i localhost
+dotnet run -- getbit result 0 -i localhost
+dotnet run -- getbit result 1 -i localhost
+
+echo ""
+echo "6. Testing BITOP OR..."
+dotnet run -- bitop OR result_or flags1 flags2 -i localhost
+dotnet run -- getbit result_or 0 -i localhost
+dotnet run -- getbit result_or 1 -i localhost
+
+echo ""
+echo "7. Testing BITOP XOR..."
+dotnet run -- bitop XOR result_xor flags1 flags2 -i localhost
+dotnet run -- getbit result_xor 0 -i localhost
+dotnet run -- getbit result_xor 1 -i localhost
+
+echo ""
+echo "8. Testing BITOP NOT..."
+dotnet run -- bitop NOT result_not flags1 -i localhost
+dotnet run -- getbit result_not 0 -i localhost
+dotnet run -- getbit result_not 1 -i localhost
+
+echo ""
+echo "Bit Commands Test Complete!"
+echo ""
diff --git a/CommandTests/06_module_tests.sh b/CommandTests/06_module_tests.sh
new file mode 100755
index 0000000..6e30352
--- /dev/null
+++ b/CommandTests/06_module_tests.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+echo "=== Module Commands Test ==="
+
+echo "1. Testing MODULE LIST..."
+dotnet run -- module-list -i localhost
+
+echo ""
+echo "2. Testing MODULE LOAD (this may fail if no modules are available)..."
+# Note: This will likely fail unless you have Redis modules available
+dotnet run -- module-load "/path/to/module.so" "arg1" "arg2" -i localhost
+
+echo ""
+echo "3. Testing MODULE UNLOAD (this may fail if no modules are loaded)..."
+# Note: This will likely fail unless you have modules loaded
+dotnet run -- module-unload "testmodule" -i localhost
+
+echo ""
+echo "4. Testing MODULE LIST again..."
+dotnet run -- module-list -i localhost
+
+echo ""
+echo "Module Commands Test Complete!"
+echo "Note: Module commands may fail if no modules are available/loaded."
+echo ""
diff --git a/CommandTests/07_list_tests.sh b/CommandTests/07_list_tests.sh
new file mode 100755
index 0000000..c8c3a73
--- /dev/null
+++ b/CommandTests/07_list_tests.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+echo "=== Testing List Commands ==="
+
+# Test LPUSH and RPUSH
+echo "Testing LPUSH and RPUSH..."
+dotnet run -- lpush mylist "first" -i localhost
+dotnet run -- lpush mylist "second" -i localhost
+dotnet run -- rpush mylist "third" -i localhost
+dotnet run -- rpush mylist "fourth" -i localhost
+
+# Test LLEN
+echo "Testing LLEN..."
+dotnet run -- llen mylist -i localhost
+
+# Test LRANGE
+echo "Testing LRANGE..."
+dotnet run -- lrange mylist 0 -1 -i localhost
+dotnet run -- lrange mylist 0 1 -i localhost
+dotnet run -- lrange mylist 1 2 -i localhost
+
+# Test LINDEX
+echo "Testing LINDEX..."
+dotnet run -- lindex mylist 0 -i localhost
+dotnet run -- lindex mylist 1 -i localhost
+dotnet run -- lindex mylist -1 -i localhost
+
+# Test LSET
+echo "Testing LSET..."
+dotnet run -- lset mylist 1 "updated_second" -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+
+# Test LINSERT
+echo "Testing LINSERT..."
+dotnet run -- linsert mylist before "updated_second" "before_second" -i localhost
+dotnet run -- linsert mylist after "updated_second" "after_second" -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+
+# Test LREM
+echo "Testing LREM..."
+dotnet run -- lpush mylist "duplicate" -i localhost
+dotnet run -- lpush mylist "duplicate" -i localhost
+dotnet run -- lrem mylist 2 "duplicate" -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+
+# Test LTRIM
+echo "Testing LTRIM..."
+dotnet run -- ltrim mylist 1 3 -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+
+# Test LPOP and RPOP
+echo "Testing LPOP and RPOP..."
+dotnet run -- lpop mylist -i localhost
+dotnet run -- rpop mylist -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+
+# Test BLPOP and BRPOP (with timeout)
+echo "Testing BLPOP and BRPOP..."
+dotnet run -- blpop mylist 1 -i localhost
+dotnet run -- brpop mylist 1 -i localhost
+
+# Test RPOPLPUSH
+echo "Testing RPOPLPUSH..."
+dotnet run -- rpush mylist "last_item" -i localhost
+dotnet run -- rpush otherlist "existing_item" -i localhost
+dotnet run -- rpoplpush mylist otherlist -i localhost
+dotnet run -- lrange mylist 0 -1 -i localhost
+dotnet run -- lrange otherlist 0 -1 -i localhost
+
+echo "List tests completed!"
diff --git a/CommandTests/08_set_tests.sh b/CommandTests/08_set_tests.sh
new file mode 100755
index 0000000..57de0fe
--- /dev/null
+++ b/CommandTests/08_set_tests.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+echo "=== Testing Set Commands ==="
+
+# Test SADD and SMEMBERS
+echo "Testing SADD and SMEMBERS..."
+dotnet run -- sadd set1 "apple" -i localhost
+dotnet run -- sadd set1 "banana" -i localhost
+dotnet run -- sadd set1 "cherry" -i localhost
+dotnet run -- smembers set1 -i localhost
+
+# Test SISMEMBER
+echo "Testing SISMEMBER..."
+dotnet run -- sismember set1 "apple" -i localhost
+dotnet run -- sismember set1 "orange" -i localhost
+
+# Test SCARD
+echo "Testing SCARD..."
+dotnet run -- scard set1 -i localhost
+
+# Test SPOP and SRANDMEMBER
+echo "Testing SPOP and SRANDMEMBER..."
+dotnet run -- sadd set2 "one" "two" "three" "four" "five" -i localhost
+dotnet run -- spop set2 -i localhost
+dotnet run -- srandmember set2 -i localhost
+dotnet run -- srandmember set2 2 -i localhost
+
+# Test SREM
+echo "Testing SREM..."
+dotnet run -- srem set1 "banana" -i localhost
+dotnet run -- smembers set1 -i localhost
+
+# Test Set operations with multiple sets
+echo "Testing Set operations..."
+dotnet run -- sadd set3 "apple" "banana" "grape" -i localhost
+dotnet run -- sadd set4 "banana" "cherry" "date" -i localhost
+
+# Test SINTER
+echo "Testing SINTER..."
+dotnet run -- sinter set1 set3 set4 -i localhost
+
+# Test SUNION
+echo "Testing SUNION..."
+dotnet run -- sunion set1 set3 set4 -i localhost
+
+# Test SDIFF
+echo "Testing SDIFF..."
+dotnet run -- sdiff set3 set4 -i localhost
+
+# Test SINTERSTORE, SUNIONSTORE, SDIFFSTORE
+echo "Testing SINTERSTORE, SUNIONSTORE, SDIFFSTORE..."
+dotnet run -- sinterstore result1 set1 set3 -i localhost
+dotnet run -- sunionstore result2 set1 set3 -i localhost
+dotnet run -- sdiffstore result3 set3 set4 -i localhost
+
+dotnet run -- smembers result1 -i localhost
+dotnet run -- smembers result2 -i localhost
+dotnet run -- smembers result3 -i localhost
+
+# Test SSCAN
+echo "Testing SSCAN..."
+dotnet run -- sscan set3 0 -i localhost
+
+# Test SMOVE
+echo "Testing SMOVE..."
+dotnet run -- sadd source_set "item1" "item2" "item3" -i localhost
+dotnet run -- sadd dest_set "existing_item" -i localhost
+dotnet run -- smove source_set dest_set "item2" -i localhost
+dotnet run -- smembers source_set -i localhost
+dotnet run -- smembers dest_set -i localhost
+
+echo "Set tests completed!"
diff --git a/CommandTests/09_sorted_set_tests.sh b/CommandTests/09_sorted_set_tests.sh
new file mode 100755
index 0000000..511756e
--- /dev/null
+++ b/CommandTests/09_sorted_set_tests.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+echo "=== Testing Sorted Set Commands ==="
+
+# Test ZADD and ZRANGE
+echo "Testing ZADD and ZRANGE..."
+dotnet run -- zadd leaderboard 100 "player1" -i localhost
+dotnet run -- zadd leaderboard 200 "player2" -i localhost
+dotnet run -- zadd leaderboard 150 "player3" -i localhost
+dotnet run -- zrange leaderboard 0 -1 -i localhost
+dotnet run -- zrange leaderboard 0 -1 withscores -i localhost
+
+# Test ZSCORE
+echo "Testing ZSCORE..."
+dotnet run -- zscore leaderboard "player1" -i localhost
+dotnet run -- zscore leaderboard "player2" -i localhost
+
+# Test ZRANK and ZREVRANK
+echo "Testing ZRANK and ZREVRANK..."
+dotnet run -- zrank leaderboard "player1" -i localhost
+dotnet run -- zrevrank leaderboard "player1" -i localhost
+
+# Test ZCARD
+echo "Testing ZCARD..."
+dotnet run -- zcard leaderboard -i localhost
+
+# Test ZREM
+echo "Testing ZREM..."
+dotnet run -- zrem leaderboard "player2" -i localhost
+dotnet run -- zrange leaderboard 0 -1 -i localhost
+
+# Test ZRANGEBYSCORE and ZREVRANGEBYSCORE
+echo "Testing ZRANGEBYSCORE and ZREVRANGEBYSCORE..."
+dotnet run -- zadd scores 50 "user1" -i localhost
+dotnet run -- zadd scores 75 "user2" -i localhost
+dotnet run -- zadd scores 90 "user3" -i localhost
+dotnet run -- zadd scores 120 "user4" -i localhost
+
+dotnet run -- zrangebyscore scores 60 100 -i localhost
+dotnet run -- zrangebyscore scores 60 100 withscores -i localhost
+dotnet run -- zrevrangebyscore scores 100 60 -i localhost
+
+# Test ZCOUNT
+echo "Testing ZCOUNT..."
+dotnet run -- zcount scores 60 100 -i localhost
+
+# Test ZINCRBY
+echo "Testing ZINCRBY..."
+dotnet run -- zincrby scores 25 "user1" -i localhost
+dotnet run -- zscore scores "user1" -i localhost
+
+# Test ZUNIONSTORE and ZINTERSTORE
+echo "Testing ZUNIONSTORE and ZINTERSTORE..."
+dotnet run -- zadd set1 1 "a" 2 "b" 3 "c" -i localhost
+dotnet run -- zadd set2 2 "b" 3 "c" 4 "d" -i localhost
+
+dotnet run -- zunionstore union_result 2 set1 set2 -i localhost
+dotnet run -- zinterstore inter_result 2 set1 set2 -i localhost
+
+dotnet run -- zrange union_result 0 -1 withscores -i localhost
+dotnet run -- zrange inter_result 0 -1 withscores -i localhost
+
+# Test ZSCAN
+echo "Testing ZSCAN..."
+dotnet run -- zscan scores 0 -i localhost
+
+# Test ZPOPMAX and ZPOPMIN
+echo "Testing ZPOPMAX and ZPOPMIN..."
+dotnet run -- zpopmax scores -i localhost
+dotnet run -- zpopmin scores -i localhost
+
+# Test ZREMRANGEBYRANK and ZREMRANGEBYSCORE
+echo "Testing ZREMRANGEBYRANK and ZREMRANGEBYSCORE..."
+dotnet run -- zadd test_set 10 "item1" 20 "item2" 30 "item3" 40 "item4" -i localhost
+dotnet run -- zremrangebyrank test_set 1 2 -i localhost
+dotnet run -- zrange test_set 0 -1 -i localhost
+
+dotnet run -- zadd test_set2 10 "item1" 20 "item2" 30 "item3" 40 "item4" -i localhost
+dotnet run -- zremrangebyscore test_set2 15 35 -i localhost
+dotnet run -- zrange test_set2 0 -1 -i localhost
+
+echo "Sorted Set tests completed!"
diff --git a/CommandTests/10_cleanup.sh b/CommandTests/10_cleanup.sh
new file mode 100755
index 0000000..f716da7
--- /dev/null
+++ b/CommandTests/10_cleanup.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo "Flushing the current Redis database..."
+dotnet run -- flushdb -i localhost --yes
diff --git a/CommandTests/README.md b/CommandTests/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/CommandTests/run_all_tests.sh b/CommandTests/run_all_tests.sh
new file mode 100755
index 0000000..9e29fd3
--- /dev/null
+++ b/CommandTests/run_all_tests.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+echo "=========================================="
+echo "Redis Manager - Complete Test Suite"
+echo "=========================================="
+echo ""
+
+# Make all scripts executable
+chmod +x CommandTests/*.sh
+
+echo "Running setup..."
+./CommandTests/01_setup.sh
+
+echo ""
+echo "Running basic string tests..."
+./CommandTests/02_basic_string_tests.sh
+
+echo ""
+echo "Running hash tests..."
+./CommandTests/03_hash_tests.sh
+
+echo ""
+echo "Running geo tests..."
+./CommandTests/04_geo_tests.sh
+
+echo ""
+echo "Running bit tests..."
+./CommandTests/05_bit_tests.sh
+
+echo ""
+echo "Running module tests..."
+./CommandTests/06_module_tests.sh
+
+echo ""
+echo "Running list tests..."
+./CommandTests/07_list_tests.sh
+
+echo ""
+echo "Running set tests..."
+./CommandTests/08_set_tests.sh
+
+echo ""
+echo "Running sorted set tests..."
+./CommandTests/09_sorted_set_tests.sh
+
+echo ""
+echo "Running cleanup..."
+./CommandTests/10_cleanup.sh
+
+echo ""
+echo "=========================================="
+echo "All tests completed!"
+echo "=========================================="
diff --git a/Commands/AdvancedStringCommands.cs b/Commands/AdvancedStringCommands.cs
new file mode 100644
index 0000000..f8d7e98
--- /dev/null
+++ b/Commands/AdvancedStringCommands.cs
@@ -0,0 +1,302 @@
+using CommandLine;
+using StackExchange.Redis;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using RedisManager.Utils;
+
+namespace RedisManager.Commands
+{
+ ///
+ /// Contains command line options and implementations for advanced Redis string operations.
+ /// Provides functionality for APPEND, INCR, DECR, INCRBY, DECRBY, INCRBYFLOAT, GETRANGE, SETRANGE, STRLEN, MGET, and MSET commands.
+ ///
+ [Verb("append", HelpText = "Append a value to a key.")]
+ public class AppendOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "value", Required = true, HelpText = "Value to append.")]
+ public string Value { get; set; }
+ }
+
+ [Verb("incr", HelpText = "Increment the integer value of a key by one.")]
+ public class IncrOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ }
+
+ [Verb("decr", HelpText = "Decrement the integer value of a key by one.")]
+ public class DecrOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ }
+
+ [Verb("incrby", HelpText = "Increment the integer value of a key by a given amount.")]
+ public class IncrByOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "amount", Required = true, HelpText = "Amount to increment by.")]
+ public long Amount { get; set; }
+ }
+
+ [Verb("decrby", HelpText = "Decrement the integer value of a key by a given amount.")]
+ public class DecrByOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "amount", Required = true, HelpText = "Amount to decrement by.")]
+ public long Amount { get; set; }
+ }
+
+ [Verb("incrbyfloat", HelpText = "Increment the float value of a key by a given amount.")]
+ public class IncrByFloatOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "amount", Required = true, HelpText = "Amount to increment by.")]
+ public double Amount { get; set; }
+ }
+
+ [Verb("getrange", HelpText = "Get a substring of the string stored at a key.")]
+ public class GetRangeOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "start", Required = true, HelpText = "Start offset.")]
+ public long Start { get; set; }
+ [Value(2, MetaName = "end", Required = true, HelpText = "End offset.")]
+ public long End { get; set; }
+ }
+
+ [Verb("setrange", HelpText = "Overwrite part of a string at key starting at the specified offset.")]
+ public class SetRangeOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "offset", Required = true, HelpText = "Offset.")]
+ public long Offset { get; set; }
+ [Value(2, MetaName = "value", Required = true, HelpText = "Value to set.")]
+ public string Value { get; set; }
+ }
+
+ [Verb("strlen", HelpText = "Get the length of the value stored in a key.")]
+ public class StrLenOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key.")]
+ public string Key { get; set; }
+ }
+
+ [Verb("mget", HelpText = "Get the values of all the given keys.")]
+ public class MGetOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Value(0, MetaName = "keys", Min = 1, Required = true, HelpText = "Keys.")]
+ public IEnumerable Keys { get; set; }
+ }
+
+ [Verb("mset", HelpText = "Set multiple keys to multiple values.")]
+ public class MSetOptions
+ {
+ [Option('i', "instance", Required = true, HelpText = "Instance name.")]
+ public string Instance { get; set; }
+ [Option("pairs", Required = true, HelpText = "Comma-separated key=value pairs.")]
+ public string Pairs { get; set; }
+ }
+
+ public static class AdvancedStringCommands
+ {
+ ///
+ /// Executes the APPEND command to append a value to a key.
+ ///
+ /// The AppendOptions containing instance, key, and value.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunAppend(AppendOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var len = db.StringAppend(opts.Key, opts.Value);
+ Console.WriteLine(Output.Green(len.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the INCR command to increment the integer value of a key by one.
+ ///
+ /// The IncrOptions containing instance and key.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunIncr(IncrOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringIncrement(opts.Key);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the DECR command to decrement the integer value of a key by one.
+ ///
+ /// The DecrOptions containing instance and key.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunDecr(DecrOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringDecrement(opts.Key);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the INCRBY command to increment the integer value of a key by a given amount.
+ ///
+ /// The IncrByOptions containing instance, key, and amount.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunIncrBy(IncrByOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringIncrement(opts.Key, opts.Amount);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the DECRBY command to decrement the integer value of a key by a given amount.
+ ///
+ /// The DecrByOptions containing instance, key, and amount.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunDecrBy(DecrByOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringDecrement(opts.Key, opts.Amount);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the INCRBYFLOAT command to increment the float value of a key by a given amount.
+ ///
+ /// The IncrByFloatOptions containing instance, key, and amount.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunIncrByFloat(IncrByFloatOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringIncrement(opts.Key, opts.Amount);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the GETRANGE command to get a substring of the string stored at a key.
+ ///
+ /// The GetRangeOptions containing instance, key, start, and end.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunGetRange(GetRangeOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var val = db.StringGetRange(opts.Key, opts.Start, opts.End);
+ Console.WriteLine(Output.Green(val.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the SETRANGE command to overwrite part of a string at key starting at the specified offset.
+ ///
+ /// The SetRangeOptions containing instance, key, offset, and value.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunSetRange(SetRangeOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var len = db.StringSetRange(opts.Key, opts.Offset, opts.Value);
+ Console.WriteLine(Output.Green(len.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the STRLEN command to get the length of the value stored in a key.
+ ///
+ /// The StrLenOptions containing instance and key.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunStrLen(StrLenOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var len = db.StringLength(opts.Key);
+ Console.WriteLine(Output.Green(len.ToString()));
+ return 0;
+ }
+ ///
+ /// Executes the MGET command to get the values of all the given keys.
+ ///
+ /// The MGetOptions containing instance and keys.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunMGet(MGetOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var keys = opts.Keys.Select(k => (RedisKey)k).ToArray();
+ var vals = db.StringGet(keys);
+ for (int i = 0; i < keys.Length; i++)
+ {
+ Console.WriteLine(Output.Green($"{keys[i]}: {vals[i]}"));
+ }
+ return 0;
+ }
+ ///
+ /// Executes the MSET command to set multiple keys to multiple values.
+ ///
+ /// The MSetOptions containing instance and pairs.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunMSet(MSetOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+ var pairs = opts.Pairs.Split(',').Select(p => p.Split('=', 2)).Where(p => p.Length == 2).Select(p => new KeyValuePair(p[0].Trim(), p[1].Trim())).ToArray();
+ db.StringSet(pairs);
+ Console.WriteLine(Output.Green("OK"));
+ return 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Commands/BitCommands.cs b/Commands/BitCommands.cs
new file mode 100644
index 0000000..6742983
--- /dev/null
+++ b/Commands/BitCommands.cs
@@ -0,0 +1,207 @@
+using CommandLine;
+using StackExchange.Redis;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using RedisManager.Utils;
+
+using RedisManager.Commands;
+
+namespace RedisManager.Commands
+{
+ [Verb("bitcount", HelpText = "Count set bits in a string.")]
+ public class BitCountOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key name.")]
+ public string Key { get; set; }
+ [Option("start", Default = 0L, HelpText = "Start byte.")]
+ public long Start { get; set; }
+ [Option("end", Default = -1L, HelpText = "End byte.")]
+ public long End { get; set; }
+ }
+
+ [Verb("bitfield", HelpText = "Perform arbitrary bitfield integer operations on strings.")]
+ public class BitFieldOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key name.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "operations", Min = 1, Required = true, HelpText = "Bitfield operations.")]
+ public IEnumerable Operations { get; set; }
+ }
+
+ [Verb("bitop", HelpText = "Perform bitwise operations between strings.")]
+ public class BitOpOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "operation", Required = true, HelpText = "Operation (AND, OR, XOR, NOT).")]
+ public string Operation { get; set; }
+ [Value(1, MetaName = "dest-key", Required = true, HelpText = "Destination key.")]
+ public string DestKey { get; set; }
+ [Value(2, MetaName = "source-keys", Min = 1, Required = true, HelpText = "Source keys.")]
+ public IEnumerable SourceKeys { get; set; }
+ }
+
+ [Verb("bitpos", HelpText = "Find first bit set or clear in a string.")]
+ public class BitPosOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key name.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "bit", Required = true, HelpText = "Bit value (0 or 1).")]
+ public int Bit { get; set; }
+ [Option("start", Default = 0L, HelpText = "Start byte.")]
+ public long Start { get; set; }
+ [Option("end", Default = -1L, HelpText = "End byte.")]
+ public long End { get; set; }
+ }
+
+ [Verb("getbit", HelpText = "Returns the bit value at offset in the string value stored at key.")]
+ public class GetBitOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key name.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "offset", Required = true, HelpText = "Bit offset.")]
+ public long Offset { get; set; }
+ }
+
+ [Verb("setbit", HelpText = "Sets or clears the bit at offset in the string value stored at key.")]
+ public class SetBitOptions : InstanceOptions
+ {
+ [Value(0, MetaName = "key", Required = true, HelpText = "Key name.")]
+ public string Key { get; set; }
+ [Value(1, MetaName = "offset", Required = true, HelpText = "Bit offset.")]
+ public long Offset { get; set; }
+ [Value(2, MetaName = "bit", Required = true, HelpText = "Bit value (0 or 1).")]
+ public int Bit { get; set; }
+ }
+
+ public static class BitCommands
+ {
+ ///
+ /// Executes the BITCOUNT command to count set bits in a string.
+ ///
+ /// The BitCountOptions containing instance, key, start, and end.
+ /// The RedisManager configuration.
+ /// Exit code (0 for success, non-zero for failure).
+ public static int RunBitCount(BitCountOptions opts, Config config)
+ {
+ var instance = RedisUtils.GetInstance(config, opts.Instance);
+ using var redis = RedisUtils.ConnectRedis(instance);
+ var db = redis.GetDatabase();
+
+ var args = new List