add project

This commit is contained in:
GuilhermeStrice
2025-07-09 19:31:34 +01:00
parent 8d2e88edf4
commit f37078157d
44 changed files with 7680 additions and 0 deletions

528
Commands/ListCommands.cs Normal file
View File

@ -0,0 +1,528 @@
using CommandLine;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using RedisManager.Utils;
using RedisManager.Commands;
namespace RedisManager.Commands
{
[Verb("lpush", HelpText = "Push elements to the left of a list.")]
public class LPushOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "values", Min = 1, Required = true, HelpText = "Values to push.")]
public IEnumerable<string> Values { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("rpush", HelpText = "Push elements to the right of a list.")]
public class RPushOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "values", Min = 1, Required = true, HelpText = "Values to push.")]
public IEnumerable<string> Values { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lpop", HelpText = "Pop element from the left of a list.")]
public class LPopOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("rpop", HelpText = "Pop element from the right of a list.")]
public class RPopOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lrange", HelpText = "Get range of elements from a list.")]
public class LRangeOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "start", Required = true, HelpText = "Start index.")]
public long Start { get; set; }
[Value(2, MetaName = "stop", Required = true, HelpText = "Stop index.")]
public long Stop { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("llen", HelpText = "Get the length of a list.")]
public class LLenOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lindex", HelpText = "Get element at index in a list.")]
public class LIndexOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "index", Required = true, HelpText = "Element index.")]
public long Index { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lset", HelpText = "Set element at index in a list.")]
public class LSetOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "index", Required = true, HelpText = "Element index.")]
public long Index { get; set; }
[Value(2, MetaName = "value", Required = true, HelpText = "New value.")]
public string Value { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("lrem", HelpText = "Remove elements from a list.")]
public class LRemOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "count", Required = true, HelpText = "Number of elements to remove (0=all, positive=from left, negative=from right).")]
public long Count { get; set; }
[Value(2, MetaName = "value", Required = true, HelpText = "Value to remove.")]
public string Value { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("linsert", HelpText = "Insert element before or after pivot in a list.")]
public class LInsertOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "position", Required = true, HelpText = "Position: BEFORE or AFTER.")]
public string Position { get; set; }
[Value(2, MetaName = "pivot", Required = true, HelpText = "Pivot element.")]
public string Pivot { get; set; }
[Value(3, MetaName = "value", Required = true, HelpText = "Value to insert.")]
public string Value { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("ltrim", HelpText = "Trim list to specified range.")]
public class LTrimOptions : InstanceOptions
{
[Value(0, MetaName = "key", Required = true, HelpText = "List key.")]
public string Key { get; set; }
[Value(1, MetaName = "start", Required = true, HelpText = "Start index.")]
public long Start { get; set; }
[Value(2, MetaName = "stop", Required = true, HelpText = "Stop index.")]
public long Stop { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("blpop", HelpText = "Blocking pop from the left of a list.")]
public class BLPopOptions : InstanceOptions
{
[Value(0, MetaName = "keys", Min = 1, Required = true, HelpText = "List keys.")]
public IEnumerable<string> Keys { get; set; }
[Value(1, MetaName = "timeout", Required = true, HelpText = "Timeout in seconds.")]
public int Timeout { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("brpop", HelpText = "Blocking pop from the right of a list.")]
public class BRPopOptions : InstanceOptions
{
[Value(0, MetaName = "keys", Min = 1, Required = true, HelpText = "List keys.")]
public IEnumerable<string> Keys { get; set; }
[Value(1, MetaName = "timeout", Required = true, HelpText = "Timeout in seconds.")]
public int Timeout { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("rpoplpush", HelpText = "Pop from right of source, push to left of destination.")]
public class RPopLPushOptions : InstanceOptions
{
[Value(0, MetaName = "source", Required = true, HelpText = "Source list key.")]
public string Source { get; set; }
[Value(1, MetaName = "destination", Required = true, HelpText = "Destination list key.")]
public string Destination { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
public static class ListCommands
{
/// <summary>
/// Executes the LPUSH command to push elements to the left of a list.
/// </summary>
/// <param name="opts">The LPushOptions containing instance, key, and values.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLPush(LPushOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var values = opts.Values.ToArray();
var length = db.ListLeftPush(opts.Key, values.Select(v => (RedisValue)v).ToArray());
if (opts.Table)
{
var rows = values.Select(v => new[] { v, "Pushed" }).ToList();
RedisUtils.PrintTable(new[] { "Value", "Status" }, rows);
RedisUtils.PrintTable(new[] { "Key", "New Length" }, new List<string[]> { new[] { opts.Key, length.ToString() } });
}
else
Console.WriteLine(Output.Green($"Pushed {values.Length} element(s), new length: {length}"));
return 0;
}
/// <summary>
/// Executes the RPUSH command to push elements to the right of a list.
/// </summary>
/// <param name="opts">The RPushOptions containing instance, key, and values.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunRPush(RPushOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var values = opts.Values.ToArray();
var length = db.ListRightPush(opts.Key, values.Select(v => (RedisValue)v).ToArray());
if (opts.Table)
{
var rows = values.Select(v => new[] { v, "Pushed" }).ToList();
RedisUtils.PrintTable(new[] { "Value", "Status" }, rows);
RedisUtils.PrintTable(new[] { "Key", "New Length" }, new List<string[]> { new[] { opts.Key, length.ToString() } });
}
else
Console.WriteLine(Output.Green($"Pushed {values.Length} element(s), new length: {length}"));
return 0;
}
/// <summary>
/// Executes the LPOP command to pop an element from the left of a list.
/// </summary>
/// <param name="opts">The LPopOptions containing instance and key.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLPop(LPopOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var value = db.ListLeftPop(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Popped Value" }, new List<string[]> { new[] { opts.Key, value.ToString() } });
else
Console.WriteLine(Output.Green(value.ToString()));
return 0;
}
/// <summary>
/// Executes the RPOP command to pop an element from the right of a list.
/// </summary>
/// <param name="opts">The RPopOptions containing instance and key.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunRPop(RPopOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var value = db.ListRightPop(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Popped Value" }, new List<string[]> { new[] { opts.Key, value.ToString() } });
else
Console.WriteLine(Output.Green(value.ToString()));
return 0;
}
/// <summary>
/// Executes the LRANGE command to get a range of elements from a list.
/// </summary>
/// <param name="opts">The LRangeOptions containing instance, key, start, and stop.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLRange(LRangeOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var values = db.ListRange(opts.Key, opts.Start, opts.Stop);
if (opts.Table)
{
var rows = values.Select((v, i) => new[] { (opts.Start + i).ToString(), v.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Index", "Value" }, rows);
}
else
foreach (var value in values)
Console.WriteLine(Output.Green(value.ToString()));
return 0;
}
/// <summary>
/// Executes the LLEN command to get the length of a list.
/// </summary>
/// <param name="opts">The LLenOptions containing instance and key.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLLen(LLenOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var length = db.ListLength(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Length" }, new List<string[]> { new[] { opts.Key, length.ToString() } });
else
Console.WriteLine(Output.Green(length.ToString()));
return 0;
}
/// <summary>
/// Executes the LINDEX command to get the element at a specific index in a list.
/// </summary>
/// <param name="opts">The LIndexOptions containing instance, key, and index.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLIndex(LIndexOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var value = db.ListGetByIndex(opts.Key, opts.Index);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Index", "Value" }, new List<string[]> { new[] { opts.Key, opts.Index.ToString(), value.ToString() } });
else
Console.WriteLine(Output.Green(value.ToString()));
return 0;
}
/// <summary>
/// Executes the LSET command to set the element at a specific index in a list.
/// </summary>
/// <param name="opts">The LSetOptions containing instance, key, index, and value.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLSet(LSetOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
db.ListSetByIndex(opts.Key, opts.Index, opts.Value);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Index", "New Value", "Status" }, new List<string[]> { new[] { opts.Key, opts.Index.ToString(), opts.Value, "OK" } });
else
Console.WriteLine(Output.Green("OK"));
return 0;
}
/// <summary>
/// Executes the LREM command to remove elements from a list.
/// </summary>
/// <param name="opts">The LRemOptions containing instance, key, count, and value.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLRem(LRemOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.ListRemove(opts.Key, opts.Value, opts.Count);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Value", "Removed Count" }, new List<string[]> { new[] { opts.Key, opts.Value, count.ToString() } });
else
Console.WriteLine(Output.Green($"Removed {count} element(s)"));
return 0;
}
/// <summary>
/// Executes the LINSERT command to insert an element before or after a pivot in a list.
/// </summary>
/// <param name="opts">The LInsertOptions containing instance, key, position, pivot, and value.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLInsert(LInsertOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
long result;
if (opts.Position.ToUpper() == "BEFORE")
result = db.ListInsertBefore(opts.Key, opts.Pivot, opts.Value);
else
result = db.ListInsertAfter(opts.Key, opts.Pivot, opts.Value);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Position", "Pivot", "Value", "New Length" }, new List<string[]> { new[] { opts.Key, opts.Position, opts.Pivot, opts.Value, result.ToString() } });
else
Console.WriteLine(Output.Green($"New length: {result}"));
return 0;
}
/// <summary>
/// Executes the LTRIM command to trim a list to a specified range.
/// </summary>
/// <param name="opts">The LTrimOptions containing instance, key, start, and stop.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunLTrim(LTrimOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
db.ListTrim(opts.Key, opts.Start, opts.Stop);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Start", "Stop", "Status" }, new List<string[]> { new[] { opts.Key, opts.Start.ToString(), opts.Stop.ToString(), "OK" } });
else
Console.WriteLine(Output.Green("OK"));
return 0;
}
/// <summary>
/// Executes the BLPOP command to perform a blocking pop from the left of a list.
/// </summary>
/// <param name="opts">The BLPopOptions containing instance, keys, and timeout.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunBLPop(BLPopOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var args = opts.Keys.Select(k => (RedisKey)k).Cast<object>().ToList();
args.Add(opts.Timeout);
var result = db.Execute("BLPOP", args.ToArray());
if (result == null)
{
Console.WriteLine(Output.Yellow("Timeout - no elements available to pop."));
return 0;
}
var arr = (RedisResult[])result;
if (arr.Length == 2)
{
var key = arr[0]?.ToString();
var value = arr[1]?.ToString();
if (opts.Table)
{
RedisUtils.PrintTable(new[] { "Key", "Popped Value" }, new List<string[]> { new[] { key ?? "", value ?? "" } });
}
else
{
Console.WriteLine(Output.Green($"{key}: {value}"));
}
}
else
{
Console.WriteLine(Output.Yellow("Unexpected result format."));
}
return 0;
}
/// <summary>
/// Executes the BRPOP command to perform a blocking pop from the right of a list.
/// </summary>
/// <param name="opts">The BRPopOptions containing instance, keys, and timeout.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunBRPop(BRPopOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var args = opts.Keys.Select(k => (RedisKey)k).Cast<object>().ToList();
args.Add(opts.Timeout);
var result = db.Execute("BRPOP", args.ToArray());
if (result == null)
{
Console.WriteLine(Output.Yellow("Timeout - no elements available to pop."));
return 0;
}
var arr = (RedisResult[])result;
if (arr.Length == 2)
{
var key = arr[0]?.ToString();
var value = arr[1]?.ToString();
if (opts.Table)
{
RedisUtils.PrintTable(new[] { "Key", "Popped Value" }, new List<string[]> { new[] { key ?? "", value ?? "" } });
}
else
{
Console.WriteLine(Output.Green($"{key}: {value}"));
}
}
else
{
Console.WriteLine(Output.Yellow("Unexpected result format."));
}
return 0;
}
/// <summary>
/// Executes the RPOPLPUSH command to pop from the right of the source and push to the left of the destination list.
/// </summary>
/// <param name="opts">The RPopLPushOptions containing instance, source, and destination.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunRPopLPush(RPopLPushOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var result = db.ListRightPopLeftPush(opts.Source, opts.Destination);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Source", "Destination", "Popped Value" }, new List<string[]> { new[] { opts.Source, opts.Destination, result.ToString() } });
else
Console.WriteLine(Output.Green(result.ToString()));
return 0;
}
}
}