diff --git a/src/LinqTests/Acceptance/querying_against_timespan.cs b/src/LinqTests/Acceptance/querying_against_timespan.cs new file mode 100644 index 0000000000..d9fe2618c7 --- /dev/null +++ b/src/LinqTests/Acceptance/querying_against_timespan.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using JasperFx.Core; +using Marten; +using Marten.Testing.Documents; +using Marten.Testing.Harness; +using Shouldly; + +namespace LinqTests.Acceptance; + +public class querying_against_timespan : IntegrationContext +{ + public querying_against_timespan(DefaultStoreFixture fixture) : base(fixture) + { + } + + [Fact] + public async Task select_to_time_span() + { + var span = TimeSpan.Parse("-20154.01:12:32"); + + var targets = Target.GenerateRandomData(10).ToArray(); + var first = targets.First(); + await theStore.BulkInsertDocumentsAsync(targets); + + var results = await theSession.Query().Where(x => x.Id == first.Id).Select(x => x.HowLong) + .ToListAsync(); + results.Single().ShouldBe(first.HowLong); + } +} diff --git a/src/Marten.Testing/Documents/Target.cs b/src/Marten.Testing/Documents/Target.cs index 69abc7473b..e756413163 100644 --- a/src/Marten.Testing/Documents/Target.cs +++ b/src/Marten.Testing/Documents/Target.cs @@ -94,6 +94,8 @@ public static Target Random(bool deep = false) target.Double = _random.NextDouble(); target.Long = _random.Next() * 10000; + target.HowLong = TimeSpan.FromSeconds(target.Long); + target.Date = DateTime.Today.AddDays(_random.Next(-10000, 10000)); if (value > 15) @@ -185,6 +187,8 @@ public Target() public List StringList { get; set; } public Guid[] GuidArray { get; set; } + + public TimeSpan HowLong { get; set; } } public class Address diff --git a/src/Marten/Linq/Members/EnumAsIntegerMember.cs b/src/Marten/Linq/Members/EnumAsIntegerMember.cs index aa46481381..d63a587811 100644 --- a/src/Marten/Linq/Members/EnumAsIntegerMember.cs +++ b/src/Marten/Linq/Members/EnumAsIntegerMember.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using System.Linq.Expressions; using System.Reflection; using Marten.Exceptions; diff --git a/src/Marten/Linq/Selectors/TimeSpanSelector.cs b/src/Marten/Linq/Selectors/TimeSpanSelector.cs new file mode 100644 index 0000000000..a95f0c8c0a --- /dev/null +++ b/src/Marten/Linq/Selectors/TimeSpanSelector.cs @@ -0,0 +1,22 @@ +#nullable enable +using System; +using System.Data.Common; +using System.Threading; +using System.Threading.Tasks; + +namespace Marten.Linq.Selectors; + +internal class TimeSpanSelector: ISelector +{ + public TimeSpan Resolve(DbDataReader reader) + { + var text = reader.GetString(0); + return TimeSpan.Parse(text); + } + + public async Task ResolveAsync(DbDataReader reader, CancellationToken token) + { + var text = await reader.GetFieldValueAsync(0, token).ConfigureAwait(false); + return TimeSpan.Parse(text); + } +} diff --git a/src/Marten/Linq/SqlGeneration/DataSelectClause.cs b/src/Marten/Linq/SqlGeneration/DataSelectClause.cs index 92ead1dd27..e220378a9b 100644 --- a/src/Marten/Linq/SqlGeneration/DataSelectClause.cs +++ b/src/Marten/Linq/SqlGeneration/DataSelectClause.cs @@ -64,13 +64,15 @@ public string[] SelectFields() public ISelector BuildSelector(IMartenSession session) { + if (typeof(T) == typeof(TimeSpan)) return new TimeSpanSelector(); + return new SerializationSelector(session.Serializer); } public IQueryHandler BuildHandler(IMartenSession session, ISqlFragment statement, ISqlFragment currentStatement) { - var selector = new SerializationSelector(session.Serializer); + var selector = typeof(T) == typeof(TimeSpan) ? (ISelector)new TimeSpanSelector() : new SerializationSelector(session.Serializer); return LinqQueryParser.BuildHandler(selector, statement); }