using StackExchange.Redis; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using WX.CRM.Model.Redis; namespace WX.CRM.DAL.Redis { public abstract class RedisHashBase : RedisStore { public RedisHashBase(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig) { } public RedisHashBase(RedisConfig redisConfig = RedisConfig.Redis0) : base(redisConfig) { } /// /// HEXISTS http://redis.io/commands/hexists /// /// /// public bool Exists(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); return Database.HashExists(Key, rKey); } /// /// HEXISTS http://redis.io/commands/hexists /// /// /// public async Task ExistsAsync(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); return await Database.HashExistsAsync(Key, rKey); } /// /// HKEYS http://redis.io/commands/hkeys /// /// public async Task> KeysAsync() { var result = await Database.HashKeysAsync(Key); return result.Select(x => Settings.ValueConverter.Deserialize(x)); } /// /// HLEN http://redis.io/commands/hlen /// public async Task LengthAsync() { return await Database.HashLengthAsync(Key); } /// /// HINCRBY http://redis.io/commands/hincrby /// public async Task IncrementAsync(TKey field, long value = 1) { var rKey = Settings.ValueConverter.Serialize(field); return await Database.HashIncrementAsync(Key, rKey, value); } /// /// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat /// public async Task IncrementAsync(TKey field, double value) { var rKey = Settings.ValueConverter.Serialize(field); return await Database.HashIncrementAsync(Key, rKey, value); } /// /// HDEL http://redis.io/commands/hdel /// public async Task DeleteAsync(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); return await Database.HashDeleteAsync(Key, rKey); } /// /// HDEL http://redis.io/commands/hdel /// public async Task DeleteAsync(TKey[] fields) { var hashFields = fields.Select(x => Settings.ValueConverter.Serialize(x)).ToArray(); return await Database.HashDeleteAsync(Key, hashFields); } } public sealed class RedisHash : RedisHashBase { public RedisHash(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig) { } public RedisHash(RedisConfig redisConfig = RedisConfig.Redis0) : base(redisConfig) { } /// /// HGET http://redis.io/commands/hget /// public TValue Get(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = Database.HashGet(Key, rKey); return Settings.ValueConverter.Deserialize(rValue); } /// /// HGET http://redis.io/commands/hget /// public async Task GetAsync(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = await Database.HashGetAsync(Key, rKey); return Settings.ValueConverter.Deserialize(rValue); } /// /// HMGET http://redis.io/commands/hmget /// public async Task> GetAsync(TKey[] fields) { var hashFields = fields.Select(x => Settings.ValueConverter.Serialize(x)).ToArray(); var rValues = await Database.HashGetAsync(Key, hashFields); return fields .Zip(rValues, (key, x) => { if (!x.HasValue) return new { key, rValue = default(TValue), x.HasValue }; var rValue = Settings.ValueConverter.Deserialize(x); return new { key, rValue, x.HasValue }; }) .Where(x => x.HasValue) .ToDictionary(x => x.key, x => x.rValue); } public Dictionary GetALL() { Dictionary list = new Dictionary(); var rValue = Database.HashGetAll(Key); foreach (var item in rValue) { //var t = Common.Utility.JSONToObject(item.Value); //list.Add(item.Name, t); var t = Settings.ValueConverter.Deserialize(item.Value); list.Add(item.Name, t); } return list; } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public bool Set(TKey field, TValue value) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = Settings.ValueConverter.Serialize(value); return Database.HashSet(Key, rKey, rValue); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public async Task SetAsync(RedisKey key, TKey field, TValue value) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = Settings.ValueConverter.Serialize(value); return await Database.HashSetAsync(key, rKey, rValue); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public async Task SetAsync(TKey field, TValue value) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = Settings.ValueConverter.Serialize(value); return await Database.HashSetAsync(Key, rKey, rValue); } /// /// HMSET http://redis.io/commands/hmset /// public async Task SetAsync(IEnumerable> values) { if (!(values is ICollection)) { values = values.ToArray(); // materialize } var hashFields = values.Select(x => { var rKey = Settings.ValueConverter.Serialize(x.Key); var rValue = Settings.ValueConverter.Serialize(x.Value); return new HashEntry(rKey, rValue); }).ToArray(); await Database.HashSetAsync(Key, hashFields); } public async Task SetByListAsync(RedisKey key, IList> values) { if (!(values is ICollection)) { values = values.ToArray(); // materialize } var hashFields = values.Select(x => { var rKey = Settings.ValueConverter.Serialize(x.Key); var rValue = Settings.ValueConverter.Serialize(x.Value); return new HashEntry(rKey, rValue); }).ToArray(); await Database.HashSetAsync(key, hashFields); } } public sealed class RedisDictionary : RedisHashBase { public RedisDictionary(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig) { } /// /// HGET http://redis.io/commands/hget /// public async Task GetAsync(TKey field) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = await Database.HashGetAsync(Key, rKey); return Settings.ValueConverter.Deserialize(rValue); } /// /// HMGET http://redis.io/commands/hmget /// public async Task> GetAsync(TKey[] fields) { var hashFields = fields.Select(x => Settings.ValueConverter.Serialize(x)).ToArray(); var rValues = await Database.HashGetAsync(Key, hashFields); return fields .Zip(rValues, (key, x) => { if (!x.HasValue) return new { key, rValue = default(TValue), x.HasValue }; var rValue = Settings.ValueConverter.Deserialize(x); return new { key, rValue, x.HasValue }; }) .Where(x => x.HasValue) .ToDictionary(x => x.key, x => x.rValue); } /// /// HGETALL http://redis.io/commands/hgetall /// public async Task> GetAllAsync() { var hashEntries = await Database.HashGetAllAsync(Key); return hashEntries.Select(x => { var vk = Settings.ValueConverter.Deserialize(x.Name); var v = Settings.ValueConverter.Deserialize(x.Value); return new { key = vk, value = v }; }).ToDictionary(x => x.key, x => x.value); } /// /// HVALS http://redis.io/commands/hvals /// public async Task> ValuesAsync() { var r = await Database.HashValuesAsync(Key); return r.Select(x => Settings.ValueConverter.Deserialize(x)); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public async Task Set(TKey field, TValue value) { var rKey = Settings.ValueConverter.Serialize(field); var rValue = Settings.ValueConverter.Serialize(value); return await Database.HashSetAsync(Key, rKey, rValue); } /// /// HMSET http://redis.io/commands/hmset /// public async Task Set(IEnumerable> values) { if (!(values is ICollection)) { values = values.ToArray(); // materialize } var hashFields = values.Select(x => { var rKey = Settings.ValueConverter.Serialize(x.Key); var rValue = Settings.ValueConverter.Serialize(x.Value); return new HashEntry(rKey, rValue); }).ToArray(); await Database.HashSetAsync(Key, hashFields); } } public class RedisClass : RedisStore where T : class, new() { public RedisClass(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig) { } /// /// All hash value map to class if key can't find returns null, includes HGETALL. /// public T Get() { var data = Database.HashGetAll(Key); if (data == null || data.Length == 0) { return null; } var accessor = TypeAccessor.Lookup(typeof(T)); var result = (T)accessor.CreateNew(); foreach (var item in data) { IMemberAccessor memberAccessor; if (accessor.TryGetValue(item.Name, out memberAccessor) && memberAccessor.IsReadable && memberAccessor.IsWritable) { var v = Settings.ValueConverter.Deserialize(memberAccessor.MemberType, item.Value); memberAccessor.SetValue(result, v); } else { var buf = (byte[])item.Value; } } return result; } /// /// All hash value map to class if key can't find returns null, includes HGETALL. /// public async Task GetAsync() { var data = await Database.HashGetAllAsync(Key); if (data == null || data.Length == 0) { return null; } var accessor = TypeAccessor.Lookup(typeof(T)); var result = (T)accessor.CreateNew(); foreach (var item in data) { IMemberAccessor memberAccessor; if (accessor.TryGetValue(item.Name, out memberAccessor) && memberAccessor.IsReadable && memberAccessor.IsWritable) { var v = Settings.ValueConverter.Deserialize(memberAccessor.MemberType, item.Value); memberAccessor.SetValue(result, v); } else { var buf = (byte[])item.Value; } } return result; } /// /// Class fields set to hash, includes HMSET. If return value is null value == null. /// public void Set(T value) { if (value == null) return; var accessor = TypeAccessor.Lookup(typeof(T)); var hashFields = accessor.Where(kvp => kvp.Value.IsReadable && kvp.Value.IsWritable) .Select(kvp => { var field = kvp.Value.GetValue(value); var rv = Settings.ValueConverter.Serialize(field); return new HashEntry(kvp.Key, rv); }) .ToArray(); Database.HashSet(Key, hashFields); } /// /// Class fields set to hash, includes HMSET. If return value is null value == null. /// public async Task SetAsync(T value) { if (value == null) return; var accessor = TypeAccessor.Lookup(typeof(T)); var hashFields = accessor.Where(kvp => kvp.Value.IsReadable && kvp.Value.IsWritable) .Select(kvp => { var field = kvp.Value.GetValue(value); var rv = Settings.ValueConverter.Serialize(field); return new HashEntry(kvp.Key, rv); }) .ToArray(); await Database.HashSetAsync(Key, hashFields); } /// /// GET(HGETALL), SET(HMSET) /// public async Task GetOrSet(Func valueFactory) { var value = await GetAsync(); if (value == null) { value = valueFactory(); await SetAsync(value); } return value; } /// /// GET(HGETALL), SET(HMSET) /// public async Task GetOrSet(Func> valueFactory) { var value = await GetAsync(); if (value == null) { value = await valueFactory(); await SetAsync(value); } return value; } /// /// HGET http://redis.io/commands/hget /// public async Task GetMember(Expression> memberSelector) { var memberExpr = memberSelector.Body as MemberExpression; if (memberExpr == null) throw new ArgumentException("can't analyze selector expression"); return await GetMember(memberExpr.Member.Name); } /// /// HGET http://redis.io/commands/hget /// public async Task GetMember(string memberName) { //if (!TypeAccessor.Lookup(typeof (T)).ContainsKey(memberName)) // return await Task.FromResult(TValue); var rValue = await Database.HashGetAsync(Key, memberName); return Settings.ValueConverter.Deserialize(rValue); } /// /// HMGET http://redis.io/commands/hmget /// public async Task> GetMembers(Expression> memberSelector, CommandFlags commandFlags = CommandFlags.None) { var newArrayExpr = memberSelector.Body as NewArrayExpression; if (newArrayExpr == null) throw new ArgumentException("can't analyze selector expression"); var fields = newArrayExpr.Expressions.OfType().Select(x => x.Member.Name).ToArray(); return await GetMembers(fields); } /// /// HMGET http://redis.io/commands/hmget /// public async Task> GetMembers(string[] memberNames) { var accesssor = TypeAccessor.Lookup(typeof(T)); memberNames = memberNames.Where(x => accesssor.ContainsKey(x)).ToArray(); if (memberNames.Length == 0) return await Task.FromResult(new Dictionary()); var hashFields = memberNames.Select(x => (RedisValue)x).ToArray(); var rValues = await Database.HashGetAsync(Key, hashFields); return memberNames .Zip(rValues, (key, x) => { if (!x.HasValue) return new { key, rValue = default(TValue), x.HasValue }; var rValue = Settings.ValueConverter.Deserialize(x); return new { key, rValue, x.HasValue }; }) .Where(x => x.HasValue) .ToDictionary(x => x.key, x => x.rValue); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public async Task SetMember(Expression> memberSelector, TValue value) { var memberExpr = memberSelector.Body as MemberExpression; if (memberExpr == null) throw new ArgumentException("can't analyze selector expression"); return await SetMember(memberExpr.Member.Name, value); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public async Task SetMember(string memberName, TValue value) { if (!TypeAccessor.Lookup(typeof(T)).ContainsKey(memberName)) return await Task.FromResult(false); RedisValue rKey = memberName; var rValue = Settings.ValueConverter.Serialize(value); return await Database.HashSetAsync(Key, rKey, rValue); } /// /// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx /// public bool SetMemberSync(string memberName, TValue value) { if (!TypeAccessor.Lookup(typeof(T)).ContainsKey(memberName)) return Task.FromResult(false).Result; RedisValue rKey = memberName; var rValue = Settings.ValueConverter.Serialize(value); return Database.HashSet(Key, rKey, rValue); } /// /// HMSET http://redis.io/commands/hmset /// public async Task SetMembers(Expression> memberSelector, TValue[] values) { var newArrayExpr = memberSelector.Body as NewArrayExpression; if (newArrayExpr == null) throw new ArgumentException("can't analyze selector expression"); var fields = newArrayExpr.Expressions.OfType().Select(x => x.Member.Name).ToArray(); if (fields.Length != values.Length) throw new ArgumentException("member and value's count is mismatch - memberSelector.Length:{fields.Length}, values.Length:{values.Length}"); var pairs = fields.Zip(values, (key, value) => new KeyValuePair(key, value)).ToArray(); await SetMembers(pairs); } /// /// HMSET http://redis.io/commands/hmset /// public async Task SetMembers(IEnumerable> values) { if (!(values is ICollection)) { values = values.ToArray(); // materialize } var hashFields = values.Select(x => { RedisValue rKey = x.Key; var rValue = Settings.ValueConverter.Serialize(x.Value); return new HashEntry(rKey, rValue); }).ToArray(); await Database.HashSetAsync(Key, hashFields); } /// /// HINCRBY http://redis.io/commands/hincrby /// public Task Increment(Expression> memberSelector, long value = 1) { return Increment(GetMemberName(memberSelector), value); } /// /// HINCRBY http://redis.io/commands/hincrby /// public async Task Increment(string member, long value = 1) { var rKey = member; return await Database.HashIncrementAsync(Key, rKey, value); } /// /// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat /// public Task Increment(Expression> memberSelector, double value) { return Increment(GetMemberName(memberSelector), value); } /// /// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat /// public async Task Increment(string member, double value) { var rKey = member; return await Database.HashIncrementAsync(Key, rKey, value); } string GetMemberName(LambdaExpression memberSelector) { var unary = memberSelector.Body as UnaryExpression; var memberExpr = (unary != null) ? unary.Operand as MemberExpression : memberSelector.Body as MemberExpression; if (memberExpr == null) throw new ArgumentException("can't analyze selector expression"); return memberExpr.Member.Name; } } }