Skip to content

Commit a2f3f70

Browse files
authored
adding ability to index and query datetimes (#240)
* adding ability to index and query datetimes * fixing sortable bit of index creation
1 parent fc7f08c commit a2f3f70

File tree

10 files changed

+404
-8
lines changed

10 files changed

+404
-8
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ Once the index is created, we can:
188188

189189
Let's see how!
190190

191+
### Indexing DateTimes
192+
193+
As of version 0.4.0, all DateTime objects are indexed as numerics, and they are inserted as numerics into JSON documents. Because of this, you can query them as if they were numerics!
194+
191195
### 🔑 Keys and Ids
192196

193197
#### ULIDs and strings

src/Redis.OM/Common/ExpressionParserUtilities.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,11 @@ private static string ValueToString(object value)
673673
return ((double)value).ToString(CultureInfo.InvariantCulture);
674674
}
675675

676+
if (value is DateTime dt)
677+
{
678+
return new DateTimeOffset(dt).ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture);
679+
}
680+
676681
return value.ToString();
677682
}
678683

src/Redis.OM/Common/ExpressionTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ internal static string TranslateBinaryExpression(BinaryExpression binExpression)
332332
}
333333
else
334334
{
335-
if (!int.TryParse(rightContent, out _))
335+
if (!int.TryParse(rightContent, out _) && !long.TryParse(rightContent, out _))
336336
{
337337
rightContent = ((int)Enum.Parse(member.Type, rightContent)).ToString();
338338
}

src/Redis.OM/Modeling/DateTimeJsonConverter.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ public class DateTimeJsonConverter : JsonConverter<DateTime>
1212
/// <inheritdoc />
1313
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1414
{
15-
var val = reader.GetString();
15+
long val = reader.TokenType == JsonTokenType.String ? long.Parse(reader.GetString() !) : reader.GetInt64();
16+
1617
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
17-
return TimeZoneInfo.ConvertTimeFromUtc(dateTime.AddMilliseconds(long.Parse(val!)), TimeZoneInfo.Local);
18+
return TimeZoneInfo.ConvertTimeFromUtc(dateTime.AddMilliseconds(val), TimeZoneInfo.Local);
1819
}
1920

2021
/// <inheritdoc />
2122
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
2223
{
23-
writer.WriteStringValue(new DateTimeOffset(value).ToUnixTimeMilliseconds().ToString());
24+
writer.WriteNumberValue(new DateTimeOffset(value).ToUnixTimeMilliseconds());
2425
}
2526
}
2627
}

src/Redis.OM/Modeling/TypeDeterminationUtilities.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ internal static class TypeDeterminationUtilities
2424
typeof(uint),
2525
typeof(ushort),
2626
typeof(float),
27+
typeof(DateTime),
2728
};
2829

2930
/// <summary>

src/Redis.OM/Redis.OM.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
<RootNamespace>Redis.OM</RootNamespace>
77
<Nullable>enable</Nullable>
88
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
9-
<PackageVersion>0.3.1</PackageVersion>
10-
<Version>0.3.1</Version>
11-
<PackageReleaseNotes>https://github.com/redis/redis-om-dotnet/releases/tag/v0.3.1</PackageReleaseNotes>
9+
<PackageVersion>0.4.0</PackageVersion>
10+
<Version>0.4.0</Version>
11+
<PackageReleaseNotes>https://github.com/redis/redis-om-dotnet/releases/tag/v0.4.0</PackageReleaseNotes>
1212
<Description>Object Mapping and More for Redis</Description>
1313
<Title>Redis OM</Title>
1414
<Authors>Steve Lorello</Authors>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using Redis.OM.Modeling;
3+
4+
namespace Redis.OM.Unit.Tests.RediSearchTests;
5+
6+
[Document(StorageType = StorageType.Json)]
7+
public class ObjectWithDateTime
8+
{
9+
[RedisField]
10+
public string Id { get; set; }
11+
[Indexed(Sortable = true)]
12+
public DateTime Timestamp { get; set; }
13+
[Indexed]
14+
public DateTime? NullableTimestamp { get; set; }
15+
}
16+
17+
[Document(StorageType = StorageType.Hash)]
18+
public class ObjectWithDateTimeHash
19+
{
20+
[RedisField]
21+
public string Id { get; set; }
22+
23+
[Indexed]
24+
public DateTime Timestamp { get; set; }
25+
[Indexed]
26+
public DateTime? NullableTimestamp { get; set; }
27+
}

test/Redis.OM.Unit.Tests/RediSearchTests/SearchFunctionalTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Globalization;
34
using System.Linq;
45
using System.Threading.Tasks;
56
using Microsoft.VisualBasic;
@@ -858,5 +859,44 @@ public async Task TestStatelessCollection()
858859
Assert.Equal(0,collection.StateManager.Data.Count);
859860
Assert.Equal(0,collection.StateManager.Snapshot.Count);
860861
}
862+
863+
public void CompareTimestamps(DateTime ts1, DateTime ts2)
864+
{
865+
Assert.Equal(ts1.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fff", CultureInfo.InvariantCulture), ts2.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fff", CultureInfo.InvariantCulture));
866+
}
867+
868+
[Fact]
869+
public async Task TestTimeStampRanges()
870+
{
871+
var collection = new RedisCollection<ObjectWithDateTime>(_connection, false, 10000);
872+
var timestamp = DateTime.Now;
873+
var greaterThanTimestamp = DateTime.Now.Subtract(TimeSpan.FromHours(1));
874+
var unixTimestamp = new DateTimeOffset(timestamp).ToUnixTimeMilliseconds();
875+
var obj = new ObjectWithDateTime { Timestamp = timestamp, NullableTimestamp = timestamp };
876+
var id = await collection.InsertAsync(obj);
877+
var first = await collection.FirstOrDefaultAsync(x => x.Timestamp > greaterThanTimestamp);
878+
Assert.NotNull(first);
879+
Assert.NotNull(first.NullableTimestamp);
880+
CompareTimestamps(timestamp, first.Timestamp);
881+
CompareTimestamps(timestamp, first.NullableTimestamp.Value);
882+
Assert.Equal(obj.Id, first.Id);
883+
}
884+
885+
[Fact]
886+
public async Task TestTimeStampRangesHash()
887+
{
888+
var collection = new RedisCollection<ObjectWithDateTimeHash>(_connection, false, 10000);
889+
var timestamp = DateTime.Now;
890+
var greaterThanTimestamp = DateTime.Now.Subtract(TimeSpan.FromHours(1));
891+
var unixTimestamp = new DateTimeOffset(timestamp).ToUnixTimeMilliseconds();
892+
var obj = new ObjectWithDateTimeHash { Timestamp = timestamp, NullableTimestamp = timestamp };
893+
var id = await collection.InsertAsync(obj);
894+
var first = await collection.FirstOrDefaultAsync(x => x.Timestamp > greaterThanTimestamp);
895+
Assert.NotNull(first);
896+
Assert.NotNull(first.NullableTimestamp);
897+
CompareTimestamps(timestamp, first.Timestamp);
898+
CompareTimestamps(timestamp, first.NullableTimestamp.Value);
899+
Assert.Equal(obj.Id, first.Id);
900+
}
861901
}
862902
}

0 commit comments

Comments
 (0)