629 lines
23 KiB
C#
629 lines
23 KiB
C#
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<TKey> : RedisStore
|
|
{
|
|
public RedisHashBase(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig)
|
|
{
|
|
}
|
|
public RedisHashBase(RedisConfig redisConfig = RedisConfig.Redis0)
|
|
: base(redisConfig)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// HEXISTS http://redis.io/commands/hexists
|
|
/// </summary>
|
|
/// <param name="field"></param>
|
|
/// <returns></returns>
|
|
public bool Exists(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
return Database.HashExists(Key, rKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HEXISTS http://redis.io/commands/hexists
|
|
/// </summary>
|
|
/// <param name="field"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ExistsAsync(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
return await Database.HashExistsAsync(Key, rKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HKEYS http://redis.io/commands/hkeys
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<IEnumerable<TKey>> KeysAsync()
|
|
{
|
|
var result = await Database.HashKeysAsync(Key);
|
|
return result.Select(x => Settings.ValueConverter.Deserialize<TKey>(x));
|
|
}
|
|
|
|
/// <summary>
|
|
/// HLEN http://redis.io/commands/hlen
|
|
/// </summary>
|
|
public async Task<long> LengthAsync()
|
|
{
|
|
return await Database.HashLengthAsync(Key);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HINCRBY http://redis.io/commands/hincrby
|
|
/// </summary>
|
|
public async Task<long> IncrementAsync(TKey field, long value = 1)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
return await Database.HashIncrementAsync(Key, rKey, value);
|
|
}
|
|
/// <summary>
|
|
/// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat
|
|
/// </summary>
|
|
public async Task<double> IncrementAsync(TKey field, double value)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
return await Database.HashIncrementAsync(Key, rKey, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HDEL http://redis.io/commands/hdel
|
|
/// </summary>
|
|
public async Task<bool> DeleteAsync(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
return await Database.HashDeleteAsync(Key, rKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HDEL http://redis.io/commands/hdel
|
|
/// </summary>
|
|
public async Task<long> DeleteAsync(TKey[] fields)
|
|
{
|
|
var hashFields = fields.Select(x => Settings.ValueConverter.Serialize(x)).ToArray();
|
|
return await Database.HashDeleteAsync(Key, hashFields);
|
|
}
|
|
}
|
|
public sealed class RedisHash<TKey> : RedisHashBase<TKey>
|
|
{
|
|
public RedisHash(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig)
|
|
{
|
|
}
|
|
public RedisHash(RedisConfig redisConfig = RedisConfig.Redis0)
|
|
: base(redisConfig)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGET http://redis.io/commands/hget
|
|
/// </summary>
|
|
public TValue Get<TValue>(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = Database.HashGet(Key, rKey);
|
|
return Settings.ValueConverter.Deserialize<TValue>(rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGET http://redis.io/commands/hget
|
|
/// </summary>
|
|
public async Task<TValue> GetAsync<TValue>(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = await Database.HashGetAsync(Key, rKey);
|
|
return Settings.ValueConverter.Deserialize<TValue>(rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMGET http://redis.io/commands/hmget
|
|
/// </summary>
|
|
public async Task<Dictionary<TKey, TValue>> GetAsync<TValue>(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<TValue>(x);
|
|
return new { key, rValue, x.HasValue };
|
|
})
|
|
.Where(x => x.HasValue)
|
|
.ToDictionary(x => x.key, x => x.rValue);
|
|
|
|
}
|
|
|
|
public Dictionary<string, TValue> GetALL<TValue>()
|
|
{
|
|
Dictionary<string, TValue> list = new Dictionary<string, TValue>();
|
|
var rValue = Database.HashGetAll(Key);
|
|
|
|
foreach (var item in rValue)
|
|
{
|
|
//var t = Common.Utility.JSONToObject<TValue>(item.Value);
|
|
//list.Add(item.Name, t);
|
|
var t = Settings.ValueConverter.Deserialize<TValue>(item.Value);
|
|
list.Add(item.Name, t);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public bool Set<TValue>(TKey field, TValue value)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = Settings.ValueConverter.Serialize(value);
|
|
return Database.HashSet(Key, rKey, rValue);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public async Task<bool> SetAsync<TValue>(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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public async Task<bool> SetAsync<TValue>(TKey field, TValue value)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = Settings.ValueConverter.Serialize(value);
|
|
return await Database.HashSetAsync(Key, rKey, rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMSET http://redis.io/commands/hmset
|
|
/// </summary>
|
|
public async Task SetAsync<TValue>(IEnumerable<KeyValuePair<TKey, TValue>> 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<TValue>(RedisKey key, IList<KeyValuePair<TKey, TValue>> 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<TKey, TValue> : RedisHashBase<TKey>
|
|
{
|
|
public RedisDictionary(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGET http://redis.io/commands/hget
|
|
/// </summary>
|
|
public async Task<TValue> GetAsync(TKey field)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = await Database.HashGetAsync(Key, rKey);
|
|
return Settings.ValueConverter.Deserialize<TValue>(rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMGET http://redis.io/commands/hmget
|
|
/// </summary>
|
|
public async Task<Dictionary<TKey, TValue>> 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<TValue>(x);
|
|
return new { key, rValue, x.HasValue };
|
|
})
|
|
.Where(x => x.HasValue)
|
|
.ToDictionary(x => x.key, x => x.rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGETALL http://redis.io/commands/hgetall
|
|
/// </summary>
|
|
public async Task<Dictionary<TKey, TValue>> GetAllAsync()
|
|
{
|
|
var hashEntries = await Database.HashGetAllAsync(Key);
|
|
return hashEntries.Select(x =>
|
|
{
|
|
var vk = Settings.ValueConverter.Deserialize<TKey>(x.Name);
|
|
var v = Settings.ValueConverter.Deserialize<TValue>(x.Value);
|
|
return new { key = vk, value = v };
|
|
}).ToDictionary(x => x.key, x => x.value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HVALS http://redis.io/commands/hvals
|
|
/// </summary>
|
|
public async Task<IEnumerable<TValue>> ValuesAsync()
|
|
{
|
|
var r = await Database.HashValuesAsync(Key);
|
|
return r.Select(x => Settings.ValueConverter.Deserialize<TValue>(x));
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public async Task<bool> Set(TKey field, TValue value)
|
|
{
|
|
var rKey = Settings.ValueConverter.Serialize(field);
|
|
var rValue = Settings.ValueConverter.Serialize(value);
|
|
return await Database.HashSetAsync(Key, rKey, rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMSET http://redis.io/commands/hmset
|
|
/// </summary>
|
|
public async Task Set(IEnumerable<KeyValuePair<TKey, TValue>> 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<T> : RedisStore where T : class, new()
|
|
{
|
|
public RedisClass(RedisKey key, RedisConfig redisConfig = RedisConfig.Redis0) : base(key, redisConfig)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// All hash value map to class if key can't find returns null, includes HGETALL.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// All hash value map to class if key can't find returns null, includes HGETALL.
|
|
/// </summary>
|
|
public async Task<T> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class fields set to hash, includes HMSET. If return value is null value == null.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class fields set to hash, includes HMSET. If return value is null value == null.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// GET(HGETALL), SET(HMSET)
|
|
/// </summary>
|
|
public async Task<T> GetOrSet(Func<T> valueFactory)
|
|
{
|
|
var value = await GetAsync();
|
|
if (value == null)
|
|
{
|
|
value = valueFactory();
|
|
await SetAsync(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// GET(HGETALL), SET(HMSET)
|
|
/// </summary>
|
|
public async Task<T> GetOrSet(Func<Task<T>> valueFactory)
|
|
{
|
|
var value = await GetAsync();
|
|
if (value == null)
|
|
{
|
|
value = await valueFactory();
|
|
await SetAsync(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGET http://redis.io/commands/hget
|
|
/// </summary>
|
|
public async Task<TValue> GetMember<TValue>(Expression<Func<T, TValue>> memberSelector)
|
|
{
|
|
var memberExpr = memberSelector.Body as MemberExpression;
|
|
if (memberExpr == null) throw new ArgumentException("can't analyze selector expression");
|
|
|
|
return await GetMember<TValue>(memberExpr.Member.Name);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HGET http://redis.io/commands/hget
|
|
/// </summary>
|
|
public async Task<TValue> GetMember<TValue>(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<TValue>(rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMGET http://redis.io/commands/hmget
|
|
/// </summary>
|
|
public async Task<Dictionary<string, TValue>> GetMembers<TValue>(Expression<Func<T, TValue[]>> 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<MemberExpression>().Select(x => x.Member.Name).ToArray();
|
|
|
|
return await GetMembers<TValue>(fields);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMGET http://redis.io/commands/hmget
|
|
/// </summary>
|
|
public async Task<Dictionary<string, TValue>> GetMembers<TValue>(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<string, TValue>());
|
|
|
|
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<TValue>(x);
|
|
return new { key, rValue, x.HasValue };
|
|
})
|
|
.Where(x => x.HasValue)
|
|
.ToDictionary(x => x.key, x => x.rValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public async Task<bool> SetMember<TValue>(Expression<Func<T, TValue>> memberSelector, TValue value)
|
|
{
|
|
var memberExpr = memberSelector.Body as MemberExpression;
|
|
if (memberExpr == null) throw new ArgumentException("can't analyze selector expression");
|
|
|
|
return await SetMember<TValue>(memberExpr.Member.Name, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public async Task<bool> SetMember<TValue>(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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HSET, HSETNX http://redis.io/commands/hset http://redis.io/commands/hsetnx
|
|
/// </summary>
|
|
public bool SetMemberSync<TValue>(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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMSET http://redis.io/commands/hmset
|
|
/// </summary>
|
|
public async Task SetMembers<TValue>(Expression<Func<T, TValue[]>> 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<MemberExpression>().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<string, TValue>(key, value)).ToArray();
|
|
await SetMembers<TValue>(pairs);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HMSET http://redis.io/commands/hmset
|
|
/// </summary>
|
|
public async Task SetMembers<TValue>(IEnumerable<KeyValuePair<string, TValue>> 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HINCRBY http://redis.io/commands/hincrby
|
|
/// </summary>
|
|
public Task<long> Increment(Expression<Func<T, long>> memberSelector, long value = 1)
|
|
{
|
|
return Increment(GetMemberName(memberSelector), value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HINCRBY http://redis.io/commands/hincrby
|
|
/// </summary>
|
|
public async Task<long> Increment(string member, long value = 1)
|
|
{
|
|
var rKey = member;
|
|
return await Database.HashIncrementAsync(Key, rKey, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat
|
|
/// </summary>
|
|
public Task<double> Increment(Expression<Func<T, double>> memberSelector, double value)
|
|
{
|
|
return Increment(GetMemberName(memberSelector), value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HINCRBYFLOAT http://redis.io/commands/hincrbyfloat
|
|
/// </summary>
|
|
public async Task<double> 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;
|
|
}
|
|
|
|
}
|
|
}
|