From 4e3fa3ae4c671443395589cc512c0c0656bb75fd Mon Sep 17 00:00:00 2001 From: atakavci Date: Tue, 7 May 2024 15:50:15 +0300 Subject: [PATCH 01/13] support for hash field expiration HEXPIRE, HPEXPIRE, HPEXPIREAT, HPEXPIREAT hashfieldtest refactor code format + unit tests refactored --- src/StackExchange.Redis/Enums/ExpireResult.cs | 27 +++ src/StackExchange.Redis/Enums/RedisCommand.cs | 8 + .../Interfaces/IDatabase.cs | 69 +++++++ .../Interfaces/IDatabaseAsync.cs | 68 +++++++ .../KeyspaceIsolation/KeyPrefixed.cs | 12 ++ .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 12 ++ .../PublicAPI/PublicAPI.Shipped.txt | 13 ++ src/StackExchange.Redis/RedisDatabase.cs | 84 +++++++++ src/StackExchange.Redis/ResultProcessor.cs | 50 +++++ .../HashFieldTests.cs | 178 ++++++++++++++++++ 10 files changed, 521 insertions(+) create mode 100644 src/StackExchange.Redis/Enums/ExpireResult.cs create mode 100644 tests/StackExchange.Redis.Tests/HashFieldTests.cs diff --git a/src/StackExchange.Redis/Enums/ExpireResult.cs b/src/StackExchange.Redis/Enums/ExpireResult.cs new file mode 100644 index 000000000..90b660104 --- /dev/null +++ b/src/StackExchange.Redis/Enums/ExpireResult.cs @@ -0,0 +1,27 @@ +using System; + +namespace StackExchange.Redis; + +/// +/// Specifies when to set the expiry for a key. +/// +public enum ExpireResult +{ + /// + /// Set expiry whether or not there is an existing expiry. + /// + Due = 2, + /// + /// Set expiry only when the new expiry is greater than current one. + /// + Success = 1, + /// + /// Set expiry only when the key has an existing expiry. + /// + ConditionNotMet = 0, + /// + /// Set expiry only when the key has no expiry. + /// + NoSuchField = -2, + +} diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs index 728b88a76..a910c7e49 100644 --- a/src/StackExchange.Redis/Enums/RedisCommand.cs +++ b/src/StackExchange.Redis/Enums/RedisCommand.cs @@ -66,6 +66,8 @@ internal enum RedisCommand HDEL, HELLO, HEXISTS, + HEXPIRE, + HEXPIREAT, HGET, HGETALL, HINCRBY, @@ -74,6 +76,8 @@ internal enum RedisCommand HLEN, HMGET, HMSET, + HPEXPIRE, + HPEXPIREAT, HRANDFIELD, HSCAN, HSET, @@ -279,9 +283,13 @@ internal static bool IsPrimaryOnly(this RedisCommand command) case RedisCommand.GETEX: case RedisCommand.GETSET: case RedisCommand.HDEL: + case RedisCommand.HEXPIRE: + case RedisCommand.HEXPIREAT: case RedisCommand.HINCRBY: case RedisCommand.HINCRBYFLOAT: case RedisCommand.HMSET: + case RedisCommand.HPEXPIRE: + case RedisCommand.HPEXPIREAT: case RedisCommand.HSET: case RedisCommand.HSETNX: case RedisCommand.INCR: diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index 7cf2248fd..f5db64022 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -325,6 +325,75 @@ public interface IDatabase : IRedis, IDatabaseAsync /// bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// Set the remaining time to live in milliseconds for a field of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The field in the hash to set expire time. + /// The timeout to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the remaining time to live in milliseconds for the given set of fields of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The fields in the hash to set expire time. + /// The timeout to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the time out on a field of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The field in the hash to set expire time. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the time out on a field of the given set of fields of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The fields in the hash to set expire time. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + /// /// Returns the value associated with field in the hash stored at key. /// diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index a19525925..e49fba6f9 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -312,6 +312,74 @@ public interface IDatabaseAsync : IRedisAsync /// Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + /// + /// Set the remaining time to live in milliseconds for a field of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The field in the hash to set expire time. + /// The timeout to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the remaining time to live in milliseconds for the given set of fields of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The fields in the hash to set expire time. + /// The timeout to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the time out on a field of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The field in the hash to set expire time. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// Set the time out on a field of the given set of fields of hash + /// After the timeout has expired, the field of the hash will automatically be deleted. + /// + /// The key of the hash. + /// The fields in the hash to set expire time. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// 2: field deleted because the specified expiration time is due + /// 1: expiration time set/updated + /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) + /// -2 : no such field + /// + Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + /// /// Returns the value associated with field in the hash stored at key. /// diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index e34cad895..ec13180ac 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -84,6 +84,18 @@ public Task HashDeleteAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashExistsAsync(ToInner(key), hashField, flags); + public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpireAsync(ToInner(key), hashField, expiry, when, flags); + + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); + + public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpireAsync(ToInner(key), hashField, expiry, when, flags); + + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); + public Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAllAsync(ToInner(key), flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index d1c47aeab..05a4c6463 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -81,6 +81,18 @@ public bool HashDelete(RedisKey key, RedisValue hashField, CommandFlags flags = public bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashExists(ToInner(key), hashField, flags); + public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpire(ToInner(key), hashField, expiry, when, flags); + + public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); + + public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpire(ToInner(key), hashField, expiry, when, flags); + + public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); + public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAll(ToInner(key), flags); diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index 1bcc6c66d..51bbb22df 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -393,6 +393,11 @@ StackExchange.Redis.Exclude.Both = StackExchange.Redis.Exclude.Start | StackExch StackExchange.Redis.Exclude.None = 0 -> StackExchange.Redis.Exclude StackExchange.Redis.Exclude.Start = 1 -> StackExchange.Redis.Exclude StackExchange.Redis.Exclude.Stop = 2 -> StackExchange.Redis.Exclude +StackExchange.Redis.ExpireResult +StackExchange.Redis.ExpireResult.ConditionNotMet = 0 -> StackExchange.Redis.ExpireResult +StackExchange.Redis.ExpireResult.Due = 2 -> StackExchange.Redis.ExpireResult +StackExchange.Redis.ExpireResult.NoSuchField = -2 -> StackExchange.Redis.ExpireResult +StackExchange.Redis.ExpireResult.Success = 1 -> StackExchange.Redis.ExpireResult StackExchange.Redis.ExpireWhen StackExchange.Redis.ExpireWhen.Always = 0 -> StackExchange.Redis.ExpireWhen StackExchange.Redis.ExpireWhen.GreaterThanCurrentExpiry = 1 -> StackExchange.Redis.ExpireWhen @@ -539,6 +544,10 @@ StackExchange.Redis.IDatabase.HashDecrement(StackExchange.Redis.RedisKey key, St StackExchange.Redis.IDatabase.HashDelete(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool StackExchange.Redis.IDatabase.HashDelete(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.HashExists(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HashGetAll(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.HashEntry[]! @@ -770,6 +779,10 @@ StackExchange.Redis.IDatabaseAsync.HashDecrementAsync(StackExchange.Redis.RedisK StackExchange.Redis.IDatabaseAsync.HashDeleteAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashDeleteAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashExistsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 6a0210e6b..29114798b 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -387,6 +387,90 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla return ExecuteAsync(msg, ResultProcessor.Boolean); } + public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncExpireResultExecutor, flags, hashField); + } + + public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncExpireResultArrayExecutor, flags, hashFields); + } + + public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = GetMillisecondsUntil(expiry); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncExpireResultExecutor, flags, hashField); + } + + public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = GetMillisecondsUntil(expiry); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncExpireResultArrayExecutor, flags, hashFields); + } + + public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncExpireResultExecutor, flags, hashField); + } + + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncExpireResultArrayExecutor, flags, hashFields); + } + + public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = GetMillisecondsUntil(expiry); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncExpireResultExecutor, flags, hashField); + } + + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + long milliseconds = GetMillisecondsUntil(expiry); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncExpireResultArrayExecutor, flags, hashFields); + } + + #region private for HFE + private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen when, Func getCmd, Executor executor, CommandFlags flags, params RedisValue[] hashFields) + { + if (hashFields == null) throw new ArgumentNullException(nameof(hashFields)); + var useSeconds = milliseconds % 1000 == 0; + var cmd = getCmd(useSeconds); + long expiry = useSeconds ? (milliseconds / 1000) : milliseconds; + + var values = when switch + { + ExpireWhen.Always => new List { expiry, hashFields.Length }, + _ => new List { expiry, when.ToLiteral(), hashFields.Length }, + }; + values.AddRange(hashFields); + RedisFeatures features = GetFeatures(key, flags, cmd, out ServerEndPoint? server); + var msg = Message.Create(Database, flags, cmd, key, values.ToArray()); + return executor(msg, server); + } + + private RedisCommand PickExpireCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIRE : RedisCommand.HPEXPIRE; + + private RedisCommand PickExpireAtCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIREAT : RedisCommand.HPEXPIREAT; + + private delegate T Executor(Message msg, ServerEndPoint? server); + + private ExpireResult? SyncExpireResultExecutor(Message msg, ServerEndPoint? server) => ExecuteSync(msg, ResultProcessor.ExpireResult, server); + + private ExpireResult[]? SyncExpireResultArrayExecutor(Message msg, ServerEndPoint? server) => ExecuteSync(msg, ResultProcessor.ExpireResultArray, server); + + private Task AsyncExpireResultExecutor(Message msg, ServerEndPoint? server) => ExecuteAsync(msg, ResultProcessor.ExpireResult, server); + + private Task AsyncExpireResultArrayExecutor(Message msg, ServerEndPoint? server) => ExecuteAsync(msg, ResultProcessor.ExpireResultArray, server); + + #endregion helper stuff for HFE + + public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { var msg = Message.Create(Database, flags, RedisCommand.HGET, key, hashField); diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index 95dc4bd87..0a84bdcb8 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -68,6 +68,10 @@ public static readonly ResultProcessor public static readonly ResultProcessor NullableInt64 = new NullableInt64Processor(); + public static readonly ResultProcessor ExpireResult = new ExpireResultProcessor(); + + public static readonly ResultProcessor ExpireResultArray = new ExpireResultArrayProcessor(); + public static readonly ResultProcessor RedisChannelArrayLiteral = new RedisChannelArrayProcessor(RedisChannel.PatternMode.Literal); @@ -1445,6 +1449,52 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } + private sealed class ExpireResultProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + switch (result.Resp2TypeBulkString) + { + case ResultType.BulkString: + if (result.IsNull) + { + SetResult(message, null); + return true; + } + break; + case ResultType.Array: + var items = result.GetItems(); + if (items.Length == 1) + { // treat an array of 1 like a single reply (for example, SCRIPT EXISTS) + if (items[0].TryGetInt64(out long value)) + { + SetResult(message, (ExpireResult)value); + return true; + } + } + break; + } + return false; + + } + } + + + private sealed class ExpireResultArrayProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + if (result.Resp2TypeArray == ResultType.Array || result.IsNull) + { + var arr = result.ToArray((in RawResult x) => (ExpireResult)(long)x.AsRedisValue())!; + + SetResult(message, arr); + return true; + } + return false; + } + } + private sealed class RedisChannelArrayProcessor : ResultProcessor { private readonly RedisChannel.PatternMode mode; diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs new file mode 100644 index 000000000..8869c3bb7 --- /dev/null +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using Xunit; +using Xunit.Abstractions; +using System.Threading.Tasks; +using System.Globalization; + +namespace StackExchange.Redis.Tests; + +/// +/// Tests for . +/// +[RunPerProtocol] +[Collection(SharedConnectionFixture.Key)] +public class HashFieldTests : TestBase +{ + private readonly DateTime nextCentury = new DateTime(2101, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private readonly TimeSpan oneYearInMs = TimeSpan.FromMilliseconds(31536000000); + + private readonly HashEntry[] entries = new HashEntry[] { new("f1", 1), new("f2", 2) }; + + private readonly RedisValue[] fields = new RedisValue[] { "f1", "f2" }; + + + public HashFieldTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) + { + } + + [Fact] + public void HashFieldExpire() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs); + Assert.Equal(ExpireResult.Success, result); + + result = db.HashFieldExpire(hashKey, "f1", nextCentury); + Assert.Equal(ExpireResult.Success, result); + + var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + + fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, }, fieldsResult); + } + + [Fact] + public void HashFieldExpireNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs); + Assert.Null(result); + + result = db.HashFieldExpire(hashKey, "f1", nextCentury); + Assert.Null(result); + + var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); + Assert.Null(fieldsResult); + + fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); + Assert.Null(fieldsResult); + } + + [Fact] + public async void HashFieldExpireAsync() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = await db.HashFieldExpireAsync(hashKey, "f1", oneYearInMs); + Assert.Equal(ExpireResult.Success, result); + + result = await db.HashFieldExpireAsync(hashKey, "f1", nextCentury); + Assert.Equal(ExpireResult.Success, result); + + var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + + fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + } + + [Fact] + public async void HashFieldExpireAsyncNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var result = await db.HashFieldExpireAsync(hashKey, "f1", oneYearInMs); + Assert.Null(result); + + result = await db.HashFieldExpireAsync(hashKey, "f1", nextCentury); + Assert.Null(result); + + var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); + Assert.Null(fieldsResult); + + fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); + Assert.Null(fieldsResult); + } + + [Fact] + public void HashFieldExpireTimeIsDue() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldExpire(hashKey, "f1", new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal(ExpireResult.Due, result); + } + + [Fact] + public void HashFieldExpireNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldExpire(hashKey, "nonExistingField", oneYearInMs); + Assert.Equal(ExpireResult.NoSuchField, result); + } + + [Fact] + public void HashFieldExpireConditionsSatisfied() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.KeyDelete(hashKey); + db.HashSet(hashKey, entries); + db.HashSet(hashKey, new HashEntry[] { new("f3", 3), new("f4", 4) }); + var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); + + var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(ExpireResult.Success, result); + + result = db.HashFieldExpire(hashKey, "f2", oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal(ExpireResult.Success, result); + + result = db.HashFieldExpire(hashKey, "f3", nextCentury, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal(ExpireResult.Success, result); + + result = db.HashFieldExpire(hashKey, "f4", oneYearInMs, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal(ExpireResult.Success, result); + } + + [Fact] + public void HashFieldExpireConditionsNotSatisfied() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.KeyDelete(hashKey); + db.HashSet(hashKey, entries); + db.HashSet(hashKey, new HashEntry[] { new("f3", 3), new("f4", 4) }); + var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); + + var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal(ExpireResult.ConditionNotMet, result); + + result = db.HashFieldExpire(hashKey, "f2", oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(ExpireResult.ConditionNotMet, result); + + result = db.HashFieldExpire(hashKey, "f3", nextCentury, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal(ExpireResult.ConditionNotMet, result); + + result = db.HashFieldExpire(hashKey, "f4", oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal(ExpireResult.ConditionNotMet, result); + } +} From 9b0baec0f6ed855fc54d68fb38b028266951729d Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 17 May 2024 16:25:10 +0300 Subject: [PATCH 02/13] add FIELDS --- src/StackExchange.Redis/RedisDatabase.cs | 101 +++++++++++++---------- src/StackExchange.Redis/RedisLiterals.cs | 1 + 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 29114798b..29135fb2a 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -445,8 +445,8 @@ private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen var values = when switch { - ExpireWhen.Always => new List { expiry, hashFields.Length }, - _ => new List { expiry, when.ToLiteral(), hashFields.Length }, + ExpireWhen.Always => new List { expiry, RedisLiterals.FIELDS, hashFields.Length }, + _ => new List { expiry, when.ToLiteral(), RedisLiterals.FIELDS, hashFields.Length }, }; values.AddRange(hashFields); RedisFeatures features = GetFeatures(key, flags, cmd, out ServerEndPoint? server); @@ -1860,7 +1860,7 @@ public RedisValue[] SetPop(RedisKey key, long count, CommandFlags flags = Comman public Task SetPopAsync(RedisKey key, long count, CommandFlags flags = CommandFlags.None) { - if(count == 0) return CompletedTask.FromDefault(Array.Empty(), asyncState); + if (count == 0) return CompletedTask.FromDefault(Array.Empty(), asyncState); var msg = count == 1 ? Message.Create(Database, flags, RedisCommand.SPOP, key) : Message.Create(Database, flags, RedisCommand.SPOP, key, count); @@ -1966,7 +1966,7 @@ public bool SortedSetAdd(RedisKey key, RedisValue member, double score, CommandF SortedSetAdd(key, member, score, SortedSetWhen.Always, flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when = When.Always, CommandFlags flags = CommandFlags.None) => - SortedSetAdd(key, member, score, SortedSetWhenExtensions.Parse(when), flags); + SortedSetAdd(key, member, score, SortedSetWhenExtensions.Parse(when), flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) { @@ -3358,9 +3358,9 @@ private Message GetCopyMessage(in RedisKey sourceKey, RedisKey destinationKey, i { < -1 => throw new ArgumentOutOfRangeException(nameof(destinationDatabase)), -1 when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.REPLACE), - -1 => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey), - _ when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase, RedisLiterals.REPLACE), - _ => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase), + -1 => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey), + _ when replace => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase, RedisLiterals.REPLACE), + _ => Message.Create(Database, flags, RedisCommand.COPY, sourceKey, destinationKey, RedisLiterals.DB, destinationDatabase), }; private Message GetExpiryMessage(in RedisKey key, CommandFlags flags, TimeSpan? expiry, ExpireWhen when, out ServerEndPoint? server) @@ -3586,7 +3586,7 @@ public MultiStreamReadGroupCommandMessage(int db, CommandFlags flags, StreamPosi this.countPerStream = countPerStream; this.noAck = noAck; - argCount = 4 // Room for GROUP groupName consumerName & STREAMS + argCount = 4 // Room for GROUP groupName consumerName & STREAMS + (streamPositions.Length * 2) // Enough room for the stream keys and associated IDs. + (countPerStream.HasValue ? 2 : 0) // Room for "COUNT num" or 0 if countPerStream is null. + (noAck ? 1 : 0); // Allow for the NOACK subcommand. @@ -3742,21 +3742,26 @@ private Message GetSetIntersectionLengthMessage(RedisKey[] keys, long limit = 0, private Message GetSortedSetAddMessage(RedisKey key, RedisValue member, double score, SortedSetWhen when, bool change, CommandFlags flags) { - RedisValue[] arr = new RedisValue[2 + when.CountBits() + (change? 1:0)]; + RedisValue[] arr = new RedisValue[2 + when.CountBits() + (change ? 1 : 0)]; int index = 0; - if ((when & SortedSetWhen.NotExists) != 0) { + if ((when & SortedSetWhen.NotExists) != 0) + { arr[index++] = RedisLiterals.NX; } - if ((when & SortedSetWhen.Exists) != 0) { + if ((when & SortedSetWhen.Exists) != 0) + { arr[index++] = RedisLiterals.XX; } - if ((when & SortedSetWhen.GreaterThan) != 0) { + if ((when & SortedSetWhen.GreaterThan) != 0) + { arr[index++] = RedisLiterals.GT; } - if ((when & SortedSetWhen.LessThan) != 0) { + if ((when & SortedSetWhen.LessThan) != 0) + { arr[index++] = RedisLiterals.LT; } - if (change) { + if (change) + { arr[index++] = RedisLiterals.CH; } arr[index++] = score; @@ -3773,21 +3778,26 @@ private Message GetSortedSetAddMessage(RedisKey key, RedisValue member, double s case 1: return GetSortedSetAddMessage(key, values[0].element, values[0].score, when, change, flags); default: - RedisValue[] arr = new RedisValue[(values.Length * 2) + when.CountBits() + (change? 1:0)]; + RedisValue[] arr = new RedisValue[(values.Length * 2) + when.CountBits() + (change ? 1 : 0)]; int index = 0; - if ((when & SortedSetWhen.NotExists) != 0) { + if ((when & SortedSetWhen.NotExists) != 0) + { arr[index++] = RedisLiterals.NX; } - if ((when & SortedSetWhen.Exists) != 0) { + if ((when & SortedSetWhen.Exists) != 0) + { arr[index++] = RedisLiterals.XX; } - if ((when & SortedSetWhen.GreaterThan) != 0) { + if ((when & SortedSetWhen.GreaterThan) != 0) + { arr[index++] = RedisLiterals.GT; } - if ((when & SortedSetWhen.LessThan) != 0) { + if ((when & SortedSetWhen.LessThan) != 0) + { arr[index++] = RedisLiterals.LT; } - if (change) { + if (change) + { arr[index++] = RedisLiterals.CH; } @@ -3819,9 +3829,9 @@ private Message GetSortMessage(RedisKey destination, RedisKey key, long skip, lo { return order switch { - Order.Ascending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key), - Order.Ascending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.ALPHA), - Order.Descending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key, RedisLiterals.DESC), + Order.Ascending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key), + Order.Ascending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.ALPHA), + Order.Descending when sortType == SortType.Numeric => Message.Create(Database, flags, command, key, RedisLiterals.DESC), Order.Descending when sortType == SortType.Alphabetic => Message.Create(Database, flags, command, key, RedisLiterals.DESC, RedisLiterals.ALPHA), Order.Ascending or Order.Descending => throw new ArgumentOutOfRangeException(nameof(sortType)), _ => throw new ArgumentOutOfRangeException(nameof(order)), @@ -4326,7 +4336,8 @@ public SingleStreamReadGroupCommandMessage(int db, CommandFlags flags, RedisKey argCount = 6 + (count.HasValue ? 2 : 0) + (noAck ? 1 : 0); } - protected override void WriteImpl(PhysicalConnection physical) { + protected override void WriteImpl(PhysicalConnection physical) + { physical.WriteHeader(Command, argCount); physical.WriteBulkString(StreamConstants.Group); physical.WriteBulkString(groupName); @@ -4522,12 +4533,12 @@ private Message GetStringSetMessage( // no expiry return when switch { - When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value), - When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.KEEPTTL), + When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value), + When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.KEEPTTL), When.NotExists when !keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value), - When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value, RedisLiterals.KEEPTTL), - When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX), - When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.KEEPTTL), + When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SETNX, key, value, RedisLiterals.KEEPTTL), + When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX), + When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.KEEPTTL), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; } @@ -4539,8 +4550,8 @@ private Message GetStringSetMessage( long seconds = milliseconds / 1000; return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SETEX, key, seconds, value), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX), + When.Always => Message.Create(Database, flags, RedisCommand.SETEX, key, seconds, value), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.NX), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4548,8 +4559,8 @@ private Message GetStringSetMessage( return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.PSETEX, key, milliseconds, value), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX), + When.Always => Message.Create(Database, flags, RedisCommand.PSETEX, key, milliseconds, value), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.NX), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4571,12 +4582,12 @@ private Message GetStringSetAndGetMessage( // no expiry return when switch { - When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET), - When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET, RedisLiterals.KEEPTTL), - When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET), - When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.Always when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET), + When.Always when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.Exists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET), + When.Exists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.XX, RedisLiterals.GET, RedisLiterals.KEEPTTL), When.NotExists when !keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET), - When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET, RedisLiterals.KEEPTTL), + When.NotExists when keepTtl => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.NX, RedisLiterals.GET, RedisLiterals.KEEPTTL), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; } @@ -4588,8 +4599,8 @@ private Message GetStringSetAndGetMessage( long seconds = milliseconds / 1000; return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.GET), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX, RedisLiterals.GET), + When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.GET), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.XX, RedisLiterals.GET), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.EX, seconds, RedisLiterals.NX, RedisLiterals.GET), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4597,8 +4608,8 @@ private Message GetStringSetAndGetMessage( return when switch { - When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.GET), - When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX, RedisLiterals.GET), + When.Always => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.GET), + When.Exists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.XX, RedisLiterals.GET), When.NotExists => Message.Create(Database, flags, RedisCommand.SET, key, value, RedisLiterals.PX, milliseconds, RedisLiterals.NX, RedisLiterals.GET), _ => throw new ArgumentOutOfRangeException(nameof(when)), }; @@ -4609,10 +4620,10 @@ private Message GetStringSetAndGetMessage( 0 => ((flags & CommandFlags.FireAndForget) != 0) ? null : Message.Create(Database, flags, RedisCommand.INCRBY, key, value), - 1 => Message.Create(Database, flags, RedisCommand.INCR, key), - -1 => Message.Create(Database, flags, RedisCommand.DECR, key), + 1 => Message.Create(Database, flags, RedisCommand.INCR, key), + -1 => Message.Create(Database, flags, RedisCommand.DECR, key), > 0 => Message.Create(Database, flags, RedisCommand.INCRBY, key, value), - _ => Message.Create(Database, flags, RedisCommand.DECRBY, key, -value), + _ => Message.Create(Database, flags, RedisCommand.DECRBY, key, -value), }; private static RedisCommand SetOperationCommand(SetOperation operation, bool store) => operation switch diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index bfd6b1a44..737effc1d 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -76,6 +76,7 @@ public static readonly RedisValue EX = "EX", EXAT = "EXAT", EXISTS = "EXISTS", + FIELDS = "FIELDS", FILTERBY = "FILTERBY", FLUSH = "FLUSH", FREQ = "FREQ", From 1ae4d4a0eed3a308fa96fa6b0c953f19930e4f1f Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 17 May 2024 16:37:03 +0300 Subject: [PATCH 03/13] support for hash field expiration HPEXPIRETIME, HPTTL, HPERSIST, HGETF, HSETF --- .../Enums/HashFieldFlags.cs | 63 +++ src/StackExchange.Redis/Enums/RedisCommand.cs | 12 + .../Interfaces/IDatabase.cs | 194 ++++++++- .../Interfaces/IDatabaseAsync.cs | 192 +++++++++ .../KeyspaceIsolation/KeyPrefixed.cs | 36 ++ .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 47 ++- .../PublicAPI/PublicAPI.Shipped.txt | 31 ++ src/StackExchange.Redis/RedisDatabase.cs | 209 ++++++++++ src/StackExchange.Redis/RedisLiterals.cs | 1 + src/StackExchange.Redis/ResultProcessor.cs | 71 +++- .../HashFieldTests.cs | 393 ++++++++++++++++++ 11 files changed, 1236 insertions(+), 13 deletions(-) create mode 100644 src/StackExchange.Redis/Enums/HashFieldFlags.cs diff --git a/src/StackExchange.Redis/Enums/HashFieldFlags.cs b/src/StackExchange.Redis/Enums/HashFieldFlags.cs new file mode 100644 index 000000000..0320ff31b --- /dev/null +++ b/src/StackExchange.Redis/Enums/HashFieldFlags.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace StackExchange.Redis; + +/// +/// Specifies the options to the HSETF command when to create hash/fields and the return data +/// +[Flags] +public enum HashFieldFlags +{ + + /// + /// No options specified. + /// + None = 0, + /// + /// When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// + DC = 1, + /// + /// When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// + DCF = 2, + /// + /// When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + DOF = 4, + /// + /// When GETNEW is specified: returns the new value of given fields + /// + GETNEW = 8, + /// + /// When GETOLD is specified: returns the old value of given fields + /// + GETOLD = 16, +} + +internal static class HashFieldFlagsExtensions +{ + internal static bool isNone(this HashFieldFlags flags) => + flags == HashFieldFlags.None; + internal static bool isDC(this HashFieldFlags flags) => + flags.HasFlag(HashFieldFlags.DC); + + internal static bool isDCF(this HashFieldFlags flags) => + flags.HasFlag(HashFieldFlags.DCF); + + internal static bool isDOF(this HashFieldFlags flags) => + flags.HasFlag(HashFieldFlags.DOF); + + internal static bool isGETNEW(this HashFieldFlags flags) => + flags.HasFlag(HashFieldFlags.GETNEW); + + internal static bool isGETOLD(this HashFieldFlags flags) => + flags.HasFlag(HashFieldFlags.GETOLD); + + internal static List ToRedisValueList(this HashFieldFlags flags) => + flags.isNone() ? new List() : flags.ToString().Split(',').Select(v => (RedisValue)v).ToList(); + +} + diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs index a910c7e49..1d228e36c 100644 --- a/src/StackExchange.Redis/Enums/RedisCommand.cs +++ b/src/StackExchange.Redis/Enums/RedisCommand.cs @@ -68,19 +68,25 @@ internal enum RedisCommand HEXISTS, HEXPIRE, HEXPIREAT, + HEXPIRETIME, HGET, HGETALL, + HGETF, HINCRBY, HINCRBYFLOAT, HKEYS, HLEN, HMGET, HMSET, + HPERSIST, HPEXPIRE, HPEXPIREAT, + HPEXPIRETIME, + HPTTL, HRANDFIELD, HSCAN, HSET, + HSETF, HSETNX, HSTRLEN, HVALS, @@ -285,12 +291,15 @@ internal static bool IsPrimaryOnly(this RedisCommand command) case RedisCommand.HDEL: case RedisCommand.HEXPIRE: case RedisCommand.HEXPIREAT: + case RedisCommand.HGETF: case RedisCommand.HINCRBY: case RedisCommand.HINCRBYFLOAT: case RedisCommand.HMSET: + case RedisCommand.HPERSIST: case RedisCommand.HPEXPIRE: case RedisCommand.HPEXPIREAT: case RedisCommand.HSET: + case RedisCommand.HSETF: case RedisCommand.HSETNX: case RedisCommand.INCR: case RedisCommand.INCRBY: @@ -386,11 +395,14 @@ internal static bool IsPrimaryOnly(this RedisCommand command) case RedisCommand.GETRANGE: case RedisCommand.HELLO: case RedisCommand.HEXISTS: + case RedisCommand.HEXPIRETIME: case RedisCommand.HGET: case RedisCommand.HGETALL: case RedisCommand.HKEYS: case RedisCommand.HLEN: case RedisCommand.HMGET: + case RedisCommand.HPEXPIRETIME: + case RedisCommand.HPTTL: case RedisCommand.HRANDFIELD: case RedisCommand.HSCAN: case RedisCommand.HSTRLEN: diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index f5db64022..b5baf75a1 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -394,6 +394,84 @@ public interface IDatabase : IRedis, IDatabaseAsync /// ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + /// + /// For specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) + /// + /// The key of the hash. + /// The field in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// expiration time: as a UNIX timestamp in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) + /// + /// The key of the hash. + /// The fields in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// expiration time: as a UNIX timestamp in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For specified field, it removes the expiration time + /// + /// The key of the hash. + /// The field in the hash to remove expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// 1: if the expiration time was removed + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it removes the expiration time + /// + /// The key of the hash. + /// The fields in the hash to remove expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// 1: if the expiration time was removed + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For specified field, it gets the remaining time to live in milliseconds + /// + /// The key of the hash. + /// The field in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// time to live: in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the remaining time to live in milliseconds + /// + /// The key of the hash. + /// The fields in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// time to live: in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + /// /// Returns the value associated with field in the hash stored at key. /// @@ -426,6 +504,120 @@ public interface IDatabase : IRedis, IDatabaseAsync /// RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + /// + /// For each specified field, it gets the value and sets the field's remaining time to live + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The time out to set in milliseconds + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the value and sets the field's expiration timestamp + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the value and removes the field's expiration + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// Whether to maintain the existing expiration. + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The time out to set in milliseconds + /// under which condition the expiration will be set using . + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + /// /// Returns all fields and values of the hash stored at key. /// @@ -1697,7 +1889,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when, CommandFlags flags= CommandFlags.None); + bool SortedSetAdd(RedisKey key, RedisValue member, double score, When when, CommandFlags flags = CommandFlags.None); /// /// Adds the specified member with the specified score to the sorted set stored at key. diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index e49fba6f9..58291e0f7 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -380,6 +380,198 @@ public interface IDatabaseAsync : IRedisAsync /// Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + /// + /// For specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) + /// + /// The key of the hash. + /// The field in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// expiration time: as a UNIX timestamp in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) + /// + /// The key of the hash. + /// The fields in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// expiration time: as a UNIX timestamp in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For specified field, it removes the expiration time + /// + /// The key of the hash. + /// The field in the hash to remove expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// 1: if the expiration time was removed + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it removes the expiration time + /// + /// The key of the hash. + /// The fields in the hash to remove expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// 1: if the expiration time was removed + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For specified field, it gets the remaining time to live in milliseconds + /// + /// The key of the hash. + /// The field in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given field + /// time to live: in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the remaining time to live in milliseconds + /// + /// The key of the hash. + /// The fields in the hash to get expire time. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// time to live: in milliseconds + /// -1: if field has no associated expiration time + /// -2: no such field + /// + Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the value and sets the field's remaining time to live + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The time out to set in milliseconds + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the value and sets the field's expiration timestamp + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it gets the value and removes the field's expiration + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// value: value of field + /// nil: if no such field exists + /// + Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// Whether to maintain the existing expiration. + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The time out to set in milliseconds + /// under which condition the expiration will be set using . + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + + /// + /// For each specified field, it sets the value and optionally sets the fields expiration + /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist + /// - When DC is not specified: if key does not exist: create key + /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) + /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time + /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist + /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists + /// + /// The key of the hash. + /// The fields in the hash for this operation. + /// The exact date to expiry to set. + /// under which condition the expiration will be set using . + /// + /// The flags to use for this operation. + /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// return value depends on the HashFieldFlags (GETNEW/GETOLD) + /// if GETNEW is specified: the value of field after command execution + /// if GETOLD is specified: the value of field before command execution + /// if GETNEW or GETOLD is not specified: a + b where + /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) + /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) + /// + Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + /// /// Returns the value associated with field in the hash stored at key. /// diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index ec13180ac..6f59a408a 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -96,6 +96,42 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); + public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldExpireTimeAsync(ToInner(key), hashField, flags); + + public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldExpireTimeAsync(ToInner(key), hashFields, flags); + + public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldPersistAsync(ToInner(key), hashField, flags); + + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldPersistAsync(ToInner(key), hashFields, flags); + + public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldTimeToLiveAsync(ToInner(key), hashField, flags); + + public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldTimeToLiveAsync(ToInner(key), hashFields, flags); + + public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAsync(ToInner(key), hashFields, expireDuration, when, flags); + + public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAsync(ToInner(key), hashFields, expireTime, when, flags); + + public Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashGetPersistFieldsAsync(ToInner(key), hashFields, flags); + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAsync(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAsync(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAsync(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); + public Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAllAsync(ToInner(key), flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index 05a4c6463..bf5583c37 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -33,7 +33,7 @@ public bool GeoAdd(RedisKey key, GeoEntry value, CommandFlags flags = CommandFla public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None) => Inner.GeoRemove(ToInner(key), member, flags); - public double? GeoDistance(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters,CommandFlags flags = CommandFlags.None) => + public double? GeoDistance(RedisKey key, RedisValue member1, RedisValue member2, GeoUnit unit = GeoUnit.Meters, CommandFlags flags = CommandFlags.None) => Inner.GeoDistance(ToInner(key), member1, member2, unit, flags); public string?[] GeoHash(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None) => @@ -48,7 +48,7 @@ public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = Comm public GeoPosition? GeoPosition(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None) => Inner.GeoPosition(ToInner(key), member, flags); - public GeoRadiusResult[] GeoRadius(RedisKey key, RedisValue member, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null,GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => + public GeoRadiusResult[] GeoRadius(RedisKey key, RedisValue member, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => Inner.GeoRadius(ToInner(key), member, radius, unit, count, order, options, flags); public GeoRadiusResult[] GeoRadius(RedisKey key, double longitude, double latitude, double radius, GeoUnit unit = GeoUnit.Meters, int count = -1, Order? order = null, GeoRadiusOptions options = GeoRadiusOptions.Default, CommandFlags flags = CommandFlags.None) => @@ -93,6 +93,24 @@ public bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); + public long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldExpireTime(ToInner(key), hashField, flags); + + public long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldExpireTime(ToInner(key), hashFields, flags); + + public long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldPersist(ToInner(key), hashField, flags); + + public long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldPersist(ToInner(key), hashFields, flags); + + public long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldTimeToLive(ToInner(key), hashField, flags); + + public long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldTimeToLive(ToInner(key), hashFields, flags); + public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAll(ToInner(key), flags); @@ -102,6 +120,24 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGet(ToInner(key), hashField, flags); + public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => + Inner.HashGet(ToInner(key), hashFields, expireDuration, when, flags); + + public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => + Inner.HashGet(ToInner(key), hashFields, expireTime, when, flags); + + public RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashGetPersistFields(ToInner(key), hashFields, flags); + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSet(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSet(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSet(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); + public Lease? HashGetLease(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGetLease(ToInner(key), hashField, flags); @@ -419,7 +455,7 @@ public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, CommandFlags fla public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, When when = When.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetAdd(ToInner(key), values, when, flags); - public long SortedSetAdd(RedisKey key, SortedSetEntry[] values,SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => + public long SortedSetAdd(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetAdd(ToInner(key), values, when, flags); public bool SortedSetAdd(RedisKey key, RedisValue member, double score, CommandFlags flags) => @@ -522,7 +558,7 @@ public long SortedSetRemoveRangeByValue(RedisKey key, RedisValue min, RedisValue public double?[] SortedSetScores(RedisKey key, RedisValue[] members, CommandFlags flags = CommandFlags.None) => Inner.SortedSetScores(ToInner(key), members, flags); - public long SortedSetUpdate(RedisKey key, SortedSetEntry[] values,SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => + public long SortedSetUpdate(RedisKey key, SortedSetEntry[] values, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.SortedSetUpdate(ToInner(key), values, when, flags); public bool SortedSetUpdate(RedisKey key, RedisValue member, double score, SortedSetWhen when = SortedSetWhen.Always, CommandFlags flags = CommandFlags.None) => @@ -719,7 +755,7 @@ IEnumerable IDatabase.HashScan(RedisKey key, RedisValue pattern, int => Inner.HashScan(ToInner(key), pattern, pageSize, cursor, pageOffset, flags); IEnumerable IDatabase.SetScan(RedisKey key, RedisValue pattern, int pageSize, CommandFlags flags) - => Inner.SetScan(ToInner(key), pattern, pageSize, flags); + => Inner.SetScan(ToInner(key), pattern, pageSize, flags); IEnumerable IDatabase.SetScan(RedisKey key, RedisValue pattern, int pageSize, long cursor, int pageOffset, CommandFlags flags) => Inner.SetScan(ToInner(key), pattern, pageSize, cursor, pageOffset, flags); @@ -735,5 +771,6 @@ public bool KeyTouch(RedisKey key, CommandFlags flags = CommandFlags.None) => public long KeyTouch(RedisKey[] keys, CommandFlags flags = CommandFlags.None) => Inner.KeyTouch(ToInner(keys), flags); + } } diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index 51bbb22df..27ba9517c 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -462,6 +462,13 @@ StackExchange.Redis.HashEntry.HashEntry(StackExchange.Redis.RedisValue name, Sta StackExchange.Redis.HashEntry.Key.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Name.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Value.get -> StackExchange.Redis.RedisValue +StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DC = 1 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DCF = 2 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DOF = 4 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.GETNEW = 8 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.GETOLD = 16 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.None = 0 -> StackExchange.Redis.HashFieldFlags StackExchange.Redis.HashSlotMovedEventArgs StackExchange.Redis.HashSlotMovedEventArgs.HashSlot.get -> int StackExchange.Redis.HashSlotMovedEventArgs.HashSlotMovedEventArgs(object! sender, int hashSlot, System.Net.EndPoint! old, System.Net.EndPoint! new) -> void @@ -548,8 +555,17 @@ StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? +StackExchange.Redis.IDatabase.HashFieldExpireTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? +StackExchange.Redis.IDatabase.HashFieldExpireTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? +StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? +StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? +StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? +StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! +StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashGetPersistFields(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashGetAll(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.HashEntry[]! StackExchange.Redis.IDatabase.HashGetLease(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.Lease? StackExchange.Redis.IDatabase.HashIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> double @@ -563,6 +579,9 @@ StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackEx StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern, int pageSize, StackExchange.Redis.CommandFlags flags) -> System.Collections.Generic.IEnumerable! StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> void StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool +StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashStringLength(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.HashValues(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HyperLogLogAdd(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool @@ -783,10 +802,19 @@ StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.Redi StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetLeaseAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task?>! +StackExchange.Redis.IDatabaseAsync.HashGetPersistFieldsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, long value = 1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashKeysAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! @@ -797,6 +825,9 @@ StackExchange.Redis.IDatabaseAsync.HashRandomFieldsWithValuesAsync(StackExchange StackExchange.Redis.IDatabaseAsync.HashScanAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern = default(StackExchange.Redis.RedisValue), int pageSize = 250, long cursor = 0, int pageOffset = 0, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Collections.Generic.IAsyncEnumerable! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashStringLengthAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashValuesAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HyperLogLogAddAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 29135fb2a..c0d4d072c 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Threading.Tasks; using Pipelines.Sockets.Unofficial.Arenas; @@ -468,8 +469,87 @@ private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen private Task AsyncExpireResultArrayExecutor(Message msg, ServerEndPoint? server) => ExecuteAsync(msg, ResultProcessor.ExpireResultArray, server); + private T HashFieldExecute(RedisCommand cmd, RedisKey key, CustomExecutor executor, P processor, CommandFlags flags = CommandFlags.None, params RedisValue[] hashFields) + { + var values = new List { RedisLiterals.FIELDS, hashFields.Length }; + values.AddRange(hashFields); + RedisFeatures features = GetFeatures(key, flags, cmd, out ServerEndPoint? server); + var msg = Message.Create(Database, flags, cmd, key, values.ToArray()); + return executor(msg, processor, server); + } + + private delegate T CustomExecutor(Message msg, P processor, ServerEndPoint? server); + + + private T? SyncCustomExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteSync(msg, processor, server); } + + private T[]? SyncCustomArrExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteSync(msg, processor, server); } + + private Task AsyncCustomExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteAsync(msg, processor, server); } + + private Task AsyncCustomArrExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteAsync(msg, processor, server); } + #endregion helper stuff for HFE + public long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } + + public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } + + public long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } + + public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } + + public long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } + + public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + } + + public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + } public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { @@ -491,6 +571,135 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteSync(msg, ResultProcessor.RedisValueArray, defaultValue: Array.Empty()); } + public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + return HashGetFields(key, args, hashFields, flags); + } + + public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + return HashGetFields(key, args, hashFields, flags); + } + + public RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PERSIST, }; + return HashGetFields(key, args, hashFields, flags); + } + + private RedisValue[]? HashGetFields(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) + { + if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); + args.Add(RedisLiterals.FIELDS); + args.Add(hashFields.Length); + args.AddRange(hashFields); + var msg = Message.Create(Database, flags, RedisCommand.HGETF, key, args.ToArray()); + return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); + } + + public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + return HashGetFieldsAsync(key, args, hashFields, flags); + } + + public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + return HashGetFieldsAsync(key, args, hashFields, flags); + } + + public Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + { + List args = new() { RedisLiterals.PERSIST, }; + return HashGetFieldsAsync(key, args, hashFields, flags); + } + + private Task HashGetFieldsAsync(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) + { + if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); + args.Add(RedisLiterals.FIELDS); + args.Add(hashFields.Length); + args.AddRange(hashFields); + var msg = Message.Create(Database, flags, RedisCommand.HGETF, key, args.ToArray()); + return ExecuteAsync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); + } + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); + return HashSetFields(key, args, hashFields, flags); + } + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + args.Add(RedisLiterals.PX); + args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); + return HashSetFields(key, args, hashFields, flags); + } + + public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + args.Add(RedisLiterals.PXAT); + args.Add(GetMillisecondsUntil(expireTime)); + return HashSetFields(key, args, hashFields, flags); + } + + private RedisValue[]? HashSetFields(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) + { + if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); + args.Add(RedisLiterals.FVS); + args.Add(hashFields.Length); + args.AddRange(hashFields.SelectMany(e => new[] { e.Name, e.Value }).ToList()); + var msg = Message.Create(Database, flags, RedisCommand.HSETF, key, args.ToArray()); + return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); + } + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); + return HashSetFieldsAsync(key, args, hashFields, flags); + } + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + args.Add(RedisLiterals.PX); + args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); + return HashSetFieldsAsync(key, args, hashFields, flags); + } + + public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + { + var args = fieldFlags.ToRedisValueList(); + if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); + args.Add(RedisLiterals.PXAT); + args.Add(GetMillisecondsUntil(expireTime)); + return HashSetFieldsAsync(key, args, hashFields, flags); + } + + private Task HashSetFieldsAsync(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) + { + if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); + args.Add(RedisLiterals.FVS); + args.Add(hashFields.Length); + args.AddRange(hashFields.SelectMany(e => new[] { e.Name, e.Value }).ToList()); + var msg = Message.Create(Database, flags, RedisCommand.HSETF, key, args.ToArray()); + return ExecuteAsync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); + } public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) { var msg = Message.Create(Database, flags, RedisCommand.HGETALL, key); diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index 737effc1d..2f54a8fff 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -80,6 +80,7 @@ public static readonly RedisValue FILTERBY = "FILTERBY", FLUSH = "FLUSH", FREQ = "FREQ", + FVS = "FVS", GET = "GET", GETKEYS = "GETKEYS", GETNAME = "GETNAME", diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index 0a84bdcb8..297adf974 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -93,9 +93,16 @@ public static readonly ResultProcessor> public static readonly ResultProcessor RedisValueArray = new RedisValueArrayProcessor(); + + public static readonly ResultProcessor + NullableRedisValueArray = new NullableRedisValueArrayProcessor(); + public static readonly ResultProcessor Int64Array = new Int64ArrayProcessor(); + public static readonly ResultProcessor + Int64NullableArray = new Int64NullableArrayProcessor(); + public static readonly ResultProcessor NullableStringArray = new NullableStringArrayProcessor(); @@ -1279,7 +1286,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes SetResult(message, true); return true; } - if(message.Command == RedisCommand.AUTH) connection?.BridgeCouldBeNull?.Multiplexer?.SetAuthSuspect(new RedisException("Unknown AUTH exception")); + if (message.Command == RedisCommand.AUTH) connection?.BridgeCouldBeNull?.Multiplexer?.SetAuthSuspect(new RedisException("Unknown AUTH exception")); return false; } } @@ -1444,6 +1451,17 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes return true; } break; + case ResultType.Array: + var items = result.GetItems(); + if (items.Length == 1) + { // treat an array of 1 like a single reply + if (items[0].TryGetInt64(out long value)) + { + SetResult(message, value); + return true; + } + } + break; } return false; } @@ -1602,6 +1620,29 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } + private sealed class NullableRedisValueArrayProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + switch (result.Resp2TypeBulkString) + { + // allow a single item to pass explicitly pretending to be an array + case ResultType.BulkString: + // If the result is nil, the result should be an empty array + var arr = result.IsNull + ? null + : new[] { result.AsRedisValue() }; + SetResult(message, arr); + return true; + case ResultType.Array: + arr = result.GetItemsAsValues()!; + SetResult(message, arr); + return true; + } + return false; + } + } + private sealed class Int64ArrayProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) @@ -1617,6 +1658,21 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } + private sealed class Int64NullableArrayProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + if (result.Resp2TypeArray == ResultType.Array || result.IsNull) + { + var arr = result.ToArray((in RawResult x) => (long)x.AsRedisValue())!; + SetResult(message, arr); + return true; + } + + return false; + } + } + private sealed class NullableStringArrayProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) @@ -2285,7 +2341,8 @@ internal static bool TryRead(Sequence pairs, in CommandBytes key, ref internal static bool TryRead(Sequence pairs, in CommandBytes key, ref int value) { long tmp = default; - if(TryRead(pairs, key, ref tmp)) { + if(TryRead(pairs, key, ref tmp)) + { value = checked((int)tmp); return true; } @@ -2411,13 +2468,13 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes var lastGeneratedId = Redis.RedisValue.Null; StreamEntry firstEntry = StreamEntry.Null, lastEntry = StreamEntry.Null; var iter = arr.GetEnumerator(); - for(int i = 0; i < max; i++) + for (int i = 0; i < max; i++) { ref RawResult key = ref iter.GetNext(), value = ref iter.GetNext(); if (key.Payload.Length > CommandBytes.MaxLength) continue; var keyBytes = new CommandBytes(key.Payload); - if(keyBytes.Equals(CommonReplies.length)) + if (keyBytes.Equals(CommonReplies.length)) { if (!value.TryGetInt64(out length)) return false; } @@ -2507,8 +2564,8 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes lowestId: arr[1].AsRedisValue(), highestId: arr[2].AsRedisValue(), consumers: consumers ?? Array.Empty()); - // ^^^^^ - // Should we bother allocating an empty array only to prevent the need for a null check? + // ^^^^^ + // Should we bother allocating an empty array only to prevent the need for a null check? SetResult(message, pendingInfo); return true; @@ -2895,7 +2952,7 @@ internal abstract class ArrayResultProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { - switch(result.Resp2TypeArray) + switch (result.Resp2TypeArray) { case ResultType.Array: var items = result.GetItems(); diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index 8869c3bb7..f9b9c5b80 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -175,4 +175,397 @@ public void HashFieldExpireConditionsNotSatisfied() result = db.HashFieldExpire(hashKey, "f4", oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); Assert.Equal(ExpireResult.ConditionNotMet, result); } + + [Fact] + public void HashFieldExpireTime() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, nextCentury); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + + var result = db.HashFieldExpireTime(hashKey, "f1"); + Assert.Equal(ms, result); + + var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new[] { ms, ms }, fieldsResult); + } + + [Fact] + public void HashFieldExpireFieldNoExpireTime() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldExpireTime(hashKey, "f1"); + Assert.Equal(-1, result); + + var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1, }, fieldsResult); + } + + [Fact] + public void HashFieldExpireTimeNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var result = db.HashFieldExpireTime(hashKey, "f1"); + Assert.Null(result); + + var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + Assert.Null(fieldsResult); + } + + [Fact] + public void HashFieldExpireTimeNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var result = db.HashFieldExpireTime(hashKey, "notExistingField1"); + Assert.Equal(-2, result); + + var fieldsResult = db.HashFieldExpireTime(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); + Assert.Equal(new long[] { -2, -2, }, fieldsResult); + } + + [Fact] + public void HashFieldTimeToLive() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + + var result = db.HashFieldTimeToLive(hashKey, "f1"); + Assert.NotNull(result); + Assert.True(result > 0); + + var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(fieldsResult); + Assert.True(fieldsResult.Length > 0); + Assert.True(fieldsResult.All(x => x > 0)); + } + + [Fact] + public void HashFieldTimeToLiveNoExpireTime() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldTimeToLive(hashKey, "f1"); + Assert.Equal(-1, result); + + var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + Assert.Equal(new long[] { -1, -1, }, fieldsResult); + } + + [Fact] + public void HashFieldTimeToLiveNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var result = db.HashFieldTimeToLive(hashKey, "f1"); + Assert.Null(result); + + var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + Assert.Null(fieldsResult); + } + + [Fact] + public void HashFieldTimeToLiveNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var result = db.HashFieldTimeToLive(hashKey, "notExistingField1"); + Assert.Equal(-2, result); + + var fieldsResult = db.HashFieldTimeToLive(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); + Assert.Equal(new long[] { -2, -2, }, fieldsResult); + } + + [Fact] + public void HashFieldPersist() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + + var result = db.HashFieldPersist(hashKey, "f1"); + Assert.Equal(1, result); + + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var fieldsResult = db.HashFieldPersist(hashKey, fields); + Assert.Equal(new long[] { 1, 1, }, fieldsResult); + } + + [Fact] + public void HashFieldPersistNoExpireTime() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var result = db.HashFieldPersist(hashKey, "f1"); + Assert.Equal(-1, result); + + var fieldsResult = db.HashFieldPersist(hashKey, fields); + Assert.Equal(new long[] { -1, -1, }, fieldsResult); + } + + [Fact] + public void HashFieldPersistNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var result = db.HashFieldPersist(hashKey, "f1"); + Assert.Null(result); + + var fieldsResult = db.HashFieldPersist(hashKey, fields); + Assert.Null(fieldsResult); + } + + [Fact] + public void HashFieldPersistNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var result = db.HashFieldPersist(hashKey, "notExistingField1"); + Assert.Equal(-2, result); + + var fieldsResult = db.HashFieldPersist(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); + Assert.Equal(new long[] { -2, -2, }, fieldsResult); + } + + [Fact] + public void HashFieldGet() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(ttlResults); + Assert.True(ttlResults.Length > 0); + Assert.True(ttlResults.All(x => x > 0)); + + fieldsResult = db.HashGet(hashKey, fields, nextCentury); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var expireDates = db.HashFieldExpireTime(hashKey, fields); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + Assert.Equal(new[] { ms, ms }, expireDates); + + + fieldsResult = db.HashGetPersistFields(hashKey, fields); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); + } + + [Fact] + public void HashFieldGetWithExpireConditions() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(ttlResults); + Assert.True(ttlResults.Length > 0); + Assert.True(ttlResults.All(x => x > 0)); + + fieldsResult = db.HashGet(hashKey, fields, nextCentury, ExpireWhen.HasNoExpiry); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var expireDates = db.HashFieldExpireTime(hashKey, fields); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + Assert.NotEqual(new[] { ms, ms }, expireDates); + + + fieldsResult = db.HashGetPersistFields(hashKey, fields); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); + } + + [Fact] + public void HashFieldGetNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs); + Assert.Null(fieldsResult); + + fieldsResult = db.HashGet(hashKey, fields, nextCentury); + Assert.Null(fieldsResult); + } + + [Fact] + public void HashFieldGetNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var fieldsResult = db.HashGet(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, oneYearInMs); + Assert.NotNull(fieldsResult); + Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); + + fieldsResult = db.HashGet(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, nextCentury); + Assert.NotNull(fieldsResult); + Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); + } + + [Fact] + public void HashFieldSet() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + + var fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("f1", 1), new HashEntry("f2", 2) }, oneYearInMs); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(ttlResults); + Assert.True(ttlResults.Length > 0); + Assert.True(ttlResults.All(x => x > 0)); + + fieldsResult = db.HashSet(hashKey, entries, nextCentury); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var expireDates = db.HashFieldExpireTime(hashKey, fields); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + Assert.Equal(new[] { ms, ms }, expireDates); + + fieldsResult = db.HashSet(hashKey, entries, false); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); + } + + [Fact] + public void HashFieldSetNoKey() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + + var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + fieldsResult = db.HashSet(hashKey, entries, nextCentury); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + } + + [Fact] + public void HashFieldSetNoField() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.HashSet(hashKey, entries); + db.HashFieldExpire(hashKey, fields, oneYearInMs); + + var fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, oneYearInMs); + Assert.NotNull(fieldsResult); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, nextCentury); + Assert.NotNull(fieldsResult); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + } + + [Fact] + public void HashFieldSetWithExpireConditions() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.KeyDelete(hashKey); + + var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(ttlResults); + Assert.True(ttlResults.Length > 0); + Assert.True(ttlResults.All(x => x > 0)); + + fieldsResult = db.HashSet(hashKey, entries, nextCentury, ExpireWhen.HasNoExpiry); + Assert.Equal(new RedisValue[] { 1, 1, }, fieldsResult); + + var expireDates = db.HashFieldExpireTime(hashKey, fields); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + Assert.NotEqual(new[] { ms, ms }, expireDates); + + fieldsResult = db.HashSet(hashKey, entries, false); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); + } + + [Fact] + public void HashFieldSetWithFlags() + { + var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var hashKey = Me(); + db.KeyDelete(hashKey); + + var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DC); + Assert.Null(fieldsResult); + + fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DCF); + Assert.Null(fieldsResult); + + fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DOF); + Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); + + var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + Assert.NotNull(ttlResults); + Assert.True(ttlResults.Length > 0); + Assert.True(ttlResults.All(x => x > 0)); + + fieldsResult = db.HashSet(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GETOLD); + Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); + + var expireDates = db.HashFieldExpireTime(hashKey, fields); + long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); + Assert.NotEqual(new[] { ms, ms }, expireDates); + + + fieldsResult = db.HashSet(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GETNEW); + Assert.Equal(new RedisValue[] { "x", "y" }, fieldsResult); + + var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); + } } From 7dbb7afe351a94f2dcfaf246b28c5c1be71e078d Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 17 May 2024 20:16:00 +0300 Subject: [PATCH 04/13] rename some methods and tidy up --- .../Enums/HashFieldFlags.cs | 14 ++- .../Interfaces/IDatabase.cs | 12 +-- .../Interfaces/IDatabaseAsync.cs | 12 +-- .../KeyspaceIsolation/KeyPrefixed.cs | 24 ++--- .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 24 ++--- .../PublicAPI/PublicAPI.Shipped.txt | 24 ++--- src/StackExchange.Redis/RedisDatabase.cs | 100 ++++++++---------- .../HashFieldTests.cs | 53 +++++----- 8 files changed, 130 insertions(+), 133 deletions(-) diff --git a/src/StackExchange.Redis/Enums/HashFieldFlags.cs b/src/StackExchange.Redis/Enums/HashFieldFlags.cs index 0320ff31b..f38b6c348 100644 --- a/src/StackExchange.Redis/Enums/HashFieldFlags.cs +++ b/src/StackExchange.Redis/Enums/HashFieldFlags.cs @@ -56,8 +56,18 @@ internal static bool isGETNEW(this HashFieldFlags flags) => internal static bool isGETOLD(this HashFieldFlags flags) => flags.HasFlag(HashFieldFlags.GETOLD); - internal static List ToRedisValueList(this HashFieldFlags flags) => - flags.isNone() ? new List() : flags.ToString().Split(',').Select(v => (RedisValue)v).ToList(); + internal static List ToRedisValueList(this HashFieldFlags flags) + { + List values = new(); + if (flags.isNone()) return values; + if (flags.isDC()) values.Add(HashFieldFlags.DC.ToString()); + if (flags.isDCF()) values.Add(HashFieldFlags.DCF.ToString()); + if (flags.isDOF()) values.Add(HashFieldFlags.DOF.ToString()); + if (flags.isGETNEW()) values.Add(HashFieldFlags.GETNEW.ToString()); + if (flags.isGETOLD()) values.Add(HashFieldFlags.GETOLD.ToString()); + return values; + + } } diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index b5baf75a1..d44bc4d43 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -516,7 +516,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// value: value of field /// nil: if no such field exists /// - RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the value and sets the field's expiration timestamp @@ -530,7 +530,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// value: value of field /// nil: if no such field exists /// - RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the value and removes the field's expiration @@ -542,7 +542,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// value: value of field /// nil: if no such field exists /// - RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -566,7 +566,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -591,7 +591,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -616,7 +616,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// Returns all fields and values of the hash stored at key. diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index 58291e0f7..f65af5e48 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -470,7 +470,7 @@ public interface IDatabaseAsync : IRedisAsync /// value: value of field /// nil: if no such field exists /// - Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the value and sets the field's expiration timestamp @@ -484,7 +484,7 @@ public interface IDatabaseAsync : IRedisAsync /// value: value of field /// nil: if no such field exists /// - Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the value and removes the field's expiration @@ -496,7 +496,7 @@ public interface IDatabaseAsync : IRedisAsync /// value: value of field /// nil: if no such field exists /// - Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -520,7 +520,7 @@ public interface IDatabaseAsync : IRedisAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -545,7 +545,7 @@ public interface IDatabaseAsync : IRedisAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it sets the value and optionally sets the fields expiration @@ -570,7 +570,7 @@ public interface IDatabaseAsync : IRedisAsync /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) /// - Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); + Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); /// /// Returns the value associated with field in the hash stored at key. diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index 6f59a408a..704f62b53 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -114,23 +114,23 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldTimeToLiveAsync(ToInner(key), hashFields, flags); - public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAsync(ToInner(key), hashFields, expireDuration, when, flags); + public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAndSetExpiryAsync(ToInner(key), hashFields, expireDuration, when, flags); - public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAsync(ToInner(key), hashFields, expireTime, when, flags); + public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAndSetExpiryAsync(ToInner(key), hashFields, expireTime, when, flags); - public Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashGetPersistFieldsAsync(ToInner(key), hashFields, flags); + public Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashGetAndPersistFieldsAsync(ToInner(key), hashFields, flags); - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAsync(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAsync(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAsync(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); public Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAllAsync(ToInner(key), flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index bf5583c37..2ecfdaf05 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -120,23 +120,23 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGet(ToInner(key), hashField, flags); - public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => - Inner.HashGet(ToInner(key), hashFields, expireDuration, when, flags); + public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAndSetExpiry(ToInner(key), hashFields, expireDuration, when, flags); - public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => - Inner.HashGet(ToInner(key), hashFields, expireTime, when, flags); + public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => + Inner.HashGetAndSetExpiry(ToInner(key), hashFields, expireTime, when, flags); - public RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashGetPersistFields(ToInner(key), hashFields, flags); + public RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashGetAndPersistFields(ToInner(key), hashFields, flags); - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSet(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiry(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSet(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiry(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSet(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => + Inner.HashSetAndSetExpiry(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); public Lease? HashGetLease(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGetLease(ToInner(key), hashField, flags); diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index 27ba9517c..df6cc78a9 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -563,9 +563,9 @@ StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey k StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! -StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashGetPersistFields(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashGetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashGetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashGetAndPersistFields(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashGetAll(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.HashEntry[]! StackExchange.Redis.IDatabase.HashGetLease(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.Lease? StackExchange.Redis.IDatabase.HashIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> double @@ -579,9 +579,9 @@ StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackEx StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern, int pageSize, StackExchange.Redis.CommandFlags flags) -> System.Collections.Generic.IEnumerable! StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> void StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool -StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? +StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashStringLength(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.HashValues(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HyperLogLogAdd(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool @@ -811,10 +811,10 @@ StackExchange.Redis.IDatabaseAsync.HashFieldTimeToLiveAsync(StackExchange.Redis. StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashGetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashGetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetLeaseAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task?>! -StackExchange.Redis.IDatabaseAsync.HashGetPersistFieldsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashGetAndPersistFieldsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, long value = 1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashKeysAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! @@ -825,9 +825,9 @@ StackExchange.Redis.IDatabaseAsync.HashRandomFieldsWithValuesAsync(StackExchange StackExchange.Redis.IDatabaseAsync.HashScanAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern = default(StackExchange.Redis.RedisValue), int pageSize = 250, long cursor = 0, int pageOffset = 0, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Collections.Generic.IAsyncEnumerable! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashStringLengthAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashValuesAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HyperLogLogAddAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index c0d4d072c..20a3c1dd3 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -391,53 +391,53 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncExpireResultExecutor, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); } public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncExpireResultArrayExecutor, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncExpireResultExecutor, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); } public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncExpireResultArrayExecutor, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncExpireResultExecutor, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); } public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncExpireResultArrayExecutor, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncExpireResultExecutor, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); } public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncExpireResultArrayExecutor, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } #region private for HFE - private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen when, Func getCmd, Executor executor, CommandFlags flags, params RedisValue[] hashFields) + private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen when, Func getCmd, CustomExecutor executor, P processor, CommandFlags flags, params RedisValue[] hashFields) { if (hashFields == null) throw new ArgumentNullException(nameof(hashFields)); var useSeconds = milliseconds % 1000 == 0; @@ -450,44 +450,32 @@ private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWhen _ => new List { expiry, when.ToLiteral(), RedisLiterals.FIELDS, hashFields.Length }, }; values.AddRange(hashFields); - RedisFeatures features = GetFeatures(key, flags, cmd, out ServerEndPoint? server); var msg = Message.Create(Database, flags, cmd, key, values.ToArray()); - return executor(msg, server); + return executor(msg, processor); } private RedisCommand PickExpireCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIRE : RedisCommand.HPEXPIRE; private RedisCommand PickExpireAtCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIREAT : RedisCommand.HPEXPIREAT; - private delegate T Executor(Message msg, ServerEndPoint? server); - - private ExpireResult? SyncExpireResultExecutor(Message msg, ServerEndPoint? server) => ExecuteSync(msg, ResultProcessor.ExpireResult, server); - - private ExpireResult[]? SyncExpireResultArrayExecutor(Message msg, ServerEndPoint? server) => ExecuteSync(msg, ResultProcessor.ExpireResultArray, server); - - private Task AsyncExpireResultExecutor(Message msg, ServerEndPoint? server) => ExecuteAsync(msg, ResultProcessor.ExpireResult, server); - - private Task AsyncExpireResultArrayExecutor(Message msg, ServerEndPoint? server) => ExecuteAsync(msg, ResultProcessor.ExpireResultArray, server); - private T HashFieldExecute(RedisCommand cmd, RedisKey key, CustomExecutor executor, P processor, CommandFlags flags = CommandFlags.None, params RedisValue[] hashFields) { var values = new List { RedisLiterals.FIELDS, hashFields.Length }; values.AddRange(hashFields); - RedisFeatures features = GetFeatures(key, flags, cmd, out ServerEndPoint? server); var msg = Message.Create(Database, flags, cmd, key, values.ToArray()); - return executor(msg, processor, server); + return executor(msg, processor); } - private delegate T CustomExecutor(Message msg, P processor, ServerEndPoint? server); + private delegate T CustomExecutor(Message msg, P processor); - private T? SyncCustomExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteSync(msg, processor, server); } + private T? SyncCustomExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteSync(msg, processor); } - private T[]? SyncCustomArrExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteSync(msg, processor, server); } + private T[]? SyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteSync(msg, processor); } - private Task AsyncCustomExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteAsync(msg, processor, server); } + private Task AsyncCustomExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteAsync(msg, processor); } - private Task AsyncCustomArrExecutor(Message msg, P processor, ServerEndPoint? server) where P : ResultProcessor { return ExecuteAsync(msg, processor, server); } + private Task AsyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteAsync(msg, processor); } #endregion helper stuff for HFE @@ -571,27 +559,27 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteSync(msg, ResultProcessor.RedisValueArray, defaultValue: Array.Empty()); } - public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetFields(key, args, hashFields, flags); + return HashGetAndSetExpiration(key, args, hashFields, flags); } - public RedisValue[]? HashGet(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetFields(key, args, hashFields, flags); + return HashGetAndSetExpiration(key, args, hashFields, flags); } - public RedisValue[]? HashGetPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PERSIST, }; - return HashGetFields(key, args, hashFields, flags); + return HashGetAndSetExpiration(key, args, hashFields, flags); } - private RedisValue[]? HashGetFields(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) + private RedisValue[]? HashGetAndSetExpiration(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) { if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); args.Add(RedisLiterals.FIELDS); @@ -601,27 +589,27 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); } - public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetFieldsAsync(key, args, hashFields, flags); + return HashGetSetExpirationAsync(key, args, hashFields, flags); } - public Task HashGetAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetFieldsAsync(key, args, hashFields, flags); + return HashGetSetExpirationAsync(key, args, hashFields, flags); } - public Task HashGetPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { List args = new() { RedisLiterals.PERSIST, }; - return HashGetFieldsAsync(key, args, hashFields, flags); + return HashGetSetExpirationAsync(key, args, hashFields, flags); } - private Task HashGetFieldsAsync(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) + private Task HashGetSetExpirationAsync(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) { if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); args.Add(RedisLiterals.FIELDS); @@ -631,32 +619,32 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteAsync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); } - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); - return HashSetFields(key, args, hashFields, flags); + return HashSetAndSetExpiration(key, args, hashFields, flags); } - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); args.Add(RedisLiterals.PX); args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); - return HashSetFields(key, args, hashFields, flags); + return HashSetAndSetExpiration(key, args, hashFields, flags); } - public RedisValue[]? HashSet(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); args.Add(RedisLiterals.PXAT); args.Add(GetMillisecondsUntil(expireTime)); - return HashSetFields(key, args, hashFields, flags); + return HashSetAndSetExpiration(key, args, hashFields, flags); } - private RedisValue[]? HashSetFields(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) + private RedisValue[]? HashSetAndSetExpiration(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) { if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); args.Add(RedisLiterals.FVS); @@ -666,32 +654,32 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); } - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); - return HashSetFieldsAsync(key, args, hashFields, flags); + return HashSetAndSetExpirationAsync(key, args, hashFields, flags); } - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); args.Add(RedisLiterals.PX); args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); - return HashSetFieldsAsync(key, args, hashFields, flags); + return HashSetAndSetExpirationAsync(key, args, hashFields, flags); } - public Task HashSetAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) + public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) { var args = fieldFlags.ToRedisValueList(); if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); args.Add(RedisLiterals.PXAT); args.Add(GetMillisecondsUntil(expireTime)); - return HashSetFieldsAsync(key, args, hashFields, flags); + return HashSetAndSetExpirationAsync(key, args, hashFields, flags); } - private Task HashSetFieldsAsync(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) + private Task HashSetAndSetExpirationAsync(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) { if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); args.Add(RedisLiterals.FVS); diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index f9b9c5b80..4bb91c0bc 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -362,7 +362,7 @@ public void HashFieldGet() var hashKey = Me(); db.HashSet(hashKey, entries); - var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs); + var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var ttlResults = db.HashFieldTimeToLive(hashKey, fields); @@ -370,7 +370,7 @@ public void HashFieldGet() Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashGet(hashKey, fields, nextCentury); + fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var expireDates = db.HashFieldExpireTime(hashKey, fields); @@ -378,7 +378,7 @@ public void HashFieldGet() Assert.Equal(new[] { ms, ms }, expireDates); - fieldsResult = db.HashGetPersistFields(hashKey, fields); + fieldsResult = db.HashGetAndPersistFields(hashKey, fields); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); @@ -392,7 +392,7 @@ public void HashFieldGetWithExpireConditions() var hashKey = Me(); db.HashSet(hashKey, entries); - var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs, ExpireWhen.HasNoExpiry); + var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs, ExpireWhen.HasNoExpiry); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var ttlResults = db.HashFieldTimeToLive(hashKey, fields); @@ -400,7 +400,7 @@ public void HashFieldGetWithExpireConditions() Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashGet(hashKey, fields, nextCentury, ExpireWhen.HasNoExpiry); + fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury, ExpireWhen.HasNoExpiry); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var expireDates = db.HashFieldExpireTime(hashKey, fields); @@ -408,7 +408,7 @@ public void HashFieldGetWithExpireConditions() Assert.NotEqual(new[] { ms, ms }, expireDates); - fieldsResult = db.HashGetPersistFields(hashKey, fields); + fieldsResult = db.HashGetAndPersistFields(hashKey, fields); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); @@ -421,10 +421,10 @@ public void HashFieldGetNoKey() var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); - var fieldsResult = db.HashGet(hashKey, fields, oneYearInMs); + var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs); Assert.Null(fieldsResult); - fieldsResult = db.HashGet(hashKey, fields, nextCentury); + fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury); Assert.Null(fieldsResult); } @@ -436,11 +436,11 @@ public void HashFieldGetNoField() db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var fieldsResult = db.HashGet(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, oneYearInMs); + var fieldsResult = db.HashGetAndSetExpiry(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, oneYearInMs); Assert.NotNull(fieldsResult); Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); - fieldsResult = db.HashGet(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, nextCentury); + fieldsResult = db.HashGetAndSetExpiry(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, nextCentury); Assert.NotNull(fieldsResult); Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); } @@ -452,7 +452,7 @@ public void HashFieldSet() var hashKey = Me(); db.HashSet(hashKey, entries); - var fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("f1", 1), new HashEntry("f2", 2) }, oneYearInMs); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("f1", 1), new HashEntry("f2", 2) }, oneYearInMs); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var ttlResults = db.HashFieldTimeToLive(hashKey, fields); @@ -460,14 +460,14 @@ public void HashFieldSet() Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashSet(hashKey, entries, nextCentury); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var expireDates = db.HashFieldExpireTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.Equal(new[] { ms, ms }, expireDates); - fieldsResult = db.HashSet(hashKey, entries, false); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); @@ -480,10 +480,10 @@ public void HashFieldSetNoKey() var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); - var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - fieldsResult = db.HashSet(hashKey, entries, nextCentury); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); } @@ -495,11 +495,11 @@ public void HashFieldSetNoField() db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, oneYearInMs); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, oneYearInMs); Assert.NotNull(fieldsResult); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - fieldsResult = db.HashSet(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, nextCentury); + fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, nextCentury); Assert.NotNull(fieldsResult); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); } @@ -508,10 +508,9 @@ public void HashFieldSetNoField() public void HashFieldSetWithExpireConditions() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.KeyDelete(hashKey); + var hashKey = Me(); - var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var ttlResults = db.HashFieldTimeToLive(hashKey, fields); @@ -519,14 +518,14 @@ public void HashFieldSetWithExpireConditions() Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashSet(hashKey, entries, nextCentury, ExpireWhen.HasNoExpiry); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury, ExpireWhen.HasNoExpiry); Assert.Equal(new RedisValue[] { 1, 1, }, fieldsResult); var expireDates = db.HashFieldExpireTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.NotEqual(new[] { ms, ms }, expireDates); - fieldsResult = db.HashSet(hashKey, entries, false); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); @@ -540,13 +539,13 @@ public void HashFieldSetWithFlags() var hashKey = Me(); db.KeyDelete(hashKey); - var fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DC); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DC); Assert.Null(fieldsResult); - fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DCF); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DCF); Assert.Null(fieldsResult); - fieldsResult = db.HashSet(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DOF); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DOF); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); var ttlResults = db.HashFieldTimeToLive(hashKey, fields); @@ -554,7 +553,7 @@ public void HashFieldSetWithFlags() Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashSet(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GETOLD); + fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GETOLD); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); var expireDates = db.HashFieldExpireTime(hashKey, fields); @@ -562,7 +561,7 @@ public void HashFieldSetWithFlags() Assert.NotEqual(new[] { ms, ms }, expireDates); - fieldsResult = db.HashSet(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GETNEW); + fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GETNEW); Assert.Equal(new RedisValue[] { "x", "y" }, fieldsResult); var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); From 3a986225b0a3cab092e48b75e93df0cd7946a2c4 Mon Sep 17 00:00:00 2001 From: atakavci Date: Tue, 21 May 2024 16:18:13 +0300 Subject: [PATCH 05/13] aoviding abbreviations and add enum for persist result --- src/StackExchange.Redis/Enums/ExpireResult.cs | 10 +- .../Enums/HashFieldFlags.cs | 47 +++----- .../Enums/PersistResult.cs | 22 ++++ .../Interfaces/IDatabase.cs | 12 +-- .../Interfaces/IDatabaseAsync.cs | 12 +-- .../KeyspaceIsolation/KeyPrefixed.cs | 20 ++-- .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 20 ++-- .../PublicAPI/PublicAPI.Shipped.txt | 38 ++++--- src/StackExchange.Redis/RedisDatabase.cs | 32 +++--- src/StackExchange.Redis/RedisLiterals.cs | 5 + src/StackExchange.Redis/ResultProcessor.cs | 55 +++++++++- .../HashFieldTests.cs | 100 +++++++++--------- 12 files changed, 221 insertions(+), 152 deletions(-) create mode 100644 src/StackExchange.Redis/Enums/PersistResult.cs diff --git a/src/StackExchange.Redis/Enums/ExpireResult.cs b/src/StackExchange.Redis/Enums/ExpireResult.cs index 90b660104..825bc5710 100644 --- a/src/StackExchange.Redis/Enums/ExpireResult.cs +++ b/src/StackExchange.Redis/Enums/ExpireResult.cs @@ -3,24 +3,24 @@ namespace StackExchange.Redis; /// -/// Specifies when to set the expiry for a key. +/// Specifies the result of operation to set expire time. /// public enum ExpireResult { /// - /// Set expiry whether or not there is an existing expiry. + /// Field deleted because the specified expiration time is due, /// Due = 2, /// - /// Set expiry only when the new expiry is greater than current one. + /// Expiration time/duration updated successfully /// Success = 1, /// - /// Set expiry only when the key has an existing expiry. + /// Expiration not set because of a specified NX | XX | GT | LT condition not met /// ConditionNotMet = 0, /// - /// Set expiry only when the key has no expiry. + /// No such field. /// NoSuchField = -2, diff --git a/src/StackExchange.Redis/Enums/HashFieldFlags.cs b/src/StackExchange.Redis/Enums/HashFieldFlags.cs index f38b6c348..e901e3512 100644 --- a/src/StackExchange.Redis/Enums/HashFieldFlags.cs +++ b/src/StackExchange.Redis/Enums/HashFieldFlags.cs @@ -15,59 +15,46 @@ public enum HashFieldFlags /// No options specified. /// None = 0, + /// /// When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) /// - DC = 1, + DontCreate = 1, + /// /// When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist /// - DCF = 2, + DontCreateFields = 2, + /// /// When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists /// - DOF = 4, + DontOverwriteFields = 4, + /// /// When GETNEW is specified: returns the new value of given fields /// - GETNEW = 8, + GetNew = 8, + /// /// When GETOLD is specified: returns the old value of given fields /// - GETOLD = 16, + GetOld = 16, } internal static class HashFieldFlagsExtensions { - internal static bool isNone(this HashFieldFlags flags) => - flags == HashFieldFlags.None; - internal static bool isDC(this HashFieldFlags flags) => - flags.HasFlag(HashFieldFlags.DC); - - internal static bool isDCF(this HashFieldFlags flags) => - flags.HasFlag(HashFieldFlags.DCF); - - internal static bool isDOF(this HashFieldFlags flags) => - flags.HasFlag(HashFieldFlags.DOF); - - internal static bool isGETNEW(this HashFieldFlags flags) => - flags.HasFlag(HashFieldFlags.GETNEW); - - internal static bool isGETOLD(this HashFieldFlags flags) => - flags.HasFlag(HashFieldFlags.GETOLD); - + internal static bool HasAny(this HashFieldFlags value, HashFieldFlags flag) => (value & flag) != 0; internal static List ToRedisValueList(this HashFieldFlags flags) { List values = new(); - if (flags.isNone()) return values; - if (flags.isDC()) values.Add(HashFieldFlags.DC.ToString()); - if (flags.isDCF()) values.Add(HashFieldFlags.DCF.ToString()); - if (flags.isDOF()) values.Add(HashFieldFlags.DOF.ToString()); - if (flags.isGETNEW()) values.Add(HashFieldFlags.GETNEW.ToString()); - if (flags.isGETOLD()) values.Add(HashFieldFlags.GETOLD.ToString()); + if (flags == HashFieldFlags.None) return values; + if (flags.HasAny(HashFieldFlags.DontCreate)) values.Add(RedisLiterals.DC); + if (flags.HasAny(HashFieldFlags.DontCreateFields)) values.Add(RedisLiterals.DCF); + if (flags.HasAny(HashFieldFlags.DontOverwriteFields)) values.Add(RedisLiterals.DOF); + if (flags.HasAny(HashFieldFlags.GetNew)) values.Add(RedisLiterals.GETNEW); + if (flags.HasAny(HashFieldFlags.GetOld)) values.Add(RedisLiterals.GETOLD); return values; - } - } diff --git a/src/StackExchange.Redis/Enums/PersistResult.cs b/src/StackExchange.Redis/Enums/PersistResult.cs new file mode 100644 index 000000000..acee5141d --- /dev/null +++ b/src/StackExchange.Redis/Enums/PersistResult.cs @@ -0,0 +1,22 @@ +using System; + +namespace StackExchange.Redis; + +/// +/// Specifies the result of operation to remove the expire time. +/// +public enum PersistResult +{ + /// + /// Expiration removed successfully + /// + Success = 1, + /// + /// Expiration not removed because of a specified NX | XX | GT | LT condition not met + /// + ConditionNotMet = -1, + /// + /// No such field. + /// + NoSuchField = -2, +} diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index d44bc4d43..9ad2a9d6e 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -405,7 +405,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) @@ -418,7 +418,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For specified field, it removes the expiration time @@ -431,7 +431,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it removes the expiration time @@ -444,7 +444,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For specified field, it gets the remaining time to live in milliseconds @@ -457,7 +457,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the remaining time to live in milliseconds @@ -470,7 +470,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// Returns the value associated with field in the hash stored at key. diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index f65af5e48..2ef2dd839 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -391,7 +391,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) @@ -404,7 +404,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For specified field, it removes the expiration time @@ -417,7 +417,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it removes the expiration time @@ -430,7 +430,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For specified field, it gets the remaining time to live in milliseconds @@ -443,7 +443,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the remaining time to live in milliseconds @@ -456,7 +456,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the value and sets the field's remaining time to live diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index 704f62b53..9c356cd1b 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -96,23 +96,23 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); - public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldExpireTimeAsync(ToInner(key), hashField, flags); + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldGetExpireDateTimeAsync(ToInner(key), hashField, flags); - public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashFieldExpireTimeAsync(ToInner(key), hashFields, flags); + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldGetExpireDateTimeAsync(ToInner(key), hashFields, flags); - public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => Inner.HashFieldPersistAsync(ToInner(key), hashField, flags); - public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldPersistAsync(ToInner(key), hashFields, flags); - public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldTimeToLiveAsync(ToInner(key), hashField, flags); + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldGetTimeToLiveAsync(ToInner(key), hashField, flags); - public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashFieldTimeToLiveAsync(ToInner(key), hashFields, flags); + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldGetTimeToLiveAsync(ToInner(key), hashFields, flags); public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => Inner.HashGetAndSetExpiryAsync(ToInner(key), hashFields, expireDuration, when, flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index 2ecfdaf05..94cbbe161 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -93,23 +93,23 @@ public bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); - public long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldExpireTime(ToInner(key), hashField, flags); + public long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldGetExpireDateTime(ToInner(key), hashField, flags); - public long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashFieldExpireTime(ToInner(key), hashFields, flags); + public long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldGetExpireDateTime(ToInner(key), hashFields, flags); - public long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags) => + public PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags) => Inner.HashFieldPersist(ToInner(key), hashField, flags); - public long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldPersist(ToInner(key), hashFields, flags); - public long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldTimeToLive(ToInner(key), hashField, flags); + public long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags) => + Inner.HashFieldGetTimeToLive(ToInner(key), hashField, flags); - public long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashFieldTimeToLive(ToInner(key), hashFields, flags); + public long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + Inner.HashFieldGetTimeToLive(ToInner(key), hashFields, flags); public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAll(ToInner(key), flags); diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index df6cc78a9..e455b4044 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -463,11 +463,11 @@ StackExchange.Redis.HashEntry.Key.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Name.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Value.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DC = 1 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DCF = 2 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DOF = 4 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.GETNEW = 8 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.GETOLD = 16 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DontCreate = 1 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DontCreateFields = 2 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.DontOverwriteFields = 4 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.GetNew = 8 -> StackExchange.Redis.HashFieldFlags +StackExchange.Redis.HashFieldFlags.GetOld = 16 -> StackExchange.Redis.HashFieldFlags StackExchange.Redis.HashFieldFlags.None = 0 -> StackExchange.Redis.HashFieldFlags StackExchange.Redis.HashSlotMovedEventArgs StackExchange.Redis.HashSlotMovedEventArgs.HashSlot.get -> int @@ -555,12 +555,12 @@ StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? -StackExchange.Redis.IDatabase.HashFieldExpireTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? -StackExchange.Redis.IDatabase.HashFieldExpireTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? -StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? -StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? -StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? -StackExchange.Redis.IDatabase.HashFieldTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? +StackExchange.Redis.IDatabase.HashFieldGetExpireDateTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? +StackExchange.Redis.IDatabase.HashFieldGetExpireDateTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? +StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.PersistResult? +StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.PersistResult[]? +StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? +StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HashGetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? @@ -802,12 +802,12 @@ StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.Redi StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetExpireDateTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetExpireDateTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! @@ -1271,6 +1271,10 @@ StackExchange.Redis.NameValueEntry.Value.get -> StackExchange.Redis.RedisValue StackExchange.Redis.Order StackExchange.Redis.Order.Ascending = 0 -> StackExchange.Redis.Order StackExchange.Redis.Order.Descending = 1 -> StackExchange.Redis.Order +StackExchange.Redis.PersistResult +StackExchange.Redis.PersistResult.ConditionNotMet = -1 -> StackExchange.Redis.PersistResult +StackExchange.Redis.PersistResult.NoSuchField = -2 -> StackExchange.Redis.PersistResult +StackExchange.Redis.PersistResult.Success = 1 -> StackExchange.Redis.PersistResult StackExchange.Redis.Profiling.IProfiledCommand StackExchange.Redis.Profiling.IProfiledCommand.Command.get -> string! StackExchange.Redis.Profiling.IProfiledCommand.CommandCreated.get -> System.DateTime diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 20a3c1dd3..5c7fe9ec7 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -479,62 +479,62 @@ private T HashFieldExecute(RedisCommand cmd, RedisKey key, CustomExecutor< #endregion helper stuff for HFE - public long? HashFieldExpireTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); } - public long[]? HashFieldExpireTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); } - public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); } - public Task HashFieldExpireTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); } - public long? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomExecutor>, ResultProcessor.PersistResult, flags, hashField); } - public long[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); } - public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomExecutor>, ResultProcessor.PersistResult, flags, hashField); } - public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); } - public long? HashFieldTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); } - public long[]? HashFieldTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); } - public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); } - public Task HashFieldTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); } diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index 2f54a8fff..ab56a97f2 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -69,9 +69,12 @@ public static readonly RedisValue COPY = "COPY", COUNT = "COUNT", DB = "DB", + DC = "DC", + DCF = "DCF", @default = "default", DESC = "DESC", DOCTOR = "DOCTOR", + DOF = "DOF", ENCODING = "ENCODING", EX = "EX", EXAT = "EXAT", @@ -84,6 +87,8 @@ public static readonly RedisValue GET = "GET", GETKEYS = "GETKEYS", GETNAME = "GETNAME", + GETNEW = "GETNEW", + GETOLD = "GETOLD", GT = "GT", HISTORY = "HISTORY", ID = "ID", diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index 297adf974..e9340dc01 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -72,6 +72,10 @@ public static readonly ResultProcessor public static readonly ResultProcessor ExpireResultArray = new ExpireResultArrayProcessor(); + public static readonly ResultProcessor PersistResult = new PersistResultProcessor(); + + public static readonly ResultProcessor PersistResultArray = new PersistResultArrayProcessor(); + public static readonly ResultProcessor RedisChannelArrayLiteral = new RedisChannelArrayProcessor(RedisChannel.PatternMode.Literal); @@ -911,7 +915,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (message?.Command == RedisCommand.CONFIG) { var iter = result.GetItems().GetEnumerator(); - while(iter.MoveNext()) + while (iter.MoveNext()) { ref RawResult key = ref iter.Current; if (!iter.MoveNext()) break; @@ -1513,6 +1517,53 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } + + private sealed class PersistResultProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + switch (result.Resp2TypeBulkString) + { + case ResultType.BulkString: + if (result.IsNull) + { + SetResult(message, null); + return true; + } + break; + case ResultType.Array: + var items = result.GetItems(); + if (items.Length == 1) + { // treat an array of 1 like a single reply (for example, SCRIPT EXISTS) + if (items[0].TryGetInt64(out long value)) + { + SetResult(message, (PersistResult)value); + return true; + } + } + break; + } + return false; + + } + } + + + private sealed class PersistResultArrayProcessor : ResultProcessor + { + protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) + { + if (result.Resp2TypeArray == ResultType.Array || result.IsNull) + { + var arr = result.ToArray((in RawResult x) => (PersistResult)(long)x.AsRedisValue())!; + + SetResult(message, arr); + return true; + } + return false; + } + } + private sealed class RedisChannelArrayProcessor : ResultProcessor { private readonly RedisChannel.PatternMode mode; @@ -2341,7 +2392,7 @@ internal static bool TryRead(Sequence pairs, in CommandBytes key, ref internal static bool TryRead(Sequence pairs, in CommandBytes key, ref int value) { long tmp = default; - if(TryRead(pairs, key, ref tmp)) + if (TryRead(pairs, key, ref tmp)) { value = checked((int)tmp); return true; diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index 4bb91c0bc..296623f37 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -107,7 +107,7 @@ public async void HashFieldExpireAsyncNoKey() } [Fact] - public void HashFieldExpireTimeIsDue() + public void HashFieldGetExpireDateTimeIsDue() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); @@ -177,7 +177,7 @@ public void HashFieldExpireConditionsNotSatisfied() } [Fact] - public void HashFieldExpireTime() + public void HashFieldGetExpireDateTime() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); @@ -185,10 +185,10 @@ public void HashFieldExpireTime() db.HashFieldExpire(hashKey, fields, nextCentury); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldExpireTime(hashKey, "f1"); + var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); Assert.Equal(ms, result); - var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new[] { ms, ms }, fieldsResult); } @@ -199,43 +199,43 @@ public void HashFieldExpireFieldNoExpireTime() var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpireTime(hashKey, "f1"); + var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); Assert.Equal(-1, result); - var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1, }, fieldsResult); } [Fact] - public void HashFieldExpireTimeNoKey() + public void HashFieldGetExpireDateTimeNoKey() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldExpireTime(hashKey, "f1"); + var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); Assert.Null(result); - var fieldsResult = db.HashFieldExpireTime(hashKey, fields); + var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Null(fieldsResult); } [Fact] - public void HashFieldExpireTimeNoField() + public void HashFieldGetExpireDateTimeNoField() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var result = db.HashFieldExpireTime(hashKey, "notExistingField1"); + var result = db.HashFieldGetExpireDateTime(hashKey, "notExistingField1"); Assert.Equal(-2, result); - var fieldsResult = db.HashFieldExpireTime(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); + var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new long[] { -2, -2, }, fieldsResult); } [Fact] - public void HashFieldTimeToLive() + public void HashFieldGetTimeToLive() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); @@ -243,55 +243,55 @@ public void HashFieldTimeToLive() db.HashFieldExpire(hashKey, fields, oneYearInMs); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldTimeToLive(hashKey, "f1"); + var result = db.HashFieldGetTimeToLive(hashKey, "f1"); Assert.NotNull(result); Assert.True(result > 0); - var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(fieldsResult); Assert.True(fieldsResult.Length > 0); Assert.True(fieldsResult.All(x => x > 0)); } [Fact] - public void HashFieldTimeToLiveNoExpireTime() + public void HashFieldGetTimeToLiveNoExpireTime() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldTimeToLive(hashKey, "f1"); + var result = db.HashFieldGetTimeToLive(hashKey, "f1"); Assert.Equal(-1, result); - var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); Assert.Equal(new long[] { -1, -1, }, fieldsResult); } [Fact] - public void HashFieldTimeToLiveNoKey() + public void HashFieldGetTimeToLiveNoKey() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldTimeToLive(hashKey, "f1"); + var result = db.HashFieldGetTimeToLive(hashKey, "f1"); Assert.Null(result); - var fieldsResult = db.HashFieldTimeToLive(hashKey, fields); + var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); Assert.Null(fieldsResult); } [Fact] - public void HashFieldTimeToLiveNoField() + public void HashFieldGetTimeToLiveNoField() { var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var result = db.HashFieldTimeToLive(hashKey, "notExistingField1"); + var result = db.HashFieldGetTimeToLive(hashKey, "notExistingField1"); Assert.Equal(-2, result); - var fieldsResult = db.HashFieldTimeToLive(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); + var fieldsResult = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new long[] { -2, -2, }, fieldsResult); } @@ -305,12 +305,12 @@ public void HashFieldPersist() long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); var result = db.HashFieldPersist(hashKey, "f1"); - Assert.Equal(1, result); + Assert.Equal(PersistResult.Success, result); db.HashFieldExpire(hashKey, fields, oneYearInMs); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(new long[] { 1, 1, }, fieldsResult); + Assert.Equal(new[] { PersistResult.Success, PersistResult.Success }, fieldsResult); } [Fact] @@ -321,10 +321,10 @@ public void HashFieldPersistNoExpireTime() db.HashSet(hashKey, entries); var result = db.HashFieldPersist(hashKey, "f1"); - Assert.Equal(-1, result); + Assert.Equal(PersistResult.ConditionNotMet, result); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(new long[] { -1, -1, }, fieldsResult); + Assert.Equal(new[] { PersistResult.ConditionNotMet, PersistResult.ConditionNotMet }, fieldsResult); } [Fact] @@ -349,10 +349,10 @@ public void HashFieldPersistNoField() db.HashFieldExpire(hashKey, fields, oneYearInMs); var result = db.HashFieldPersist(hashKey, "notExistingField1"); - Assert.Equal(-2, result); + Assert.Equal(PersistResult.NoSuchField, result); var fieldsResult = db.HashFieldPersist(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); - Assert.Equal(new long[] { -2, -2, }, fieldsResult); + Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); } [Fact] @@ -365,7 +365,7 @@ public void HashFieldGet() var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(ttlResults); Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); @@ -373,7 +373,7 @@ public void HashFieldGet() fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var expireDates = db.HashFieldExpireTime(hashKey, fields); + var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.Equal(new[] { ms, ms }, expireDates); @@ -381,7 +381,7 @@ public void HashFieldGet() fieldsResult = db.HashGetAndPersistFields(hashKey, fields); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); } @@ -395,7 +395,7 @@ public void HashFieldGetWithExpireConditions() var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs, ExpireWhen.HasNoExpiry); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(ttlResults); Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); @@ -403,7 +403,7 @@ public void HashFieldGetWithExpireConditions() fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury, ExpireWhen.HasNoExpiry); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var expireDates = db.HashFieldExpireTime(hashKey, fields); + var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.NotEqual(new[] { ms, ms }, expireDates); @@ -411,7 +411,7 @@ public void HashFieldGetWithExpireConditions() fieldsResult = db.HashGetAndPersistFields(hashKey, fields); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); } @@ -455,7 +455,7 @@ public void HashFieldSet() var fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("f1", 1), new HashEntry("f2", 2) }, oneYearInMs); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(ttlResults); Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); @@ -463,14 +463,14 @@ public void HashFieldSet() fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var expireDates = db.HashFieldExpireTime(hashKey, fields); + var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.Equal(new[] { ms, ms }, expireDates); fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); } @@ -513,7 +513,7 @@ public void HashFieldSetWithExpireConditions() var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(ttlResults); Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); @@ -521,14 +521,14 @@ public void HashFieldSetWithExpireConditions() fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury, ExpireWhen.HasNoExpiry); Assert.Equal(new RedisValue[] { 1, 1, }, fieldsResult); - var expireDates = db.HashFieldExpireTime(hashKey, fields); + var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.NotEqual(new[] { ms, ms }, expireDates); fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); } @@ -539,32 +539,32 @@ public void HashFieldSetWithFlags() var hashKey = Me(); db.KeyDelete(hashKey); - var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DC); + var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontCreate); Assert.Null(fieldsResult); - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DCF); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontCreateFields); Assert.Null(fieldsResult); - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DOF); + fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontOverwriteFields); Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - var ttlResults = db.HashFieldTimeToLive(hashKey, fields); + var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(ttlResults); Assert.True(ttlResults.Length > 0); Assert.True(ttlResults.All(x => x > 0)); - fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GETOLD); + fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GetOld); Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - var expireDates = db.HashFieldExpireTime(hashKey, fields); + var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); Assert.NotEqual(new[] { ms, ms }, expireDates); - fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GETNEW); + fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GetNew); Assert.Equal(new RedisValue[] { "x", "y" }, fieldsResult); - var fieldsNoExpireDates = db.HashFieldExpireTime(hashKey, fields); + var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); } } From 8cb0c69d5517842d7cfb7fcf8f88dccd61b052ba Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 24 May 2024 10:14:23 +0300 Subject: [PATCH 06/13] pruning HSET and HGETF --- src/StackExchange.Redis/Enums/RedisCommand.cs | 4 - .../Interfaces/IDatabase.cs | 114 ---------- .../Interfaces/IDatabaseAsync.cs | 114 ---------- .../KeyspaceIsolation/KeyPrefixed.cs | 18 -- .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 18 -- .../PublicAPI/PublicAPI.Shipped.txt | 12 - src/StackExchange.Redis/RedisDatabase.cs | 129 ----------- .../HashFieldTests.cs | 213 ------------------ 8 files changed, 622 deletions(-) diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs index 1d228e36c..a4647d7eb 100644 --- a/src/StackExchange.Redis/Enums/RedisCommand.cs +++ b/src/StackExchange.Redis/Enums/RedisCommand.cs @@ -71,7 +71,6 @@ internal enum RedisCommand HEXPIRETIME, HGET, HGETALL, - HGETF, HINCRBY, HINCRBYFLOAT, HKEYS, @@ -86,7 +85,6 @@ internal enum RedisCommand HRANDFIELD, HSCAN, HSET, - HSETF, HSETNX, HSTRLEN, HVALS, @@ -291,7 +289,6 @@ internal static bool IsPrimaryOnly(this RedisCommand command) case RedisCommand.HDEL: case RedisCommand.HEXPIRE: case RedisCommand.HEXPIREAT: - case RedisCommand.HGETF: case RedisCommand.HINCRBY: case RedisCommand.HINCRBYFLOAT: case RedisCommand.HMSET: @@ -299,7 +296,6 @@ internal static bool IsPrimaryOnly(this RedisCommand command) case RedisCommand.HPEXPIRE: case RedisCommand.HPEXPIREAT: case RedisCommand.HSET: - case RedisCommand.HSETF: case RedisCommand.HSETNX: case RedisCommand.INCR: case RedisCommand.INCRBY: diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index 9ad2a9d6e..ae3c41f20 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -504,120 +504,6 @@ public interface IDatabase : IRedis, IDatabaseAsync /// RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - /// - /// For each specified field, it gets the value and sets the field's remaining time to live - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The time out to set in milliseconds - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it gets the value and sets the field's expiration timestamp - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it gets the value and removes the field's expiration - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// Whether to maintain the existing expiration. - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The time out to set in milliseconds - /// under which condition the expiration will be set using . - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - /// /// Returns all fields and values of the hash stored at key. /// diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index 2ef2dd839..0e8e96d5c 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -458,120 +458,6 @@ public interface IDatabaseAsync : IRedisAsync /// Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - /// - /// For each specified field, it gets the value and sets the field's remaining time to live - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The time out to set in milliseconds - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it gets the value and sets the field's expiration timestamp - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it gets the value and removes the field's expiration - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// value: value of field - /// nil: if no such field exists - /// - Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// Whether to maintain the existing expiration. - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The time out to set in milliseconds - /// under which condition the expiration will be set using . - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - - /// - /// For each specified field, it sets the value and optionally sets the fields expiration - /// Depending on HashFieldFlags it creates the hash key or its fields in case they dont exist - /// - When DC is not specified: if key does not exist: create key - /// - When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - When neither DCF nor DOF are specified: for each specified field: if such field does not exist: create field; set all fields' value and expiration time - /// - When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - /// The key of the hash. - /// The fields in the hash for this operation. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields - /// return value depends on the HashFieldFlags (GETNEW/GETOLD) - /// if GETNEW is specified: the value of field after command execution - /// if GETOLD is specified: the value of field before command execution - /// if GETNEW or GETOLD is not specified: a + b where - /// a: 1 if the field's value was set or 0 if not (DCF/DOF met) - /// b: 2 if the field's expiration time was set/discarded or 0 if not (DCF/DOF met, NX/XX/GT/LT not met) - /// - Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None); - /// /// Returns the value associated with field in the hash stored at key. /// diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index 9c356cd1b..1e517ce71 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -114,24 +114,6 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldGetTimeToLiveAsync(ToInner(key), hashFields, flags); - public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAndSetExpiryAsync(ToInner(key), hashFields, expireDuration, when, flags); - - public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAndSetExpiryAsync(ToInner(key), hashFields, expireTime, when, flags); - - public Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashGetAndPersistFieldsAsync(ToInner(key), hashFields, flags); - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiryAsync(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); - public Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.HashGetAllAsync(ToInner(key), flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index 94cbbe161..06059581c 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -120,24 +120,6 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGet(ToInner(key), hashField, flags); - public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAndSetExpiry(ToInner(key), hashFields, expireDuration, when, flags); - - public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when, CommandFlags flags) => - Inner.HashGetAndSetExpiry(ToInner(key), hashFields, expireTime, when, flags); - - public RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => - Inner.HashGetAndPersistFields(ToInner(key), hashFields, flags); - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiry(ToInner(key), hashFields, keepExpiry, fieldFlags, flags); - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiry(ToInner(key), hashFields, expireDuration, when, fieldFlags, flags); - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when, HashFieldFlags fieldFlags, CommandFlags flags) => - Inner.HashSetAndSetExpiry(ToInner(key), hashFields, expireTime, when, fieldFlags, flags); - public Lease? HashGetLease(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashGetLease(ToInner(key), hashField, flags); diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index e455b4044..716721270 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -563,9 +563,6 @@ StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKe StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! -StackExchange.Redis.IDatabase.HashGetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashGetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashGetAndPersistFields(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashGetAll(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.HashEntry[]! StackExchange.Redis.IDatabase.HashGetLease(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.Lease? StackExchange.Redis.IDatabase.HashIncrement(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> double @@ -579,9 +576,6 @@ StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackEx StackExchange.Redis.IDatabase.HashScan(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern, int pageSize, StackExchange.Redis.CommandFlags flags) -> System.Collections.Generic.IEnumerable! StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> void StackExchange.Redis.IDatabase.HashSet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool -StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? -StackExchange.Redis.IDatabase.HashSetAndSetExpiry(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]? StackExchange.Redis.IDatabase.HashStringLength(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.HashValues(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HyperLogLogAdd(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool @@ -811,10 +805,7 @@ StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Red StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashGetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashGetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetLeaseAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task?>! -StackExchange.Redis.IDatabaseAsync.HashGetAndPersistFieldsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, double value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashIncrementAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, long value = 1, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashKeysAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! @@ -825,9 +816,6 @@ StackExchange.Redis.IDatabaseAsync.HashRandomFieldsWithValuesAsync(StackExchange StackExchange.Redis.IDatabaseAsync.HashScanAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pattern = default(StackExchange.Redis.RedisValue), int pageSize = 250, long cursor = 0, int pageOffset = 0, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Collections.Generic.IAsyncEnumerable! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashSetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, bool keepExpiry, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.DateTime expireTime, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashSetAndSetExpiryAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.HashEntry[]! hashFields, System.TimeSpan expireDuration, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.HashFieldFlags fieldFlags = StackExchange.Redis.HashFieldFlags.None, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashStringLengthAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashValuesAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HyperLogLogAddAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 5c7fe9ec7..d33b950f8 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -559,135 +559,6 @@ public RedisValue[] HashGet(RedisKey key, RedisValue[] hashFields, CommandFlags return ExecuteSync(msg, ResultProcessor.RedisValueArray, defaultValue: Array.Empty()); } - public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetAndSetExpiration(key, args, hashFields, flags); - } - - public RedisValue[]? HashGetAndSetExpiry(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetAndSetExpiration(key, args, hashFields, flags); - } - - public RedisValue[]? HashGetAndPersistFields(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PERSIST, }; - return HashGetAndSetExpiration(key, args, hashFields, flags); - } - - private RedisValue[]? HashGetAndSetExpiration(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) - { - if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); - args.Add(RedisLiterals.FIELDS); - args.Add(hashFields.Length); - args.AddRange(hashFields); - var msg = Message.Create(Database, flags, RedisCommand.HGETF, key, args.ToArray()); - return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); - } - - public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PX, expireDuration.Ticks / TimeSpan.TicksPerMillisecond }; - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetSetExpirationAsync(key, args, hashFields, flags); - } - - public Task HashGetAndSetExpiryAsync(RedisKey key, RedisValue[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PXAT, GetMillisecondsUntil(expireTime) }; - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - return HashGetSetExpirationAsync(key, args, hashFields, flags); - } - - public Task HashGetAndPersistFieldsAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) - { - List args = new() { RedisLiterals.PERSIST, }; - return HashGetSetExpirationAsync(key, args, hashFields, flags); - } - - private Task HashGetSetExpirationAsync(RedisKey key, List args, RedisValue[] hashFields, CommandFlags flags) - { - if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); - args.Add(RedisLiterals.FIELDS); - args.Add(hashFields.Length); - args.AddRange(hashFields); - var msg = Message.Create(Database, flags, RedisCommand.HGETF, key, args.ToArray()); - return ExecuteAsync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); - } - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); - return HashSetAndSetExpiration(key, args, hashFields, flags); - } - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - args.Add(RedisLiterals.PX); - args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); - return HashSetAndSetExpiration(key, args, hashFields, flags); - } - - public RedisValue[]? HashSetAndSetExpiry(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - args.Add(RedisLiterals.PXAT); - args.Add(GetMillisecondsUntil(expireTime)); - return HashSetAndSetExpiration(key, args, hashFields, flags); - } - - private RedisValue[]? HashSetAndSetExpiration(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) - { - if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); - args.Add(RedisLiterals.FVS); - args.Add(hashFields.Length); - args.AddRange(hashFields.SelectMany(e => new[] { e.Name, e.Value }).ToList()); - var msg = Message.Create(Database, flags, RedisCommand.HSETF, key, args.ToArray()); - return ExecuteSync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); - } - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, bool keepExpiry, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (keepExpiry) args.Add(RedisLiterals.KEEPTTL); - return HashSetAndSetExpirationAsync(key, args, hashFields, flags); - } - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, TimeSpan expireDuration, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - args.Add(RedisLiterals.PX); - args.Add(expireDuration.Ticks / TimeSpan.TicksPerMillisecond); - return HashSetAndSetExpirationAsync(key, args, hashFields, flags); - } - - public Task HashSetAndSetExpiryAsync(RedisKey key, HashEntry[] hashFields, DateTime expireTime, ExpireWhen when = ExpireWhen.Always, HashFieldFlags fieldFlags = HashFieldFlags.None, CommandFlags flags = CommandFlags.None) - { - var args = fieldFlags.ToRedisValueList(); - if (when != ExpireWhen.Always) args.Add(when.ToLiteral()); - args.Add(RedisLiterals.PXAT); - args.Add(GetMillisecondsUntil(expireTime)); - return HashSetAndSetExpirationAsync(key, args, hashFields, flags); - } - - private Task HashSetAndSetExpirationAsync(RedisKey key, List args, HashEntry[] hashFields, CommandFlags flags) - { - if (hashFields == null || hashFields.Length == 0) throw new ArgumentNullException(nameof(hashFields)); - args.Add(RedisLiterals.FVS); - args.Add(hashFields.Length); - args.AddRange(hashFields.SelectMany(e => new[] { e.Name, e.Value }).ToList()); - var msg = Message.Create(Database, flags, RedisCommand.HSETF, key, args.ToArray()); - return ExecuteAsync(msg, ResultProcessor.NullableRedisValueArray, defaultValue: null); - } public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) { var msg = Message.Create(Database, flags, RedisCommand.HGETALL, key); diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index 296623f37..33931aef3 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -354,217 +354,4 @@ public void HashFieldPersistNoField() var fieldsResult = db.HashFieldPersist(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); } - - [Fact] - public void HashFieldGet() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.HashSet(hashKey, entries); - - var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.NotNull(ttlResults); - Assert.True(ttlResults.Length > 0); - Assert.True(ttlResults.All(x => x > 0)); - - fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - Assert.Equal(new[] { ms, ms }, expireDates); - - - fieldsResult = db.HashGetAndPersistFields(hashKey, fields); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); - } - - [Fact] - public void HashFieldGetWithExpireConditions() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.HashSet(hashKey, entries); - - var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.NotNull(ttlResults); - Assert.True(ttlResults.Length > 0); - Assert.True(ttlResults.All(x => x > 0)); - - fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury, ExpireWhen.HasNoExpiry); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - Assert.NotEqual(new[] { ms, ms }, expireDates); - - - fieldsResult = db.HashGetAndPersistFields(hashKey, fields); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); - } - - [Fact] - public void HashFieldGetNoKey() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - - var fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, oneYearInMs); - Assert.Null(fieldsResult); - - fieldsResult = db.HashGetAndSetExpiry(hashKey, fields, nextCentury); - Assert.Null(fieldsResult); - } - - [Fact] - public void HashFieldGetNoField() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.HashSet(hashKey, entries); - db.HashFieldExpire(hashKey, fields, oneYearInMs); - - var fieldsResult = db.HashGetAndSetExpiry(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, oneYearInMs); - Assert.NotNull(fieldsResult); - Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); - - fieldsResult = db.HashGetAndSetExpiry(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }, nextCentury); - Assert.NotNull(fieldsResult); - Assert.Equal(new RedisValue[] { RedisValue.Null, RedisValue.Null }, fieldsResult); - } - - [Fact] - public void HashFieldSet() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.HashSet(hashKey, entries); - - var fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("f1", 1), new HashEntry("f2", 2) }, oneYearInMs); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.NotNull(ttlResults); - Assert.True(ttlResults.Length > 0); - Assert.True(ttlResults.All(x => x > 0)); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - Assert.Equal(new[] { ms, ms }, expireDates); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); - } - - [Fact] - public void HashFieldSetNoKey() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - - var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - } - - [Fact] - public void HashFieldSetNoField() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.HashSet(hashKey, entries); - db.HashFieldExpire(hashKey, fields, oneYearInMs); - - var fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, oneYearInMs); - Assert.NotNull(fieldsResult); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, new[] { new HashEntry("notExistingField1", 1), new HashEntry("notExistingField2", 2) }, nextCentury); - Assert.NotNull(fieldsResult); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - } - - [Fact] - public void HashFieldSetWithExpireConditions() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - - var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.NotNull(ttlResults); - Assert.True(ttlResults.Length > 0); - Assert.True(ttlResults.All(x => x > 0)); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, nextCentury, ExpireWhen.HasNoExpiry); - Assert.Equal(new RedisValue[] { 1, 1, }, fieldsResult); - - var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - Assert.NotEqual(new[] { ms, ms }, expireDates); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, false); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); - } - - [Fact] - public void HashFieldSetWithFlags() - { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); - var hashKey = Me(); - db.KeyDelete(hashKey); - - var fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontCreate); - Assert.Null(fieldsResult); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontCreateFields); - Assert.Null(fieldsResult); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, entries, oneYearInMs, ExpireWhen.HasNoExpiry, HashFieldFlags.DontOverwriteFields); - Assert.Equal(new RedisValue[] { 3, 3 }, fieldsResult); - - var ttlResults = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.NotNull(ttlResults); - Assert.True(ttlResults.Length > 0); - Assert.True(ttlResults.All(x => x > 0)); - - fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "a"), new("f2", "b") }, nextCentury, ExpireWhen.HasNoExpiry, HashFieldFlags.GetOld); - Assert.Equal(entries.Select(i => i.Value).ToArray(), fieldsResult); - - var expireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - Assert.NotEqual(new[] { ms, ms }, expireDates); - - - fieldsResult = db.HashSetAndSetExpiry(hashKey, new HashEntry[] { new("f1", "x"), new("f2", "y") }, false, HashFieldFlags.GetNew); - Assert.Equal(new RedisValue[] { "x", "y" }, fieldsResult); - - var fieldsNoExpireDates = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1 }, fieldsNoExpireDates); - } } From f312d6ed7677784d36e1cfa0345c913a18e20fbf Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 31 May 2024 09:16:50 +0300 Subject: [PATCH 07/13] remove single field methods and convert to empty array responses --- .../Interfaces/IDatabase.cs | 84 +-------- .../Interfaces/IDatabaseAsync.cs | 83 +-------- .../KeyspaceIsolation/KeyPrefixed.cs | 25 +-- .../KeyspaceIsolation/KeyPrefixedDatabase.cs | 25 +-- .../PublicAPI/PublicAPI.Shipped.txt | 32 ++-- src/StackExchange.Redis/RedisDatabase.cs | 103 +++--------- src/StackExchange.Redis/RedisFeatures.cs | 4 +- src/StackExchange.Redis/ResultProcessor.cs | 118 +------------ .../HashFieldTests.cs | 159 ++++++------------ 9 files changed, 117 insertions(+), 516 deletions(-) diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index ae3c41f20..cf43d6083 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -325,24 +325,6 @@ public interface IDatabase : IRedis, IDatabaseAsync /// bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - - /// - /// Set the remaining time to live in milliseconds for a field of hash - /// After the timeout has expired, the field of the hash will automatically be deleted. - /// - /// The key of the hash. - /// The field in the hash to set expire time. - /// The timeout to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field; - /// 2: field deleted because the specified expiration time is due - /// 1: expiration time set/updated - /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) - /// -2 : no such field - /// - ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - /// /// Set the remaining time to live in milliseconds for the given set of fields of hash /// After the timeout has expired, the field of the hash will automatically be deleted. @@ -358,24 +340,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) /// -2 : no such field /// - ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// Set the time out on a field of hash - /// After the timeout has expired, the field of the hash will automatically be deleted. - /// - /// The key of the hash. - /// The field in the hash to set expire time. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field; - /// 2: field deleted because the specified expiration time is due - /// 1: expiration time set/updated - /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) - /// -2 : no such field - /// - ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// Set the time out on a field of the given set of fields of hash @@ -392,20 +357,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) /// -2 : no such field /// - ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) - /// - /// The key of the hash. - /// The field in the hash to get expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// expiration time: as a UNIX timestamp in milliseconds - /// -1: if field has no associated expiration time - /// -2: no such field - /// - long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) @@ -418,20 +370,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it removes the expiration time - /// - /// The key of the hash. - /// The field in the hash to remove expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// 1: if the expiration time was removed - /// -1: if field has no associated expiration time - /// -2: no such field - /// - PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + long[] HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it removes the expiration time @@ -444,20 +383,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it gets the remaining time to live in milliseconds - /// - /// The key of the hash. - /// The field in the hash to get expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// time to live: in milliseconds - /// -1: if field has no associated expiration time - /// -2: no such field - /// - long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + PersistResult[] HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the remaining time to live in milliseconds @@ -470,7 +396,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// -1: if field has no associated expiration time /// -2: no such field /// - long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + long[] HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// Returns the value associated with field in the hash stored at key. diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index 0e8e96d5c..2b258d61a 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -312,23 +312,6 @@ public interface IDatabaseAsync : IRedisAsync /// Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); - /// - /// Set the remaining time to live in milliseconds for a field of hash - /// After the timeout has expired, the field of the hash will automatically be deleted. - /// - /// The key of the hash. - /// The field in the hash to set expire time. - /// The timeout to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field; - /// 2: field deleted because the specified expiration time is due - /// 1: expiration time set/updated - /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) - /// -2 : no such field - /// - Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - /// /// Set the remaining time to live in milliseconds for the given set of fields of hash /// After the timeout has expired, the field of the hash will automatically be deleted. @@ -344,24 +327,7 @@ public interface IDatabaseAsync : IRedisAsync /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) /// -2 : no such field /// - Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// Set the time out on a field of hash - /// After the timeout has expired, the field of the hash will automatically be deleted. - /// - /// The key of the hash. - /// The field in the hash to set expire time. - /// The exact date to expiry to set. - /// under which condition the expiration will be set using . - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field; - /// 2: field deleted because the specified expiration time is due - /// 1: expiration time set/updated - /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) - /// -2 : no such field - /// - Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); + Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// Set the time out on a field of the given set of fields of hash @@ -378,20 +344,7 @@ public interface IDatabaseAsync : IRedisAsync /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) /// -2 : no such field /// - Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) - /// - /// The key of the hash. - /// The field in the hash to get expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// expiration time: as a UNIX timestamp in milliseconds - /// -1: if field has no associated expiration time - /// -2: no such field - /// - Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the expiration time as a Unix timestamp in milliseconds (milliseconds since the Unix epoch) @@ -404,20 +357,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it removes the expiration time - /// - /// The key of the hash. - /// The field in the hash to remove expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// 1: if the expiration time was removed - /// -1: if field has no associated expiration time - /// -2: no such field - /// - Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it removes the expiration time @@ -430,20 +370,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); - - /// - /// For specified field, it gets the remaining time to live in milliseconds - /// - /// The key of the hash. - /// The field in the hash to get expire time. - /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given field - /// time to live: in milliseconds - /// -1: if field has no associated expiration time - /// -2: no such field - /// - Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None); + Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// For each specified field, it gets the remaining time to live in milliseconds @@ -456,7 +383,7 @@ public interface IDatabaseAsync : IRedisAsync /// -1: if field has no associated expiration time /// -2: no such field /// - Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); + Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None); /// /// Returns the value associated with field in the hash stored at key. diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs index 1e517ce71..66f1008ac 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixed.cs @@ -84,34 +84,19 @@ public Task HashDeleteAsync(RedisKey key, RedisValue hashField, CommandFla public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashExistsAsync(ToInner(key), hashField, flags); - public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => - Inner.HashFieldExpireAsync(ToInner(key), hashField, expiry, when, flags); - - public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); - public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => - Inner.HashFieldExpireAsync(ToInner(key), hashField, expiry, when, flags); - - public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpireAsync(ToInner(key), hashFields, expiry, when, flags); - public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldGetExpireDateTimeAsync(ToInner(key), hashField, flags); - - public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldGetExpireDateTimeAsync(ToInner(key), hashFields, flags); - public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldPersistAsync(ToInner(key), hashField, flags); - - public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldPersistAsync(ToInner(key), hashFields, flags); - public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldGetTimeToLiveAsync(ToInner(key), hashField, flags); - - public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldGetTimeToLiveAsync(ToInner(key), hashFields, flags); public Task HashGetAllAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => diff --git a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs index 06059581c..378ccff60 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/KeyPrefixedDatabase.cs @@ -81,34 +81,19 @@ public bool HashDelete(RedisKey key, RedisValue hashField, CommandFlags flags = public bool HashExists(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) => Inner.HashExists(ToInner(key), hashField, flags); - public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => - Inner.HashFieldExpire(ToInner(key), hashField, expiry, when, flags); - - public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + public ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); - public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => - Inner.HashFieldExpire(ToInner(key), hashField, expiry, when, flags); - - public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => + public ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) => Inner.HashFieldExpire(ToInner(key), hashFields, expiry, when, flags); - public long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldGetExpireDateTime(ToInner(key), hashField, flags); - - public long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public long[] HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldGetExpireDateTime(ToInner(key), hashFields, flags); - public PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldPersist(ToInner(key), hashField, flags); - - public PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public PersistResult[] HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldPersist(ToInner(key), hashFields, flags); - public long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags) => - Inner.HashFieldGetTimeToLive(ToInner(key), hashField, flags); - - public long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => + public long[] HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags) => Inner.HashFieldGetTimeToLive(ToInner(key), hashFields, flags); public HashEntry[] HashGetAll(RedisKey key, CommandFlags flags = CommandFlags.None) => diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index 716721270..b9d5bc286 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -551,16 +551,11 @@ StackExchange.Redis.IDatabase.HashDecrement(StackExchange.Redis.RedisKey key, St StackExchange.Redis.IDatabase.HashDelete(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool StackExchange.Redis.IDatabase.HashDelete(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.HashExists(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool -StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? -StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult? -StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? -StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]? -StackExchange.Redis.IDatabase.HashFieldGetExpireDateTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? -StackExchange.Redis.IDatabase.HashFieldGetExpireDateTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? -StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.PersistResult? -StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.PersistResult[]? -StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long? -StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]? +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]! +StackExchange.Redis.IDatabase.HashFieldExpire(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.ExpireResult[]! +StackExchange.Redis.IDatabase.HashFieldGetExpireDateTime(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]! +StackExchange.Redis.IDatabase.HashFieldGetTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long[]! +StackExchange.Redis.IDatabase.HashFieldPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.PersistResult[]! StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.HashGet(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.HashGetAll(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.HashEntry[]! @@ -792,16 +787,13 @@ StackExchange.Redis.IDatabaseAsync.HashDecrementAsync(StackExchange.Redis.RedisK StackExchange.Redis.IDatabaseAsync.HashDeleteAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashDeleteAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashExistsAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldGetExpireDateTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldGetExpireDateTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! -StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! + +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.DateTime expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldExpireAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, System.TimeSpan expiry, StackExchange.Redis.ExpireWhen when = StackExchange.Redis.ExpireWhen.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetExpireDateTimeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldGetTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.HashFieldPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! + StackExchange.Redis.IDatabaseAsync.HashGetAllAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue hashField, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.HashGetAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue[]! hashFields, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index d33b950f8..ba28f8ea5 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -388,52 +388,28 @@ public Task HashExistsAsync(RedisKey key, RedisValue hashField, CommandFla return ExecuteAsync(msg, ResultProcessor.Boolean); } - public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } - public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); - } - - public ExpireResult? HashFieldExpire(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); - } - - public ExpireResult[]? HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public ExpireResult[] HashFieldExpire(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, SyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } - public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } - public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, TimeSpan expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - long milliseconds = expiry.Ticks / TimeSpan.TicksPerMillisecond; - return HashFieldExpireExecute(key, milliseconds, when, PickExpireCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); - } - - public Task HashFieldExpireAsync(RedisKey key, RedisValue hashField, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) + public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) { long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncCustomExecutor>, ResultProcessor.ExpireResult, flags, hashField); - } - - public Task HashFieldExpireAsync(RedisKey key, RedisValue[] hashFields, DateTime expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None) - { - long milliseconds = GetMillisecondsUntil(expiry); - return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); + return HashFieldExpireExecute(key, milliseconds, when, PickExpireAtCommandByPrecision, AsyncCustomArrExecutor>, ResultProcessor.ExpireResultArray, flags, hashFields); } #region private for HFE @@ -468,75 +444,40 @@ private T HashFieldExecute(RedisCommand cmd, RedisKey key, CustomExecutor< private delegate T CustomExecutor(Message msg, P processor); + private T[] SyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteSync(msg, processor)!; } - private T? SyncCustomExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteSync(msg, processor); } - - private T[]? SyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteSync(msg, processor); } - - private Task AsyncCustomExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteAsync(msg, processor); } - - private Task AsyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteAsync(msg, processor); } + private Task AsyncCustomArrExecutor(Message msg, P processor) where P : ResultProcessor { return ExecuteAsync(msg, processor)!; } #endregion helper stuff for HFE - public long? HashFieldGetExpireDateTime(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); - } - - public long[]? HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); - } - - public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); - } - - public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); - } - - public PersistResult? HashFieldPersist(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomExecutor>, ResultProcessor.PersistResult, flags, hashField); - } - - public PersistResult[]? HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) - { - return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); - } - - public Task HashFieldPersistAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public long[] HashFieldGetExpireDateTime(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomExecutor>, ResultProcessor.PersistResult, flags, hashField); + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, SyncCustomArrExecutor>, ResultProcessor.Int64Array, flags, hashFields); } - public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetExpireDateTimeAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); + return HashFieldExecute(RedisCommand.HPEXPIRETIME, key, AsyncCustomArrExecutor>, ResultProcessor.Int64Array, flags, hashFields); } - public long? HashFieldGetTimeToLive(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public PersistResult[] HashFieldPersist(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + return HashFieldExecute(RedisCommand.HPERSIST, key, SyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); } - public long[]? HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldPersistAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + return HashFieldExecute(RedisCommand.HPERSIST, key, AsyncCustomArrExecutor>, ResultProcessor.PersistResultArray, flags, hashFields); } - public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) + public long[] HashFieldGetTimeToLive(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomExecutor>, ResultProcessor.NullableInt64, flags, hashField); + return HashFieldExecute(RedisCommand.HPTTL, key, SyncCustomArrExecutor>, ResultProcessor.Int64Array, flags, hashFields); } - public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) + public Task HashFieldGetTimeToLiveAsync(RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None) { - return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomArrExecutor>, ResultProcessor.Int64NullableArray, flags, hashFields); + return HashFieldExecute(RedisCommand.HPTTL, key, AsyncCustomArrExecutor>, ResultProcessor.Int64Array, flags, hashFields); } public RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None) diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs index 7e3bb77dc..6e918504c 100644 --- a/src/StackExchange.Redis/RedisFeatures.cs +++ b/src/StackExchange.Redis/RedisFeatures.cs @@ -40,7 +40,9 @@ namespace StackExchange.Redis v6_0_6 = new Version(6, 0, 6), v6_2_0 = new Version(6, 2, 0), v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240 - v7_2_0_rc1 = new Version(7, 1, 240); // 7.2 RC1 is version 7.1.240 + v7_2_0_rc1 = new Version(7, 1, 240), // 7.2 RC1 is version 7.1.240 + v7_4_0_rc1 = new Version(7, 4, 240); // 7.2 RC1 is version 7.4.240 + private readonly Version version; diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index e9340dc01..70dc810fa 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -68,13 +68,9 @@ public static readonly ResultProcessor public static readonly ResultProcessor NullableInt64 = new NullableInt64Processor(); - public static readonly ResultProcessor ExpireResult = new ExpireResultProcessor(); + public static readonly ResultProcessor ExpireResultArray = new ExpireResultArrayProcessor(); - public static readonly ResultProcessor ExpireResultArray = new ExpireResultArrayProcessor(); - - public static readonly ResultProcessor PersistResult = new PersistResultProcessor(); - - public static readonly ResultProcessor PersistResultArray = new PersistResultArrayProcessor(); + public static readonly ResultProcessor PersistResultArray = new PersistResultArrayProcessor(); public static readonly ResultProcessor RedisChannelArrayLiteral = new RedisChannelArrayProcessor(RedisChannel.PatternMode.Literal); @@ -98,15 +94,9 @@ public static readonly ResultProcessor RedisValueArray = new RedisValueArrayProcessor(); - public static readonly ResultProcessor - NullableRedisValueArray = new NullableRedisValueArrayProcessor(); - public static readonly ResultProcessor Int64Array = new Int64ArrayProcessor(); - public static readonly ResultProcessor - Int64NullableArray = new Int64NullableArrayProcessor(); - public static readonly ResultProcessor NullableStringArray = new NullableStringArrayProcessor(); @@ -1471,38 +1461,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } - private sealed class ExpireResultProcessor : ResultProcessor - { - protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) - { - switch (result.Resp2TypeBulkString) - { - case ResultType.BulkString: - if (result.IsNull) - { - SetResult(message, null); - return true; - } - break; - case ResultType.Array: - var items = result.GetItems(); - if (items.Length == 1) - { // treat an array of 1 like a single reply (for example, SCRIPT EXISTS) - if (items[0].TryGetInt64(out long value)) - { - SetResult(message, (ExpireResult)value); - return true; - } - } - break; - } - return false; - - } - } - - - private sealed class ExpireResultArrayProcessor : ResultProcessor + private sealed class ExpireResultArrayProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { @@ -1517,39 +1476,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } - - private sealed class PersistResultProcessor : ResultProcessor - { - protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) - { - switch (result.Resp2TypeBulkString) - { - case ResultType.BulkString: - if (result.IsNull) - { - SetResult(message, null); - return true; - } - break; - case ResultType.Array: - var items = result.GetItems(); - if (items.Length == 1) - { // treat an array of 1 like a single reply (for example, SCRIPT EXISTS) - if (items[0].TryGetInt64(out long value)) - { - SetResult(message, (PersistResult)value); - return true; - } - } - break; - } - return false; - - } - } - - - private sealed class PersistResultArrayProcessor : ResultProcessor + private sealed class PersistResultArrayProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) { @@ -1671,28 +1598,6 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } - private sealed class NullableRedisValueArrayProcessor : ResultProcessor - { - protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) - { - switch (result.Resp2TypeBulkString) - { - // allow a single item to pass explicitly pretending to be an array - case ResultType.BulkString: - // If the result is nil, the result should be an empty array - var arr = result.IsNull - ? null - : new[] { result.AsRedisValue() }; - SetResult(message, arr); - return true; - case ResultType.Array: - arr = result.GetItemsAsValues()!; - SetResult(message, arr); - return true; - } - return false; - } - } private sealed class Int64ArrayProcessor : ResultProcessor { @@ -1709,21 +1614,6 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes } } - private sealed class Int64NullableArrayProcessor : ResultProcessor - { - protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) - { - if (result.Resp2TypeArray == ResultType.Array || result.IsNull) - { - var arr = result.ToArray((in RawResult x) => (long)x.AsRedisValue())!; - SetResult(message, arr); - return true; - } - - return false; - } - } - private sealed class NullableStringArrayProcessor : ResultProcessor { protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result) diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index 33931aef3..a25e352bf 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -31,16 +31,10 @@ public HashFieldTests(ITestOutputHelper output, SharedConnectionFixture fixture) [Fact] public void HashFieldExpire() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs); - Assert.Equal(ExpireResult.Success, result); - - result = db.HashFieldExpire(hashKey, "f1", nextCentury); - Assert.Equal(ExpireResult.Success, result); - var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); @@ -51,35 +45,23 @@ public void HashFieldExpire() [Fact] public void HashFieldExpireNoKey() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs); - Assert.Null(result); - - result = db.HashFieldExpire(hashKey, "f1", nextCentury); - Assert.Null(result); - var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); } [Fact] public async void HashFieldExpireAsync() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = await db.HashFieldExpireAsync(hashKey, "f1", oneYearInMs); - Assert.Equal(ExpireResult.Success, result); - - result = await db.HashFieldExpireAsync(hashKey, "f1", nextCentury); - Assert.Equal(ExpireResult.Success, result); - var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); @@ -90,48 +72,42 @@ public async void HashFieldExpireAsync() [Fact] public async void HashFieldExpireAsyncNoKey() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); - var result = await db.HashFieldExpireAsync(hashKey, "f1", oneYearInMs); - Assert.Null(result); - - result = await db.HashFieldExpireAsync(hashKey, "f1", nextCentury); - Assert.Null(result); - var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); } [Fact] public void HashFieldGetExpireDateTimeIsDue() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpire(hashKey, "f1", new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); - Assert.Equal(ExpireResult.Due, result); + var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal(new[] { ExpireResult.Due }, result); } [Fact] public void HashFieldExpireNoField() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpire(hashKey, "nonExistingField", oneYearInMs); - Assert.Equal(ExpireResult.NoSuchField, result); + var result = db.HashFieldExpire(hashKey, new RedisValue[] { "nonExistingField" }, oneYearInMs); + Assert.Equal(new[] { ExpireResult.NoSuchField }, result); } [Fact] public void HashFieldExpireConditionsSatisfied() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.KeyDelete(hashKey); db.HashSet(hashKey, entries); @@ -139,23 +115,23 @@ public void HashFieldExpireConditionsSatisfied() var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); - var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(ExpireResult.Success, result); + var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(new[] { ExpireResult.Success }, result); - result = db.HashFieldExpire(hashKey, "f2", oneYearInMs, ExpireWhen.HasExpiry); - Assert.Equal(ExpireResult.Success, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f2" }, oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal(new[] { ExpireResult.Success }, result); - result = db.HashFieldExpire(hashKey, "f3", nextCentury, ExpireWhen.GreaterThanCurrentExpiry); - Assert.Equal(ExpireResult.Success, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f3" }, nextCentury, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal(new[] { ExpireResult.Success }, result); - result = db.HashFieldExpire(hashKey, "f4", oneYearInMs, ExpireWhen.LessThanCurrentExpiry); - Assert.Equal(ExpireResult.Success, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f4" }, oneYearInMs, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal(new[] { ExpireResult.Success }, result); } [Fact] public void HashFieldExpireConditionsNotSatisfied() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.KeyDelete(hashKey); db.HashSet(hashKey, entries); @@ -163,30 +139,30 @@ public void HashFieldExpireConditionsNotSatisfied() var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); - var result = db.HashFieldExpire(hashKey, "f1", oneYearInMs, ExpireWhen.HasExpiry); - Assert.Equal(ExpireResult.ConditionNotMet, result); + var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); - result = db.HashFieldExpire(hashKey, "f2", oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(ExpireResult.ConditionNotMet, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f2" }, oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); - result = db.HashFieldExpire(hashKey, "f3", nextCentury, ExpireWhen.LessThanCurrentExpiry); - Assert.Equal(ExpireResult.ConditionNotMet, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f3" }, nextCentury, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); - result = db.HashFieldExpire(hashKey, "f4", oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); - Assert.Equal(ExpireResult.ConditionNotMet, result); + result = db.HashFieldExpire(hashKey, new RedisValue[] { "f4" }, oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); } [Fact] public void HashFieldGetExpireDateTime() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, nextCentury); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); - Assert.Equal(ms, result); + var result = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "f1" }); + Assert.Equal(new[] { ms }, result); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new[] { ms, ms }, fieldsResult); @@ -195,12 +171,12 @@ public void HashFieldGetExpireDateTime() [Fact] public void HashFieldExpireFieldNoExpireTime() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); - Assert.Equal(-1, result); + var result = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "f1" }); + Assert.Equal(new[] { -1L }, result); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); Assert.Equal(new long[] { -1, -1, }, fieldsResult); @@ -209,27 +185,21 @@ public void HashFieldExpireFieldNoExpireTime() [Fact] public void HashFieldGetExpireDateTimeNoKey() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldGetExpireDateTime(hashKey, "f1"); - Assert.Null(result); - var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); } [Fact] public void HashFieldGetExpireDateTimeNoField() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var result = db.HashFieldGetExpireDateTime(hashKey, "notExistingField1"); - Assert.Equal(-2, result); - var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new long[] { -2, -2, }, fieldsResult); } @@ -237,15 +207,16 @@ public void HashFieldGetExpireDateTimeNoField() [Fact] public void HashFieldGetTimeToLive() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldGetTimeToLive(hashKey, "f1"); + var result = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" }); Assert.NotNull(result); - Assert.True(result > 0); + Assert.True(result.Length == 1); + Assert.True(result[0] > 0); var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); Assert.NotNull(fieldsResult); @@ -256,13 +227,10 @@ public void HashFieldGetTimeToLive() [Fact] public void HashFieldGetTimeToLiveNoExpireTime() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldGetTimeToLive(hashKey, "f1"); - Assert.Equal(-1, result); - var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); Assert.Equal(new long[] { -1, -1, }, fieldsResult); } @@ -270,27 +238,21 @@ public void HashFieldGetTimeToLiveNoExpireTime() [Fact] public void HashFieldGetTimeToLiveNoKey() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldGetTimeToLive(hashKey, "f1"); - Assert.Null(result); - var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); } [Fact] public void HashFieldGetTimeToLiveNoField() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var result = db.HashFieldGetTimeToLive(hashKey, "notExistingField1"); - Assert.Equal(-2, result); - var fieldsResult = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new long[] { -2, -2, }, fieldsResult); } @@ -298,14 +260,14 @@ public void HashFieldGetTimeToLiveNoField() [Fact] public void HashFieldPersist() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldPersist(hashKey, "f1"); - Assert.Equal(PersistResult.Success, result); + var result = db.HashFieldPersist(hashKey, new RedisValue[] { "f1" }); + Assert.Equal(new[] { PersistResult.Success }, result); db.HashFieldExpire(hashKey, fields, oneYearInMs); @@ -316,13 +278,10 @@ public void HashFieldPersist() [Fact] public void HashFieldPersistNoExpireTime() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldPersist(hashKey, "f1"); - Assert.Equal(PersistResult.ConditionNotMet, result); - var fieldsResult = db.HashFieldPersist(hashKey, fields); Assert.Equal(new[] { PersistResult.ConditionNotMet, PersistResult.ConditionNotMet }, fieldsResult); } @@ -330,27 +289,21 @@ public void HashFieldPersistNoExpireTime() [Fact] public void HashFieldPersistNoKey() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); - var result = db.HashFieldPersist(hashKey, "f1"); - Assert.Null(result); - var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Null(fieldsResult); + Assert.Equal(Array.Empty(), fieldsResult); } [Fact] public void HashFieldPersistNoField() { - var db = Create(require: RedisFeatures.v7_2_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var result = db.HashFieldPersist(hashKey, "notExistingField1"); - Assert.Equal(PersistResult.NoSuchField, result); - var fieldsResult = db.HashFieldPersist(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); } From 517404e23ddfc53efbd04ad76fcb3d5871333ccc Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 31 May 2024 09:55:01 +0300 Subject: [PATCH 08/13] get rid of HashFieldFlags --- .../Enums/HashFieldFlags.cs | 60 ------------------- .../PublicAPI/PublicAPI.Shipped.txt | 7 --- src/StackExchange.Redis/RedisFeatures.cs | 2 +- src/StackExchange.Redis/RedisLiterals.cs | 6 -- 4 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 src/StackExchange.Redis/Enums/HashFieldFlags.cs diff --git a/src/StackExchange.Redis/Enums/HashFieldFlags.cs b/src/StackExchange.Redis/Enums/HashFieldFlags.cs deleted file mode 100644 index e901e3512..000000000 --- a/src/StackExchange.Redis/Enums/HashFieldFlags.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StackExchange.Redis; - -/// -/// Specifies the options to the HSETF command when to create hash/fields and the return data -/// -[Flags] -public enum HashFieldFlags -{ - - /// - /// No options specified. - /// - None = 0, - - /// - /// When DC (“Don’t Create”) is specified: if key does not exist: do nothing (don’t create key) - /// - DontCreate = 1, - - /// - /// When DCF (“Don’t Create Fields”) is specified: for each specified field: if the field already exists: set the field's value and expiration time; ignore fields that do not exist - /// - DontCreateFields = 2, - - /// - /// When DOF (“Don’t Overwrite Fields”) is specified: for each specified field: if such field does not exist: create field and set its value and expiration time; ignore fields that already exists - /// - DontOverwriteFields = 4, - - /// - /// When GETNEW is specified: returns the new value of given fields - /// - GetNew = 8, - - /// - /// When GETOLD is specified: returns the old value of given fields - /// - GetOld = 16, -} - -internal static class HashFieldFlagsExtensions -{ - internal static bool HasAny(this HashFieldFlags value, HashFieldFlags flag) => (value & flag) != 0; - internal static List ToRedisValueList(this HashFieldFlags flags) - { - List values = new(); - if (flags == HashFieldFlags.None) return values; - if (flags.HasAny(HashFieldFlags.DontCreate)) values.Add(RedisLiterals.DC); - if (flags.HasAny(HashFieldFlags.DontCreateFields)) values.Add(RedisLiterals.DCF); - if (flags.HasAny(HashFieldFlags.DontOverwriteFields)) values.Add(RedisLiterals.DOF); - if (flags.HasAny(HashFieldFlags.GetNew)) values.Add(RedisLiterals.GETNEW); - if (flags.HasAny(HashFieldFlags.GetOld)) values.Add(RedisLiterals.GETOLD); - return values; - } -} - diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt index b9d5bc286..ff6d62f4e 100644 --- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt @@ -462,13 +462,6 @@ StackExchange.Redis.HashEntry.HashEntry(StackExchange.Redis.RedisValue name, Sta StackExchange.Redis.HashEntry.Key.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Name.get -> StackExchange.Redis.RedisValue StackExchange.Redis.HashEntry.Value.get -> StackExchange.Redis.RedisValue -StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DontCreate = 1 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DontCreateFields = 2 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.DontOverwriteFields = 4 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.GetNew = 8 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.GetOld = 16 -> StackExchange.Redis.HashFieldFlags -StackExchange.Redis.HashFieldFlags.None = 0 -> StackExchange.Redis.HashFieldFlags StackExchange.Redis.HashSlotMovedEventArgs StackExchange.Redis.HashSlotMovedEventArgs.HashSlot.get -> int StackExchange.Redis.HashSlotMovedEventArgs.HashSlotMovedEventArgs(object! sender, int hashSlot, System.Net.EndPoint! old, System.Net.EndPoint! new) -> void diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs index 6e918504c..bd192eaeb 100644 --- a/src/StackExchange.Redis/RedisFeatures.cs +++ b/src/StackExchange.Redis/RedisFeatures.cs @@ -41,7 +41,7 @@ namespace StackExchange.Redis v6_2_0 = new Version(6, 2, 0), v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240 v7_2_0_rc1 = new Version(7, 1, 240), // 7.2 RC1 is version 7.1.240 - v7_4_0_rc1 = new Version(7, 4, 240); // 7.2 RC1 is version 7.4.240 + v7_4_0_rc1 = new Version(7, 4, 240); // 7.4 RC1 is version 7.4.240 private readonly Version version; diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index ab56a97f2..737effc1d 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -69,12 +69,9 @@ public static readonly RedisValue COPY = "COPY", COUNT = "COUNT", DB = "DB", - DC = "DC", - DCF = "DCF", @default = "default", DESC = "DESC", DOCTOR = "DOCTOR", - DOF = "DOF", ENCODING = "ENCODING", EX = "EX", EXAT = "EXAT", @@ -83,12 +80,9 @@ public static readonly RedisValue FILTERBY = "FILTERBY", FLUSH = "FLUSH", FREQ = "FREQ", - FVS = "FVS", GET = "GET", GETKEYS = "GETKEYS", GETNAME = "GETNAME", - GETNEW = "GETNEW", - GETOLD = "GETOLD", GT = "GT", HISTORY = "HISTORY", ID = "ID", From 47c0ff5d299fa13c389de74cb9ad7bcec73920ad Mon Sep 17 00:00:00 2001 From: atakavci Date: Fri, 31 May 2024 10:48:20 +0300 Subject: [PATCH 09/13] update comments with empty array return value --- src/StackExchange.Redis/Interfaces/IDatabase.cs | 10 +++++----- src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index cf43d6083..a4b4fd416 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -334,7 +334,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The timeout to set. /// under which condition the expiration will be set using . /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// Empty array if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; /// 2: field deleted because the specified expiration time is due /// 1: expiration time set/updated /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) @@ -351,7 +351,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The exact date to expiry to set. /// under which condition the expiration will be set using . /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// Empty array if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; /// 2: field deleted because the specified expiration time is due /// 1: expiration time set/updated /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) @@ -365,7 +365,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The key of the hash. /// The fields in the hash to get expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// expiration time: as a UNIX timestamp in milliseconds /// -1: if field has no associated expiration time /// -2: no such field @@ -378,7 +378,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The key of the hash. /// The fields in the hash to remove expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// 1: if the expiration time was removed /// -1: if field has no associated expiration time /// -2: no such field @@ -391,7 +391,7 @@ public interface IDatabase : IRedis, IDatabaseAsync /// The key of the hash. /// The fields in the hash to get expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// time to live: in milliseconds /// -1: if field has no associated expiration time /// -2: no such field diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index 2b258d61a..fa7723eef 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -321,7 +321,7 @@ public interface IDatabaseAsync : IRedisAsync /// The timeout to set. /// under which condition the expiration will be set using . /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// Empty array if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; /// 2: field deleted because the specified expiration time is due /// 1: expiration time set/updated /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) @@ -338,7 +338,7 @@ public interface IDatabaseAsync : IRedisAsync /// The exact date to expiry to set. /// under which condition the expiration will be set using . /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; + /// Empty array if the key does not exist. Otherwise returns an array where each item is the result of operation for given fields; /// 2: field deleted because the specified expiration time is due /// 1: expiration time set/updated /// 0: expiration time is not set/update (a specified ExpireWhen condition is not met) @@ -352,7 +352,7 @@ public interface IDatabaseAsync : IRedisAsync /// The key of the hash. /// The fields in the hash to get expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// expiration time: as a UNIX timestamp in milliseconds /// -1: if field has no associated expiration time /// -2: no such field @@ -365,7 +365,7 @@ public interface IDatabaseAsync : IRedisAsync /// The key of the hash. /// The fields in the hash to remove expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// 1: if the expiration time was removed /// -1: if field has no associated expiration time /// -2: no such field @@ -378,7 +378,7 @@ public interface IDatabaseAsync : IRedisAsync /// The key of the hash. /// The fields in the hash to get expire time. /// The flags to use for this operation. - /// null if the key does not exist. Otherwise returns the result of operation for given fields + /// Empty array if the key does not exist. Otherwise returns the result of operation for given fields /// time to live: in milliseconds /// -1: if field has no associated expiration time /// -2: no such field From c437953dcaca619a9a39a257846527994ef19990 Mon Sep 17 00:00:00 2001 From: atakavci Date: Thu, 20 Jun 2024 11:43:51 +0300 Subject: [PATCH 10/13] response for each missing fields instead of empty array when key not exists --- src/StackExchange.Redis/RedisFeatures.cs | 4 +++- .../HashFieldTests.cs | 24 +++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/StackExchange.Redis/RedisFeatures.cs b/src/StackExchange.Redis/RedisFeatures.cs index bd192eaeb..ae2ed9c7f 100644 --- a/src/StackExchange.Redis/RedisFeatures.cs +++ b/src/StackExchange.Redis/RedisFeatures.cs @@ -41,7 +41,9 @@ namespace StackExchange.Redis v6_2_0 = new Version(6, 2, 0), v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240 v7_2_0_rc1 = new Version(7, 1, 240), // 7.2 RC1 is version 7.1.240 - v7_4_0_rc1 = new Version(7, 4, 240); // 7.4 RC1 is version 7.4.240 + v7_4_0_rc1 = new Version(7, 3, 240), // 7.4 RC1 is version 7.3.240 + v7_4_0_rc2 = new Version(7, 3, 241); // 7.4 RC2 is version 7.3.241 + private readonly Version version; diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index a25e352bf..c35a26e0a 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -45,14 +45,14 @@ public void HashFieldExpire() [Fact] public void HashFieldExpireNoKey() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); } [Fact] @@ -72,14 +72,14 @@ public async void HashFieldExpireAsync() [Fact] public async void HashFieldExpireAsyncNoKey() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); } [Fact] @@ -185,11 +185,11 @@ public void HashFieldExpireFieldNoExpireTime() [Fact] public void HashFieldGetExpireDateTimeNoKey() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new long[] { -2, -2, }, fieldsResult); } [Fact] @@ -238,11 +238,11 @@ public void HashFieldGetTimeToLiveNoExpireTime() [Fact] public void HashFieldGetTimeToLiveNoKey() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new long[] { -2, -2, }, fieldsResult); } [Fact] @@ -289,11 +289,11 @@ public void HashFieldPersistNoExpireTime() [Fact] public void HashFieldPersistNoKey() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); + var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(Array.Empty(), fieldsResult); + Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); } [Fact] From a2f734ebd45ee788ec103977896548c61ec851dd Mon Sep 17 00:00:00 2001 From: atakavci Date: Sat, 3 Aug 2024 15:26:56 +0300 Subject: [PATCH 11/13] static methods to pick commandtype --- src/StackExchange.Redis/RedisDatabase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index ba28f8ea5..39370e4cf 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -430,9 +430,9 @@ private T HashFieldExpireExecute(RedisKey key, long milliseconds, ExpireWh return executor(msg, processor); } - private RedisCommand PickExpireCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIRE : RedisCommand.HPEXPIRE; + private static RedisCommand PickExpireCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIRE : RedisCommand.HPEXPIRE; - private RedisCommand PickExpireAtCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIREAT : RedisCommand.HPEXPIREAT; + private static RedisCommand PickExpireAtCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIREAT : RedisCommand.HPEXPIREAT; private T HashFieldExecute(RedisCommand cmd, RedisKey key, CustomExecutor executor, P processor, CommandFlags flags = CommandFlags.None, params RedisValue[] hashFields) { From 8764546dd04b9960478554484aac3da7ca40f399 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sat, 3 Aug 2024 11:09:39 -0400 Subject: [PATCH 12/13] Cleanup --- src/StackExchange.Redis/RedisDatabase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 685e75eb2..0e5eada53 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -1,7 +1,6 @@ using System; using System.Buffers; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Threading.Tasks; using Pipelines.Sockets.Unofficial.Arenas; From 76267811a0f3fdcb10cb6288637ace4534161106 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Sat, 3 Aug 2024 11:11:43 -0400 Subject: [PATCH 13/13] Add release notes --- docs/ReleaseNotes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 5a1b9aa64..bf057512f 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -8,6 +8,7 @@ Current package versions: ## Unreleased +- Add support for hash field expiration (see [#2715](https://github.com/StackExchange/StackExchange.Redis/issues/2715)) ([#2716 by atakavci](https://github.com/StackExchange/StackExchange.Redis/pull/2716])) ## 2.8.0