Skip to content

Commit

Permalink
Clarify meaning of RedisValue.IsInteger (#2420)
Browse files Browse the repository at this point in the history
* add passing (modified) test for #2418

* - clarify the meaning of RedisValue.IsInteger, and reduce the visibility
- fix a typo

* fix PR number
  • Loading branch information
mgravell authored Mar 30, 2023
1 parent ef388bd commit f690d16
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
1 change: 1 addition & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Current package versions:
- Fix [#2392](https://github.com/StackExchange/StackExchange.Redis/issues/2392): Dequeue *all* timed out messages from the backlog when not connected (including Fire+Forget) ([#2397 by kornelpal](https://github.com/StackExchange/StackExchange.Redis/pull/2397))
- Fix [#2400](https://github.com/StackExchange/StackExchange.Redis/issues/2400): Expose `ChannelMessageQueue` as `IAsyncEnumerable<ChannelMessage>` ([#2402 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2402))
- Add: support for `CLIENT SETINFO` (lib name/version) during handshake; opt-out is via `ConfigurationOptions`; also support read of `resp`, `lib-ver` and `lib-name` via `CLIENT LIST` ([#2414 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2414))
- Documentation: clarify the meaning of `RedisValue.IsInteger` re [#2418](https://github.com/StackExchange/StackExchange.Redis/issues/2418) ([#2420 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2420))

## 2.6.96

Expand Down
2 changes: 1 addition & 1 deletion src/StackExchange.Redis/RedisServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private Message GetCommandListMessage(RedisValue? moduleName = null, RedisValue?
}

else
throw new ArgumentException("More then one filter is not allwed");
throw new ArgumentException("More then one filter is not allowed");
}

private RedisValue[] AddValueToArray(RedisValue val, RedisValue[] arr)
Expand Down
28 changes: 16 additions & 12 deletions src/StackExchange.Redis/RedisValue.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Buffers;
using System.Buffers.Text;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -107,8 +108,11 @@ public static RedisValue Unbox(object? value)
public static RedisValue Null { get; } = new RedisValue(0, default, null);

/// <summary>
/// Indicates whether the value is a primitive integer (signed or unsigned).
/// Indicates whether the **underlying** value is a primitive integer (signed or unsigned); this is **not**
/// the same as whether the value can be *treated* as an integer - see <seealso cref="TryParse(out int)"/>
/// and <seealso cref="TryParse(out long)"/>, which is usually the more appropriate test.
/// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] // hide it, because this *probably* isn't what callers need
public bool IsInteger => _objectOrSentinel == Sentinel_SignedInteger || _objectOrSentinel == Sentinel_UnsignedInteger;

/// <summary>
Expand Down Expand Up @@ -698,65 +702,65 @@ private static bool TryParseDouble(ReadOnlySpan<byte> blob, out double value)
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{double}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator double? (RedisValue value)
public static explicit operator double?(RedisValue value)
=> value.IsNull ? (double?)null : (double)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{float}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator float? (RedisValue value)
public static explicit operator float?(RedisValue value)
=> value.IsNull ? (float?)null : (float)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{decimal}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator decimal? (RedisValue value)
public static explicit operator decimal?(RedisValue value)
=> value.IsNull ? (decimal?)null : (decimal)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{long}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator long? (RedisValue value)
public static explicit operator long?(RedisValue value)
=> value.IsNull ? (long?)null : (long)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{ulong}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
[CLSCompliant(false)]
public static explicit operator ulong? (RedisValue value)
public static explicit operator ulong?(RedisValue value)
=> value.IsNull ? (ulong?)null : (ulong)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{int}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator int? (RedisValue value)
public static explicit operator int?(RedisValue value)
=> value.IsNull ? (int?)null : (int)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{uint}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
[CLSCompliant(false)]
public static explicit operator uint? (RedisValue value)
public static explicit operator uint?(RedisValue value)
=> value.IsNull ? (uint?)null : (uint)value;

/// <summary>
/// Converts the <see cref="RedisValue"/> to a <see cref="T:Nullable{bool}"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static explicit operator bool? (RedisValue value)
public static explicit operator bool?(RedisValue value)
=> value.IsNull ? (bool?)null : (bool)value;

/// <summary>
/// Converts a <see cref="RedisValue"/> to a <see cref="string"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static implicit operator string? (RedisValue value)
public static implicit operator string?(RedisValue value)
{
switch (value.Type)
{
Expand Down Expand Up @@ -810,7 +814,7 @@ private static string ToHex(ReadOnlySpan<byte> src)
/// Converts a <see cref="RedisValue"/> to a <see cref="T:byte[]"/>.
/// </summary>
/// <param name="value">The <see cref="RedisValue"/> to convert.</param>
public static implicit operator byte[]? (RedisValue value)
public static implicit operator byte[]?(RedisValue value)
{
switch (value.Type)
{
Expand Down Expand Up @@ -1112,7 +1116,7 @@ private ReadOnlyMemory<byte> AsMemory(out byte[]? leased)
return _memory;
case StorageType.String:
string s = (string)_objectOrSentinel!;
HaveString:
HaveString:
if (s.Length == 0)
{
leased = null;
Expand Down
48 changes: 48 additions & 0 deletions tests/StackExchange.Redis.Tests/Issues/Issue2418.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace StackExchange.Redis.Tests.Issues;

public class Issue2418 : TestBase
{
public Issue2418(ITestOutputHelper output, SharedConnectionFixture? fixture = null)
: base(output, fixture) { }

[Fact]
public async Task Execute()
{
using var conn = Create();
var db = conn.GetDatabase();

RedisKey key = Me();
RedisValue someInt = 12;
Assert.False(someInt.IsNullOrEmpty, nameof(someInt.IsNullOrEmpty) + " before");
Assert.True(someInt.IsInteger, nameof(someInt.IsInteger) + " before");
await db.HashSetAsync(key, new[]
{
new HashEntry("some_int", someInt),
// ...
});

// check we can fetch it
var entry = await db.HashGetAllAsync(key);
Assert.NotEmpty(entry);
Assert.Single(entry);
foreach (var pair in entry)
{
Log($"'{pair.Name}'='{pair.Value}'");
}


// filter with LINQ
Assert.True(entry.Any(x => x.Name == "some_int"), "Any");
someInt = entry.FirstOrDefault(x => x.Name == "some_int").Value;
Log($"found via Any: '{someInt}'");
Assert.False(someInt.IsNullOrEmpty, nameof(someInt.IsNullOrEmpty) + " after");
Assert.True(someInt.TryParse(out int i));
Assert.Equal(12, i);
Assert.Equal(12, (int)someInt);
}
}

0 comments on commit f690d16

Please sign in to comment.