using CommandLine; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using RedisManager.Utils; using RedisManager.Commands; namespace RedisManager.Commands { [Verb("sadd", HelpText = "Add members to a set.")] public class SAddOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Value(1, MetaName = "members", Min = 1, Required = true, HelpText = "Members to add.")] public IEnumerable Members { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("srem", HelpText = "Remove members from a set.")] public class SRemOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Value(1, MetaName = "members", Min = 1, Required = true, HelpText = "Members to remove.")] public IEnumerable Members { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("smembers", HelpText = "Get all members of a set.")] public class SMembersOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("scard", HelpText = "Get the number of members in a set.")] public class SCardOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sismember", HelpText = "Check if a member exists in a set.")] public class SIsMemberOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Value(1, MetaName = "member", Required = true, HelpText = "Member to check.")] public string Member { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("srandmember", HelpText = "Get random member(s) from a set.")] public class SRandMemberOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "Set key.")] public string Key { get; set; } [Option("count", Required = false, HelpText = "Number of random members to get.")] public int? Count { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("spop", HelpText = "Remove and return random member(s) from a set.")] public class SPopOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "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("sinter", HelpText = "Get intersection of multiple sets.")] public class SInterOptions : InstanceOptions { [Value(0, MetaName = "keys", Min = 2, Required = true, HelpText = "Set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sunion", HelpText = "Get union of multiple sets.")] public class SUnionOptions : InstanceOptions { [Value(0, MetaName = "keys", Min = 2, Required = true, HelpText = "Set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sdiff", HelpText = "Get difference of multiple sets.")] public class SDiffOptions : InstanceOptions { [Value(0, MetaName = "keys", Min = 2, Required = true, HelpText = "Set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sinterstore", HelpText = "Store intersection of multiple sets.")] public class SInterStoreOptions : InstanceOptions { [Value(0, MetaName = "destination", Required = true, HelpText = "Destination set key.")] public string Destination { get; set; } [Value(1, MetaName = "keys", Min = 2, Required = true, HelpText = "Source set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sunionstore", HelpText = "Store union of multiple sets.")] public class SUnionStoreOptions : InstanceOptions { [Value(0, MetaName = "destination", Required = true, HelpText = "Destination set key.")] public string Destination { get; set; } [Value(1, MetaName = "keys", Min = 2, Required = true, HelpText = "Source set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sdiffstore", HelpText = "Store difference of multiple sets.")] public class SDiffStoreOptions : InstanceOptions { [Value(0, MetaName = "destination", Required = true, HelpText = "Destination set key.")] public string Destination { get; set; } [Value(1, MetaName = "keys", Min = 2, Required = true, HelpText = "Source set keys.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("sscan", HelpText = "Scan set members.")] public class SScanOptions : InstanceOptions { [Value(0, MetaName = "key", Required = true, HelpText = "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("smove", HelpText = "Move member from one set to another.")] public class SMoveOptions : InstanceOptions { [Value(0, MetaName = "source", Required = true, HelpText = "Source set key.")] public string Source { get; set; } [Value(1, MetaName = "destination", Required = true, HelpText = "Destination set key.")] public string Destination { get; set; } [Value(2, MetaName = "member", Required = true, HelpText = "Member to move.")] public string Member { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } public static class SetCommands { /// /// Executes the SADD command to add members to a set. /// /// The SAddOptions containing instance, key, and members. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSAdd(SAddOptions 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.SetAdd(opts.Key, members.Select(m => (RedisValue)m).ToArray()); if (opts.Table) { var rows = members.Select(m => new[] { m, "Added" }).ToList(); RedisUtils.PrintTable(new[] { "Member", "Status" }, rows); RedisUtils.PrintTable(new[] { "Key", "Added Count" }, new List { new[] { opts.Key, count.ToString() } }); } else Console.WriteLine(Output.Green($"Added {count} new member(s)")); return 0; } /// /// Executes the SREM command to remove members from a set. /// /// The SRemOptions containing instance, key, and members. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSRem(SRemOptions 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.SetRemove(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 { new[] { opts.Key, count.ToString() } }); } else Console.WriteLine(Output.Green($"Removed {count} member(s)")); return 0; } /// /// Executes the SMEMBERS command to get all members of a set. /// /// The SMembersOptions containing instance and key. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSMembers(SMembersOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var members = db.SetMembers(opts.Key); 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; } /// /// Executes the SCARD command to get the number of members in a set. /// /// The SCardOptions containing instance and key. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSCard(SCardOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var count = db.SetLength(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Cardinality" }, new List { new[] { opts.Key, count.ToString() } }); else Console.WriteLine(Output.Green(count.ToString())); return 0; } /// /// Executes the SISMEMBER command to check if a member exists in a set. /// /// The SIsMemberOptions containing instance, key, and member. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSIsMember(SIsMemberOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var exists = db.SetContains(opts.Key, opts.Member); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Member", "Exists" }, new List { new[] { opts.Key, opts.Member, exists.ToString() } }); else Console.WriteLine(Output.Green(exists.ToString())); return 0; } /// /// Executes the SRANDMEMBER command to get random member(s) from a set. /// /// The SRandMemberOptions containing instance, key, and count. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSRandMember(SRandMemberOptions 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 members = db.SetRandomMembers(opts.Key, opts.Count.Value); if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Random Member" }, rows); } else foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); } else { var member = db.SetRandomMember(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Random Member" }, new List { new[] { opts.Key, member.ToString() } }); else Console.WriteLine(Output.Green(member.ToString())); } return 0; } /// /// Executes the SPOP command to remove and return random member(s) from a set. /// /// The SPopOptions containing instance, key, and count. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSPop(SPopOptions 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 members = db.SetPop(opts.Key, opts.Count.Value); if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Popped Member" }, rows); } else foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); } else { var member = db.SetPop(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Popped Member" }, new List { new[] { opts.Key, member.ToString() } }); else Console.WriteLine(Output.Green(member.ToString())); } return 0; } /// /// Executes the SINTER command to get the intersection of multiple sets. /// /// The SInterOptions containing instance and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSInter(SInterOptions 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 members = db.SetCombine(SetOperation.Intersect, keys); if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Intersection Member" }, rows); } else foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); return 0; } /// /// Executes the SUNION command to get the union of multiple sets. /// /// The SUnionOptions containing instance and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSUnion(SUnionOptions 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 members = db.SetCombine(SetOperation.Union, keys); if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Union Member" }, rows); } else foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); return 0; } /// /// Executes the SDIFF command to get the difference of multiple sets. /// /// The SDiffOptions containing instance and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSDiff(SDiffOptions 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 members = db.SetCombine(SetOperation.Difference, keys); if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Difference Member" }, rows); } else foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); return 0; } /// /// Executes the SINTERSTORE command to store the intersection of multiple sets. /// /// The SInterStoreOptions containing instance, destination, and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSInterStore(SInterStoreOptions 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.SetCombineAndStore(SetOperation.Intersect, opts.Destination, keys); if (opts.Table) RedisUtils.PrintTable(new[] { "Destination", "Stored Count" }, new List { new[] { opts.Destination, count.ToString() } }); else Console.WriteLine(Output.Green($"Stored {count} member(s) in {opts.Destination}")); return 0; } /// /// Executes the SUNIONSTORE command to store the union of multiple sets. /// /// The SUnionStoreOptions containing instance, destination, and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSUnionStore(SUnionStoreOptions 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.SetCombineAndStore(SetOperation.Union, opts.Destination, keys); if (opts.Table) RedisUtils.PrintTable(new[] { "Destination", "Stored Count" }, new List { new[] { opts.Destination, count.ToString() } }); else Console.WriteLine(Output.Green($"Stored {count} member(s) in {opts.Destination}")); return 0; } /// /// Executes the SDIFFSTORE command to store the difference of multiple sets. /// /// The SDiffStoreOptions containing instance, destination, and keys. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSDiffStore(SDiffStoreOptions 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.SetCombineAndStore(SetOperation.Difference, opts.Destination, keys); if (opts.Table) RedisUtils.PrintTable(new[] { "Destination", "Stored Count" }, new List { new[] { opts.Destination, count.ToString() } }); else Console.WriteLine(Output.Green($"Stored {count} member(s) in {opts.Destination}")); return 0; } /// /// Executes the SSCAN command to scan set members. /// /// The SScanOptions containing instance, key, cursor, and scan options. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSScan(SScanOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var args = new List { opts.Cursor }; if (!string.IsNullOrEmpty(opts.Match)) { args.Add("MATCH"); args.Add(opts.Match); } if (opts.Count.HasValue) { args.Add("COUNT"); args.Add(opts.Count.Value); } var result = db.Execute("SSCAN", opts.Key, args.ToArray()); var arr = (RedisResult[])result; var newCursor = (int)arr[0]; var members = (RedisResult[])arr[1]; if (opts.Table) { var rows = members.Select(m => new[] { m.ToString() }).ToList(); RedisUtils.PrintTable(new[] { "Member" }, rows); RedisUtils.PrintTable(new[] { "Next Cursor" }, new List { new[] { newCursor.ToString() } }); } else { foreach (var member in members) Console.WriteLine(Output.Green(member.ToString())); Console.WriteLine(Output.Yellow($"Next cursor: {newCursor}")); } return 0; } /// /// Executes the SMOVE command to move a member from one set to another. /// /// The SMoveOptions containing instance, source, destination, and member. /// The RedisManager configuration. /// Exit code (0 for success, non-zero for failure). public static int RunSMove(SMoveOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var moved = db.SetMove(opts.Source, opts.Destination, opts.Member); if (opts.Table) RedisUtils.PrintTable(new[] { "Source", "Destination", "Member", "Moved" }, new List { new[] { opts.Source, opts.Destination, opts.Member, moved.ToString() } }); else Console.WriteLine(Output.Green(moved.ToString())); return 0; } } }