Skip to content

Commit

Permalink
fixing issue with timespans having fractional millisecond values (#497)
Browse files Browse the repository at this point in the history
* fixing issue with timespans having fractional values

* fixign test

* fixing test

* more test fixes
  • Loading branch information
slorello89 authored Oct 28, 2024
1 parent 52bff7f commit 48ea85e
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 18 deletions.
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

0 comments on commit 48ea85e

Please sign in to comment.