Files
RedisManager/Commands/SortedSetCommands.cs
GuilhermeStrice f37078157d add project
2025-07-09 19:31:34 +01:00

836 lines
40 KiB
C#

using CommandLine;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using RedisManager.Utils;
namespace RedisManager.Commands
{
/// <summary>
/// Contains command line options and implementations for Redis sorted set operations.
/// Provides functionality for ZADD, ZREM, ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZCARD, ZSCORE, ZRANK, ZREVRANK, ZINCRBY, ZREVRANGEBYSCORE, ZCOUNT, ZUNIONSTORE, ZINTERSTORE, ZSCAN, ZPOPMAX, ZPOPMIN, ZREMRANGEBYRANK, and ZREMRANGEBYSCORE commands.
/// </summary>
[Verb("zadd", HelpText = "Add members to a sorted set.")]
public class ZAddOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "score", Required = true, HelpText = "Score for the member.")]
public double Score { get; set; }
[Value(2, MetaName = "member", Required = true, HelpText = "Member to add.")]
public string Member { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrem", HelpText = "Remove members from a sorted set.")]
public class ZRemOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "members", Min = 1, Required = true, HelpText = "Members to remove.")]
public IEnumerable<string> Members { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrange", HelpText = "Get range of members by rank.")]
public class ZRangeOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "start", Required = true, HelpText = "Start rank.")]
public long Start { get; set; }
[Value(2, MetaName = "stop", Required = true, HelpText = "Stop rank.")]
public long Stop { get; set; }
[Option("withscores", Required = false, HelpText = "Include scores in output.")]
public bool WithScores { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrevrange", HelpText = "Get range of members by rank (reverse order).")]
public class ZRevRangeOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "start", Required = true, HelpText = "Start rank.")]
public long Start { get; set; }
[Value(2, MetaName = "stop", Required = true, HelpText = "Stop rank.")]
public long Stop { get; set; }
[Option("withscores", Required = false, HelpText = "Include scores in output.")]
public bool WithScores { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrangebyscore", HelpText = "Get range of members by score.")]
public class ZRangeByScoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "min", Required = true, HelpText = "Minimum score.")]
public double Min { get; set; }
[Value(2, MetaName = "max", Required = true, HelpText = "Maximum score.")]
public double Max { get; set; }
[Option("withscores", Required = false, HelpText = "Include scores in output.")]
public bool WithScores { get; set; }
[Option("limit", Required = false, HelpText = "Limit results (offset count).")]
public string Limit { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zcard", HelpText = "Get the number of members in a sorted set.")]
public class ZCardOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zscore", HelpText = "Get the score of a member.")]
public class ZScoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "member", Required = true, HelpText = "Member name.")]
public string Member { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrank", HelpText = "Get the rank of a member.")]
public class ZRankOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "member", Required = true, HelpText = "Member name.")]
public string Member { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrevrank", HelpText = "Get the reverse rank of a member.")]
public class ZRevRankOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "member", Required = true, HelpText = "Member name.")]
public string Member { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zincrby", HelpText = "Increment the score of a member.")]
public class ZIncrByOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "increment", Required = true, HelpText = "Score increment.")]
public double Increment { get; set; }
[Value(2, MetaName = "member", Required = true, HelpText = "Member name.")]
public string Member { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zrevrangebyscore", HelpText = "Get range of members by score (reverse order).")]
public class ZRevRangeByScoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "max", Required = true, HelpText = "Maximum score.")]
public double Max { get; set; }
[Value(2, MetaName = "min", Required = true, HelpText = "Minimum score.")]
public double Min { get; set; }
[Option("withscores", Required = false, HelpText = "Include scores in output.")]
public bool WithScores { get; set; }
[Option("limit", Required = false, HelpText = "Limit results (offset count).")]
public string Limit { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zcount", HelpText = "Count members within a score range.")]
public class ZCountOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "min", Required = true, HelpText = "Minimum score.")]
public double Min { get; set; }
[Value(2, MetaName = "max", Required = true, HelpText = "Maximum score.")]
public double Max { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zunionstore", HelpText = "Store union of multiple sorted sets.")]
public class ZUnionStoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "destination", Required = true, HelpText = "Destination sorted set key.")]
public string Destination { get; set; }
[Value(1, MetaName = "numkeys", Required = true, HelpText = "Number of source keys.")]
public int NumKeys { get; set; }
[Value(2, MetaName = "keys", Min = 1, Required = true, HelpText = "Source sorted set keys.")]
public IEnumerable<string> Keys { get; set; }
[Option("weights", Required = false, HelpText = "Weights for each source set.")]
public IEnumerable<double> Weights { get; set; }
[Option("aggregate", Required = false, HelpText = "Aggregation method (sum, min, max).")]
public string Aggregate { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zinterstore", HelpText = "Store intersection of multiple sorted sets.")]
public class ZInterStoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "destination", Required = true, HelpText = "Destination sorted set key.")]
public string Destination { get; set; }
[Value(1, MetaName = "numkeys", Required = true, HelpText = "Number of source keys.")]
public int NumKeys { get; set; }
[Value(2, MetaName = "keys", Min = 1, Required = true, HelpText = "Source sorted set keys.")]
public IEnumerable<string> Keys { get; set; }
[Option("weights", Required = false, HelpText = "Weights for each source set.")]
public IEnumerable<double> Weights { get; set; }
[Option("aggregate", Required = false, HelpText = "Aggregation method (sum, min, max).")]
public string Aggregate { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zscan", HelpText = "Scan sorted set members.")]
public class ZScanOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "cursor", Required = true, HelpText = "Cursor position.")]
public int Cursor { get; set; }
[Option("match", Required = false, HelpText = "Pattern to match.")]
public string Match { get; set; }
[Option("count", Required = false, HelpText = "Count hint.")]
public int? Count { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zpopmax", HelpText = "Remove and return members with highest scores.")]
public class ZPopMaxOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Option("count", Required = false, HelpText = "Number of members to pop.")]
public int? Count { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zpopmin", HelpText = "Remove and return members with lowest scores.")]
public class ZPopMinOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Option("count", Required = false, HelpText = "Number of members to pop.")]
public int? Count { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zremrangebyrank", HelpText = "Remove members by rank range.")]
public class ZRemRangeByRankOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "start", Required = true, HelpText = "Start rank.")]
public long Start { get; set; }
[Value(2, MetaName = "stop", Required = true, HelpText = "Stop rank.")]
public long Stop { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
[Verb("zremrangebyscore", HelpText = "Remove members by score range.")]
public class ZRemRangeByScoreOptions
{
[Option('i', "instance", Required = true, HelpText = "Instance name.")]
public string Instance { get; set; }
[Value(0, MetaName = "key", Required = true, HelpText = "Sorted set key.")]
public string Key { get; set; }
[Value(1, MetaName = "min", Required = true, HelpText = "Minimum score.")]
public double Min { get; set; }
[Value(2, MetaName = "max", Required = true, HelpText = "Maximum score.")]
public double Max { get; set; }
[Option("table", Required = false, HelpText = "Output as table.")]
public bool Table { get; set; }
}
public static class SortedSetCommands
{
/// <summary>
/// Executes the ZADD command to add members to a sorted set.
/// </summary>
/// <param name="opts">The ZAddOptions containing instance, key, score, and member.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZAdd(ZAddOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.SortedSetAdd(opts.Key, opts.Member, opts.Score);
if (opts.Table)
{
RedisUtils.PrintTable(new[] { "Key", "Added Count" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
}
else
Console.WriteLine(Output.Green($"Added {count} new member(s)"));
return 0;
}
/// <summary>
/// Executes the ZREM command to remove members from a sorted set.
/// </summary>
/// <param name="opts">The ZRemOptions containing instance, key, and members.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRem(ZRemOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var members = opts.Members.ToArray();
var count = db.SortedSetRemove(opts.Key, members.Select(m => (RedisValue)m).ToArray());
if (opts.Table)
{
var rows = members.Select(m => new[] { m, "Removed" }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Status" }, rows);
RedisUtils.PrintTable(new[] { "Key", "Removed Count" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
}
else
Console.WriteLine(Output.Green($"Removed {count} member(s)"));
return 0;
}
/// <summary>
/// Executes the ZRANGE command to get a range of members by rank.
/// </summary>
/// <param name="opts">The ZRangeOptions 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 RunZRange(ZRangeOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.WithScores)
{
var entries = db.SortedSetRangeByRankWithScores(opts.Key, opts.Start, opts.Stop, Order.Ascending);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Score" }, rows);
}
else
{
foreach (var e in entries)
Console.WriteLine(Output.Green($"{e.Element} {e.Score}"));
}
}
else
{
var members = db.SortedSetRangeByRank(opts.Key, opts.Start, opts.Stop, Order.Ascending);
if (opts.Table)
{
var rows = members.Select(m => new[] { m.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member" }, rows);
}
else
{
foreach (var member in members)
Console.WriteLine(Output.Green(member.ToString()));
}
}
return 0;
}
/// <summary>
/// Executes the ZREVRANGE command to get a range of members by rank in reverse order.
/// </summary>
/// <param name="opts">The ZRevRangeOptions 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 RunZRevRange(ZRevRangeOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.WithScores)
{
var entries = db.SortedSetRangeByRankWithScores(opts.Key, opts.Start, opts.Stop, Order.Descending);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Score" }, rows);
}
else
{
foreach (var e in entries)
Console.WriteLine(Output.Green($"{e.Element} {e.Score}"));
}
}
else
{
var members = db.SortedSetRangeByRank(opts.Key, opts.Start, opts.Stop, Order.Descending);
if (opts.Table)
{
var rows = members.Select(m => new[] { m.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member" }, rows);
}
else
{
foreach (var member in members)
Console.WriteLine(Output.Green(member.ToString()));
}
}
return 0;
}
/// <summary>
/// Executes the ZRANGEBYSCORE command to get a range of members by score.
/// </summary>
/// <param name="opts">The ZRangeByScoreOptions containing instance, key, min, and max.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRangeByScore(ZRangeByScoreOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.WithScores)
{
var entries = db.SortedSetRangeByScoreWithScores(opts.Key, opts.Min, opts.Max, Exclude.None, Order.Ascending);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Score" }, rows);
}
else
{
foreach (var e in entries)
Console.WriteLine(Output.Green($"{e.Element} {e.Score}"));
}
}
else
{
var members = db.SortedSetRangeByScore(opts.Key, opts.Min, opts.Max, Exclude.None, Order.Ascending);
if (opts.Table)
{
var rows = members.Select(m => new[] { m.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member" }, rows);
}
else
{
foreach (var member in members)
Console.WriteLine(Output.Green(member.ToString()));
}
}
return 0;
}
/// <summary>
/// Executes the ZCARD command to get the number of members in a sorted set.
/// </summary>
/// <param name="opts">The ZCardOptions 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 RunZCard(ZCardOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.SortedSetLength(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Cardinality" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
else
Console.WriteLine(Output.Green(count.ToString()));
return 0;
}
/// <summary>
/// Executes the ZSCORE command to get the score of a member in a sorted set.
/// </summary>
/// <param name="opts">The ZScoreOptions containing instance, key, and member.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZScore(ZScoreOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var score = db.SortedSetScore(opts.Key, opts.Member);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Member", "Score" }, new List<string[]> { new[] { opts.Key, opts.Member, score?.ToString() ?? "[null]" } });
else if (score.HasValue)
Console.WriteLine(Output.Green(score.Value.ToString()));
else
Console.WriteLine(Output.Yellow("[null]"));
return 0;
}
/// <summary>
/// Executes the ZRANK command to get the rank of a member in a sorted set.
/// </summary>
/// <param name="opts">The ZRankOptions containing instance, key, and member.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRank(ZRankOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var rank = db.SortedSetRank(opts.Key, opts.Member);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Member", "Rank" }, new List<string[]> { new[] { opts.Key, opts.Member, rank?.ToString() ?? "[null]" } });
else if (rank.HasValue)
Console.WriteLine(Output.Green(rank.Value.ToString()));
else
Console.WriteLine(Output.Yellow("[null]"));
return 0;
}
/// <summary>
/// Executes the ZREVRANK command to get the reverse rank of a member in a sorted set.
/// </summary>
/// <param name="opts">The ZRevRankOptions containing instance, key, and member.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRevRank(ZRevRankOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var rank = db.SortedSetRank(opts.Key, opts.Member, Order.Descending);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Member", "Reverse Rank" }, new List<string[]> { new[] { opts.Key, opts.Member, rank?.ToString() ?? "[null]" } });
else if (rank.HasValue)
Console.WriteLine(Output.Green(rank.Value.ToString()));
else
Console.WriteLine(Output.Yellow("[null]"));
return 0;
}
/// <summary>
/// Executes the ZINCRBY command to increment the score of a member in a sorted set.
/// </summary>
/// <param name="opts">The ZIncrByOptions containing instance, key, increment, and member.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZIncrBy(ZIncrByOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var newScore = db.SortedSetIncrement(opts.Key, opts.Member, opts.Increment);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Member", "New Score" }, new List<string[]> { new[] { opts.Key, opts.Member, newScore.ToString() } });
else
Console.WriteLine(Output.Green(newScore.ToString()));
return 0;
}
/// <summary>
/// Executes the ZREVRANGEBYSCORE command to get a range of members by score in reverse order.
/// </summary>
/// <param name="opts">The ZRevRangeByScoreOptions containing instance, key, max, and min.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRevRangeByScore(ZRevRangeByScoreOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.WithScores)
{
var entries = db.SortedSetRangeByScoreWithScores(opts.Key, opts.Min, opts.Max, Exclude.None, Order.Descending);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Score" }, rows);
}
else
foreach (var entry in entries)
Console.WriteLine(Output.Green($"{entry.Element}: {entry.Score}"));
}
else
{
var members = db.SortedSetRangeByScore(opts.Key, opts.Min, opts.Max, Exclude.None, Order.Descending);
if (opts.Table)
{
var rows = members.Select(m => new string[] { m.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member" }, rows);
}
else
foreach (var member in members)
Console.WriteLine(Output.Green(member.ToString()));
}
return 0;
}
/// <summary>
/// Executes the ZCOUNT command to count members within a score range in a sorted set.
/// </summary>
/// <param name="opts">The ZCountOptions containing instance, key, min, and max.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZCount(ZCountOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.SortedSetLengthByValue(opts.Key, opts.Min, opts.Max);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Count" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
else
Console.WriteLine(Output.Green(count.ToString()));
return 0;
}
/// <summary>
/// Executes the ZUNIONSTORE command to store the union of multiple sorted sets.
/// </summary>
/// <param name="opts">The ZUnionStoreOptions containing instance, destination, numkeys, and keys.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZUnionStore(ZUnionStoreOptions 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 count = db.SortedSetCombineAndStore(SetOperation.Union, opts.Destination, keys);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Destination", "Stored Count" }, new List<string[]> { new[] { opts.Destination, count.ToString() } });
else
Console.WriteLine(Output.Green($"Stored {count} member(s) in {opts.Destination}"));
return 0;
}
/// <summary>
/// Executes the ZINTERSTORE command to store the intersection of multiple sorted sets.
/// </summary>
/// <param name="opts">The ZInterStoreOptions containing instance, destination, numkeys, and keys.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZInterStore(ZInterStoreOptions 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 count = db.SortedSetCombineAndStore(SetOperation.Intersect, opts.Destination, keys);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Destination", "Stored Count" }, new List<string[]> { new[] { opts.Destination, count.ToString() } });
else
Console.WriteLine(Output.Green($"Stored {count} member(s) in {opts.Destination}"));
return 0;
}
/// <summary>
/// Executes the ZSCAN command to scan sorted set members.
/// </summary>
/// <param name="opts">The ZScanOptions containing instance, key, cursor, and scan options.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZScan(ZScanOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var result = db.SortedSetScan(opts.Key, opts.Match ?? "*", pageSize: opts.Count ?? 10, cursor: opts.Cursor);
if (opts.Table)
{
var rows = result.Select(e => new[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Member", "Score" }, rows);
}
else
{
foreach (var entry in result)
Console.WriteLine(Output.Green($"{entry.Element}: {entry.Score}"));
}
return 0;
}
/// <summary>
/// Executes the ZPOPMAX command to remove and return members with the highest scores.
/// </summary>
/// <param name="opts">The ZPopMaxOptions containing instance, key, and count.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZPopMax(ZPopMaxOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.Count.HasValue)
{
var entries = db.SortedSetPop(opts.Key, opts.Count.Value);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Popped Member", "Score" }, rows);
}
else
foreach (var entry in entries)
Console.WriteLine(Output.Green($"{entry.Element}: {entry.Score}"));
}
else
{
var entry = db.SortedSetPop(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Popped Member", "Score" }, new List<string[]> { new[] { entry.Value.Element.ToString(), entry.Value.Score.ToString() } });
else
Console.WriteLine(Output.Green($"{entry.Value.Element}: {entry.Value.Score}"));
}
return 0;
}
/// <summary>
/// Executes the ZPOPMIN command to remove and return members with the lowest scores.
/// </summary>
/// <param name="opts">The ZPopMinOptions containing instance, key, and count.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZPopMin(ZPopMinOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
if (opts.Count.HasValue)
{
var entries = db.SortedSetPop(opts.Key, opts.Count.Value);
if (opts.Table)
{
var rows = entries.Select(e => new string[] { e.Element.ToString(), e.Score.ToString() }).ToList();
RedisUtils.PrintTable(new[] { "Popped Member", "Score" }, rows);
}
else
foreach (var entry in entries)
Console.WriteLine(Output.Green($"{entry.Element}: {entry.Score}"));
}
else
{
var entry = db.SortedSetPop(opts.Key);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Popped Member", "Score" }, new List<string[]> { new[] { entry.Value.Element.ToString(), entry.Value.Score.ToString() } });
else
Console.WriteLine(Output.Green($"{entry.Value.Element}: {entry.Value.Score}"));
}
return 0;
}
/// <summary>
/// Executes the ZREMRANGEBYRANK command to remove members by rank range.
/// </summary>
/// <param name="opts">The ZRemRangeByRankOptions 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 RunZRemRangeByRank(ZRemRangeByRankOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.SortedSetRemoveRangeByRank(opts.Key, opts.Start, opts.Stop);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Removed Count" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
else
Console.WriteLine(Output.Green($"Removed {count} member(s)"));
return 0;
}
/// <summary>
/// Executes the ZREMRANGEBYSCORE command to remove members by score range.
/// </summary>
/// <param name="opts">The ZRemRangeByScoreOptions containing instance, key, min, and max.</param>
/// <param name="config">The RedisManager configuration.</param>
/// <returns>Exit code (0 for success, non-zero for failure).</returns>
public static int RunZRemRangeByScore(ZRemRangeByScoreOptions opts, Config config)
{
var instance = RedisUtils.GetInstance(config, opts.Instance);
using var redis = RedisUtils.ConnectRedis(instance);
var db = redis.GetDatabase();
var count = db.SortedSetRemoveRangeByScore(opts.Key, opts.Min, opts.Max);
if (opts.Table)
RedisUtils.PrintTable(new[] { "Key", "Removed Count" }, new List<string[]> { new[] { opts.Key, count.ToString() } });
else
Console.WriteLine(Output.Green($"Removed {count} member(s)"));
return 0;
}
}
}