using CommandLine; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using RedisManager.Utils; namespace RedisManager.Commands { [Verb("exists", HelpText = "Check if key(s) exist.")] public class ExistsOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "keys", Min = 1, Required = true, HelpText = "Keys to check.")] public IEnumerable Keys { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("expire", HelpText = "Set a timeout on a key.")] public class ExpireOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "key", Required = true, HelpText = "Key to expire.")] public string Key { get; set; } [Value(1, MetaName = "seconds", Required = true, HelpText = "Expire time in seconds.")] public int Seconds { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("ttl", HelpText = "Get the time to live for a key.")] public class TtlOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "key", Required = true, HelpText = "Key to check.")] public string Key { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("persist", HelpText = "Remove the expiration from a key.")] public class PersistOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "key", Required = true, HelpText = "Key to persist.")] public string Key { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("rename", HelpText = "Rename a key.")] public class RenameOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "key", Required = true, HelpText = "Current key name.")] public string Key { get; set; } [Value(1, MetaName = "newkey", Required = true, HelpText = "New key name.")] public string NewKey { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("type", HelpText = "Get the type of a key.")] public class TypeOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "key", Required = true, HelpText = "Key to check.")] public string Key { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("keys", HelpText = "Find all keys matching pattern.")] public class KeysOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Value(0, MetaName = "pattern", Required = true, HelpText = "Pattern to match.")] public string Pattern { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } [Verb("scan", HelpText = "Incrementally iterate the keyspace.")] public class ScanOptions { [Option('i', "instance", Required = true, HelpText = "Instance name.")] public string Instance { get; set; } [Option("cursor", Required = false, HelpText = "Cursor to start from.")] public ulong Cursor { get; set; } = 0; [Option("pattern", Required = false, HelpText = "Pattern to match.")] public string Pattern { get; set; } [Option("count", Required = false, HelpText = "Count of keys to return.")] public int? Count { get; set; } [Option("table", Required = false, HelpText = "Output as table.")] public bool Table { get; set; } } public static class KeyCommands { public static int RunExists(ExistsOptions 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.KeyExists(keys); if (opts.Table) RedisUtils.PrintTable(new[] { "Keys", "Exist Count" }, new List { new[] { string.Join(", ", opts.Keys), count.ToString() } }); else Console.WriteLine(Output.Green(count.ToString())); return 0; } public static int RunExpire(ExpireOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var ok = db.KeyExpire(opts.Key, TimeSpan.FromSeconds(opts.Seconds)); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Expire Set" }, new List { new[] { opts.Key, ok ? "Yes" : "No" } }); else Console.WriteLine(Output.Green(ok ? "1" : "0")); return 0; } public static int RunTtl(TtlOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var ttl = db.KeyTimeToLive(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "TTL (s)" }, new List { new[] { opts.Key, ttl?.TotalSeconds.ToString() ?? "-1" } }); else Console.WriteLine(Output.Green(ttl?.TotalSeconds.ToString() ?? "-1")); return 0; } public static int RunPersist(PersistOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var ok = db.KeyPersist(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Persisted" }, new List { new[] { opts.Key, ok ? "Yes" : "No" } }); else Console.WriteLine(Output.Green(ok ? "1" : "0")); return 0; } public static int RunRename(RenameOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); db.KeyRename(opts.Key, opts.NewKey); if (opts.Table) RedisUtils.PrintTable(new[] { "Old Key", "New Key", "Status" }, new List { new[] { opts.Key, opts.NewKey, "Renamed" } }); else Console.WriteLine(Output.Green("OK")); return 0; } public static int RunType(TypeOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var type = db.KeyType(opts.Key); if (opts.Table) RedisUtils.PrintTable(new[] { "Key", "Type" }, new List { new[] { opts.Key, type.ToString() } }); else Console.WriteLine(Output.Green(type.ToString())); return 0; } public static int RunKeys(KeysOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var keys = db.Execute("KEYS", opts.Pattern).ToString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (opts.Table) { var rows = keys.Select(k => new[] { k }).ToList(); RedisUtils.PrintTable(new[] { "Key" }, rows); } else { foreach (var key in keys) Console.WriteLine(Output.Green(key)); } return 0; } public static int RunScan(ScanOptions opts, Config config) { var instance = RedisUtils.GetInstance(config, opts.Instance); using var redis = RedisUtils.ConnectRedis(instance); var db = redis.GetDatabase(); var result = db.Execute("SCAN", opts.Cursor.ToString(), string.IsNullOrEmpty(opts.Pattern) ? null : "MATCH", string.IsNullOrEmpty(opts.Pattern) ? null : opts.Pattern, opts.Count.HasValue ? "COUNT" : null, opts.Count.HasValue ? opts.Count.Value.ToString() : null); var arr = (RedisResult[])result; var nextCursor = arr[0].ToString(); var keys = ((RedisResult[])arr[1]).Select(x => x.ToString()).ToArray(); if (opts.Table) { var rows = keys.Select(k => new[] { k }).ToList(); RedisUtils.PrintTable(new[] { "Key" }, rows); RedisUtils.PrintTable(new[] { "Next Cursor" }, new List { new[] { nextCursor } }); } else { foreach (var key in keys) Console.WriteLine(Output.Green(key)); Console.WriteLine(Output.Yellow($"Next Cursor: {nextCursor}")); } return 0; } } }