Skip to content

Commit

Permalink
Replace all occurrences of "nil" in IDatabase(Async) xmldoc with le…
Browse files Browse the repository at this point in the history
…ss ambiguous alternatives (#2702)

Closes #2697.

All of the replacements were empirically tested to be correct via simple programs in combination with a local redis instance.

Notably, there is one worrying nit; in testing it turns out that the `IDatabase.List{Left,Right}Pop(RedisKey, long, CommandFlags)` overload which I talked about in the issue _can_ actually return null, contrary to its nullability annotations. This occurs on missing key; in that case redis replies

	Nil reply: if the key does not exist.

as per https://redis.io/docs/latest/commands/lpop/, which then at

https://github.com/StackExchange/StackExchange.Redis/blob/cb8b20df0e2975717bde97ce95ac20e8e8353572/src/StackExchange.Redis/ResultProcessor.cs#L1546-L1547

and later at

https://github.com/StackExchange/StackExchange.Redis/blob/cb8b20df0e2975717bde97ce95ac20e8e8353572/src/StackExchange.Redis/ExtensionMethods.cs#L339-L341

turns into a `null`.

I briefly attempted to rectify this, but the `RedisValueArrayProcessor` poses a problem here, as changing it to derive
`ResultProcessor<RedisValue[]?>` causes the solution to light up in red, and I'd rather not mess with that as a first contribution without at least prior discussion concerning direction there.
  • Loading branch information
bdach committed May 7, 2024
1 parent cb8b20d commit 61c13c2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 56 deletions.
57 changes: 29 additions & 28 deletions src/StackExchange.Redis/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the hash.</param>
/// <param name="hashField">The field in the hash to get.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value associated with field, or nil when field is not present in the hash or key does not exist.</returns>
/// <returns>The value associated with field, or <see cref="RedisValue.Null"/> when field is not present in the hash or key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/hget"/></remarks>
RedisValue HashGet(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None);

Expand All @@ -341,13 +341,14 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the hash.</param>
/// <param name="hashField">The field in the hash to get.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value associated with field, or nil when field is not present in the hash or key does not exist.</returns>
/// <returns>The value associated with field, or <see langword="null"/> when field is not present in the hash or key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/hget"/></remarks>
Lease<byte>? HashGetLease(RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the values associated with the specified fields in the hash stored at key.
/// For every field that does not exist in the hash, a nil value is returned.Because a non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of nil values.
/// For every field that does not exist in the hash, a <see langword="RedisValue.Null"/> value is returned.
/// Because non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of <see langword="RedisValue.Null"/> values.
/// </summary>
/// <param name="key">The key of the hash.</param>
/// <param name="hashFields">The fields in the hash to get.</param>
Expand Down Expand Up @@ -802,7 +803,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// Return a random key from the currently selected database.
/// </summary>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The random key, or nil when the database is empty.</returns>
/// <returns>The random key, or <see cref="RedisKey.Null"/> when the database is empty.</returns>
/// <remarks><seealso href="https://redis.io/commands/randomkey"/></remarks>
RedisKey KeyRandom(CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -847,7 +848,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// </summary>
/// <param name="key">The key to check.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>TTL, or nil when key does not exist or does not have a timeout.</returns>
/// <returns>TTL, or <see langword="null"/> when key does not exist or does not have a timeout.</returns>
/// <remarks><seealso href="https://redis.io/commands/ttl"/></remarks>
TimeSpan? KeyTimeToLive(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -888,7 +889,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the list.</param>
/// <param name="index">The index position to get the value at.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The requested element, or nil when index is out of range.</returns>
/// <returns>The requested element, or <see cref="RedisValue.Null"/> when index is out of range.</returns>
/// <remarks><seealso href="https://redis.io/commands/lindex"/></remarks>
RedisValue ListGetByIndex(RedisKey key, long index, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -921,7 +922,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// </summary>
/// <param name="key">The key of the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of the first element, or nil when key does not exist.</returns>
/// <returns>The value of the first element, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/lpop"/></remarks>
RedisValue ListLeftPop(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand All @@ -932,7 +933,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the list.</param>
/// <param name="count">The number of elements to remove</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>Array of values that were popped, or nil if the key doesn't exist.</returns>
/// <returns>Array of values that were popped, or <see langword="null"/> if the key doesn't exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/lpop"/></remarks>
RedisValue[] ListLeftPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -1075,7 +1076,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// </summary>
/// <param name="key">The key of the list.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The element being popped.</returns>
/// <returns>The element being popped, or <see cref="RedisValue.Null"/> when key does not exist..</returns>
/// <remarks><seealso href="https://redis.io/commands/rpop"/></remarks>
RedisValue ListRightPop(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand All @@ -1086,7 +1087,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the list.</param>
/// <param name="count">The number of elements to pop</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>Array of values that were popped, or nil if the key doesn't exist.</returns>
/// <returns>Array of values that were popped, or <see langword="null"/> if the key doesn't exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/rpop"/></remarks>
RedisValue[] ListRightPop(RedisKey key, long count, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -1494,7 +1495,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// </summary>
/// <param name="key">The key of the set.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The removed element, or nil when key does not exist.</returns>
/// <returns>The removed element, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/spop"/></remarks>
RedisValue SetPop(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -2122,7 +2123,7 @@ public interface IDatabase : IRedis, IDatabaseAsync

/// <summary>
/// Returns the score of member in the sorted set at key.
/// If member does not exist in the sorted set, or key does not exist, nil is returned.
/// If member does not exist in the sorted set, or key does not exist, <see langword="null"/> is returned.
/// </summary>
/// <param name="key">The key of the sorted set.</param>
/// <param name="member">The member to get a score for.</param>
Expand Down Expand Up @@ -2151,7 +2152,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the sorted set.</param>
/// <param name="order">The order to sort by (defaults to ascending).</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The removed element, or nil when key does not exist.</returns>
/// <returns>The removed element, or <see langword="null"/> when key does not exist.</returns>
/// <remarks>
/// <seealso href="https://redis.io/commands/zpopmin"/>,
/// <seealso href="https://redis.io/commands/zpopmax"/>
Expand Down Expand Up @@ -2674,32 +2675,32 @@ public interface IDatabase : IRedis, IDatabaseAsync
double StringDecrement(RedisKey key, double value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Get the value of key. If the key does not exist the special value nil is returned.
/// Get the value of key. If the key does not exist the special value <see cref="RedisValue.Null"/> is returned.
/// An error is returned if the value stored at key is not a string, because GET only handles string values.
/// </summary>
/// <param name="key">The key of the string.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key, or nil when key does not exist.</returns>
/// <returns>The value of key, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/get"/></remarks>
RedisValue StringGet(RedisKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the values of all specified keys.
/// For every key that does not hold a string value or does not exist, the special value nil is returned.
/// For every key that does not hold a string value or does not exist, the special value <see cref="RedisValue.Null"/> is returned.
/// </summary>
/// <param name="keys">The keys of the strings.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The values of the strings with nil for keys do not exist.</returns>
/// <returns>The values of the strings with <see cref="RedisValue.Null"/> for keys do not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/mget"/></remarks>
RedisValue[] StringGet(RedisKey[] keys, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Get the value of key. If the key does not exist the special value nil is returned.
/// Get the value of key. If the key does not exist the special value <see langword="null"/> is returned.
/// An error is returned if the value stored at key is not a string, because GET only handles string values.
/// </summary>
/// <param name="key">The key of the string.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key, or nil when key does not exist.</returns>
/// <returns>The value of key, or <see langword="null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/get"/></remarks>
Lease<byte>? StringGetLease(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -2733,7 +2734,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the string.</param>
/// <param name="value">The value to replace the existing value with.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The old value stored at key, or nil when key did not exist.</returns>
/// <returns>The old value stored at key, or <see cref="RedisValue.Null"/> when key did not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/getset"/></remarks>
RedisValue StringGetSet(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None);

Expand All @@ -2744,7 +2745,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the string.</param>
/// <param name="expiry">The expiry to set. <see langword="null"/> will remove expiry.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key, or nil when key does not exist.</returns>
/// <returns>The value of key, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/getex"/></remarks>
RedisValue StringGetSetExpiry(RedisKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None);

Expand All @@ -2755,29 +2756,29 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="key">The key of the string.</param>
/// <param name="expiry">The exact date and time to expire at. <see cref="DateTime.MaxValue"/> will remove expiry.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key, or nil when key does not exist.</returns>
/// <returns>The value of key, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/getex"/></remarks>
RedisValue StringGetSetExpiry(RedisKey key, DateTime expiry, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Get the value of key and delete the key.
/// If the key does not exist the special value nil is returned.
/// If the key does not exist the special value <see cref="RedisValue.Null"/> is returned.
/// An error is returned if the value stored at key is not a string, because GET only handles string values.
/// </summary>
/// <param name="key">The key of the string.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key, or nil when key does not exist.</returns>
/// <returns>The value of key, or <see cref="RedisValue.Null"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/getdelete"/></remarks>
RedisValue StringGetDelete(RedisKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Get the value of key.
/// If the key does not exist the special value nil is returned.
/// If the key does not exist the special value <see langword="default"/> is returned.
/// An error is returned if the value stored at key is not a string, because GET only handles string values.
/// </summary>
/// <param name="key">The key of the string.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The value of key and its expiry, or nil when key does not exist.</returns>
/// <returns>The value of key and its expiry, or <see langword="default"/> when key does not exist.</returns>
/// <remarks><seealso href="https://redis.io/commands/get"/></remarks>
RedisValueWithExpiry StringGetWithExpiry(RedisKey key, CommandFlags flags = CommandFlags.None);

Expand Down Expand Up @@ -2901,7 +2902,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="expiry">The expiry to set.</param>
/// <param name="when">Which condition to set the value under (defaults to <see cref="When.Always"/>).</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The previous value stored at <paramref name="key"/>, or nil when key did not exist.</returns>
/// <returns>The previous value stored at <paramref name="key"/>, or <see cref="RedisValue.Null"/> when key did not exist.</returns>
/// <remarks>
/// <para>This method uses the <c>SET</c> command with the <c>GET</c> option introduced in Redis 6.2.0 instead of the deprecated <c>GETSET</c> command.</para>
/// <para><seealso href="https://redis.io/commands/set"/></para>
Expand All @@ -2917,7 +2918,7 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <param name="keepTtl">Whether to maintain the existing key's TTL (KEEPTTL flag).</param>
/// <param name="when">Which condition to set the value under (defaults to <see cref="When.Always"/>).</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The previous value stored at <paramref name="key"/>, or nil when key did not exist.</returns>
/// <returns>The previous value stored at <paramref name="key"/>, or <see cref="RedisValue.Null"/> when key did not exist.</returns>
/// <remarks>This method uses the SET command with the GET option introduced in Redis 6.2.0 instead of the deprecated GETSET command.</remarks>
/// <remarks><seealso href="https://redis.io/commands/set"/></remarks>
RedisValue StringSetAndGet(RedisKey key, RedisValue value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None);
Expand Down

0 comments on commit 61c13c2

Please sign in to comment.