Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixing issue with timespans having fractional millisecond values #497

Merged
merged 4 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Redis.OM/Extensions/TimespanExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Globalization;

namespace Redis.OM;

/// <summary>
/// Extension methods for Timespans.
/// </summary>
internal static class TimespanExtensions
{
/// <summary>
/// Rounds up total milliseconds as an integer.
/// </summary>
/// <param name="ts">the timespan.</param>
/// <returns>the rounded timespan milliseconds.</returns>
public static string TotalMillisecondsString(this TimeSpan ts)
{
return Math.Ceiling(ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture);
}
}
20 changes: 10 additions & 10 deletions src/Redis.OM/RedisCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public static async Task<bool> JsonSetAsync(this IRedisConnection connection, st
/// <returns>whether the operation succeeded.</returns>
public static async Task<bool> JsonSetAsync(this IRedisConnection connection, string key, string path, string json, WhenKey when, TimeSpan? timeSpan = null)
{
var argList = new List<string> { timeSpan != null ? ((long)timeSpan.Value.TotalMilliseconds).ToString() : "-1", path, json };
var argList = new List<string> { timeSpan != null ? timeSpan.Value.TotalMillisecondsString() : "-1", path, json };
switch (when)
{
case WhenKey.Exists:
Expand Down Expand Up @@ -328,7 +328,7 @@ public static bool JsonSet(this IRedisConnection connection, string key, string
/// <returns>whether the operation succeeded.</returns>
public static bool JsonSet(this IRedisConnection connection, string key, string path, string json, WhenKey when, TimeSpan? timeSpan = null)
{
var argList = new List<string> { timeSpan != null ? ((long)timeSpan.Value.TotalMilliseconds).ToString() : "-1", path, json };
var argList = new List<string> { timeSpan != null ? timeSpan.Value.TotalMillisecondsString() : "-1", path, json };
switch (when)
{
case WhenKey.Exists:
Expand Down Expand Up @@ -416,7 +416,7 @@ public static string Set(this IRedisConnection connection, object obj)
var kvps = obj.BuildHashSet();
var argsList = new List<object>();
int? res = null;
argsList.Add(timespan != null ? ((long)timespan.Value.TotalMilliseconds).ToString() : "-1");
argsList.Add(timespan != null ? timespan.Value.TotalMillisecondsString() : "-1");
foreach (var kvp in kvps)
{
argsList.Add(kvp.Key);
Expand Down Expand Up @@ -467,7 +467,7 @@ public static string Set(this IRedisConnection connection, object obj)
var kvps = obj.BuildHashSet();
var argsList = new List<object>();
int? res = null;
argsList.Add(timespan != null ? ((long)timespan.Value.TotalMilliseconds).ToString() : "-1");
argsList.Add(timespan != null ? timespan.Value.TotalMillisecondsString() : "-1");
foreach (var kvp in kvps)
{
argsList.Add(kvp.Key);
Expand Down Expand Up @@ -794,8 +794,8 @@ internal static void UnlinkAndSet<T>(this IRedisConnection connection, string ke
args.Add(pair.Value);
if (ttl is not null)
{
args.Add("EXPIRE");
args.Add(ttl.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
args.Add("PEXPIRE");
args.Add(ttl.Value.TotalMillisecondsString());
}
}

Expand Down Expand Up @@ -831,8 +831,8 @@ internal static async Task UnlinkAndSetAsync<T>(this IRedisConnection connection
args.Add(pair.Value);
if (ttl is not null)
{
args.Add("EXPIRE");
args.Add(ttl.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
args.Add("PEXPIRE");
args.Add(ttl.Value.TotalMillisecondsString());
}
}

Expand All @@ -848,7 +848,7 @@ private static RedisReply[] SendCommandWithExpiry(
TimeSpan ts)
{
var commandTuple = Tuple.Create(command, args);
var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) });
var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ts.TotalMillisecondsString() });
return connection.ExecuteInTransaction(new[] { commandTuple, expireTuple });
}

Expand All @@ -860,7 +860,7 @@ private static Task<RedisReply[]> SendCommandWithExpiryAsync(
TimeSpan ts)
{
var commandTuple = Tuple.Create(command, args);
var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) });
var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ts.TotalMillisecondsString() });
return connection.ExecuteInTransactionAsync(new[] { commandTuple, expireTuple });
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/Redis.OM/Searching/RedisCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -773,14 +773,14 @@ private async Task<KeyValuePair<string, T>> UpdateAsyncNoSave(T item, TimeSpan?
if (ttl is not null)
{
args.Add("EXPIRE");
args.Add(ttl.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
args.Add(ttl.Value.TotalMillisecondsString());
}

await _connection.CreateAndEvalAsync(scriptName, new[] { key }, args.ToArray());
}
else if (ttl is not null)
{
await _connection.ExecuteAsync("PEXPIRE", key, ttl.Value.TotalMilliseconds);
await _connection.ExecuteAsync("PEXPIRE", key, ttl.Value.TotalMillisecondsString());
}
}
else
Expand Down Expand Up @@ -841,14 +841,14 @@ private void SendUpdate(T item, TimeSpan? ttl = null)
if (ttl is not null)
{
args.Add("EXPIRE");
args.Add(ttl.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
args.Add(ttl.Value.TotalMillisecondsString());
}

_connection.CreateAndEval(scriptName, new[] { key }, args.ToArray());
}
else if (ttl is not null)
{
_connection.Execute("PEXPIRE", key, ttl.Value.TotalMilliseconds);
_connection.Execute("PEXPIRE", key, ttl.Value.TotalMillisecondsString());
}
}
else
Expand Down Expand Up @@ -879,14 +879,14 @@ private Task SendUpdateAsync(T item, TimeSpan? ttl = null)
if (ttl is not null)
{
args.Add("EXPIRE");
args.Add(ttl.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
args.Add(ttl.Value.TotalMillisecondsString());
}

task = _connection.CreateAndEvalAsync(scriptName, new[] { key }, args.ToArray());
}
else if (ttl is not null)
{
task = _connection.ExecuteAsync("PEXPIRE", key, ttl.Value.TotalMilliseconds);
task = _connection.ExecuteAsync("PEXPIRE", key, ttl.Value.TotalMillisecondsString());
}
}
else
Expand Down
4 changes: 2 additions & 2 deletions test/Redis.OM.Unit.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public async Task ExpireFractionalMillisecondAsync()
var jsonObjWithExpire = new BasicJsonObject { Name = "JsonWithExpire" };
var key = await connection.SetAsync(jsonObjWithExpire, TimeSpan.FromMilliseconds(5000.5));
var ttl = (long)await connection.ExecuteAsync("PTTL", key);
Assert.True(ttl <= 5000.5);
Assert.True(ttl <= 5001);
Assert.True(ttl >= 1000);
}

Expand All @@ -78,7 +78,7 @@ public void ExpireFractionalMillisecond()
var jsonObjWithExpire = new BasicJsonObject { Name = "JsonWithExpire" };
var key = connection.Set(jsonObjWithExpire, TimeSpan.FromMilliseconds(5000.5));
var ttl = (long)connection.Execute("PTTL", key);
Assert.True(ttl <= 5000.5);
Assert.True(ttl <= 5001);
Assert.True(ttl >= 1000);
}

Expand Down
26 changes: 26 additions & 0 deletions test/Redis.OM.Unit.Tests/RediSearchTests/SearchFunctionalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,32 @@ public async Task TestUpdateWithTtlAsync()
Assert.Equal(secondQueriedP.Id, queriedP.Id);
Assert.Equal(testP.Id, secondQueriedP.Id);
}

[Fact]
public async Task TestUpdateWithTtlAsyncFractionalTimespan()
{
var collection = new RedisCollection<Person>(_connection);
var testP = new Person { Name = "Steve", Age = 32 };
var key = await collection.InsertAsync(testP);
var queriedP = await collection.FindByIdAsync(key);
Assert.NotNull(queriedP);
queriedP.Age = 33;
TimeSpan ttl = TimeSpan.FromHours(1);
ttl = ttl.Add(TimeSpan.FromTicks(5000));

await collection.UpdateAsync(queriedP, ttl);

var ttlFromKey = (double) await _connection.ExecuteAsync("PTTL", key);

var secondQueriedP = await collection.FindByIdAsync(key);

Assert.Equal("3600001", ttl.TotalMillisecondsString());
Assert.InRange(ttlFromKey, ttl.TotalMilliseconds - 2000, ttl.TotalMilliseconds + 1);
Assert.NotNull(secondQueriedP);
Assert.Equal(33, secondQueriedP.Age);
Assert.Equal(secondQueriedP.Id, queriedP.Id);
Assert.Equal(testP.Id, secondQueriedP.Id);
}

[Fact]
public async Task TestUpdateName()
Expand Down
Loading