Skip to content
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
1 change: 1 addition & 0 deletions src/DocumentDbTests/Indexes/computed_indexes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ index definition was executed in postgresql.

StoreOptions(_ =>
{
_.RegisterFSharpOptionValueTypes();
var columns = new Expression<Func<Target, object>>[]
{
x => x.FSharpDateOption,
Expand Down
3 changes: 3 additions & 0 deletions src/LinqTests/Acceptance/where_clauses_fsharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ static where_clauses_fsharp()
@where(x => x.FSharpIntOption == FSharpOption<int>.Some(300));
@where(x => x.FSharpStringOption == FSharpOption<string>.Some("My String"));
@where(x => x.FSharpLongOption == FSharpOption<long>.Some(5_000_000));
@where(x => x.FSharpTimeOnlyOption == FSharpOption<TimeOnly>.Some(new TimeOnly(5,10)));
@where(x => x.FSharpDateTimeOffsetOption == FSharpOption<DateTimeOffset>.Some(DateTimeOffset.UtcNow));
@where(x => x.FSharpDateOnlyOption == FSharpOption<DateOnly>.Some(new DateOnly(2008, 10, 10)));

//Comparing options is not a valid syntax in C#, we therefore define these expressions in F#
@where(FSharpTypes.greaterThanWithFsharpDateOption);
Expand Down
6 changes: 4 additions & 2 deletions src/Marten/Linq/Members/DateTimeOffsetMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using Marten.Linq.Parsing;
using Marten.Linq.SqlGeneration.Filters;
using Marten.Util;
using Weasel.Postgresql.SqlGeneration;
Expand All @@ -23,12 +24,13 @@ public override string SelectorForDuplication(string pgType)

public override ISqlFragment CreateComparison(string op, ConstantExpression constant)
{
if (constant.Value == null)
var unwrappedValue = constant.UnwrapValue();
if (unwrappedValue == null)
{
return op == "=" ? new IsNullFilter(this) : new IsNotNullFilter(this);
}

var value = (DateTimeOffset)constant.Value;
var value = (DateTimeOffset)unwrappedValue;

var def = new CommandParameter(value.ToUniversalTime());
return new MemberComparisonFilter(this, def, op);
Expand Down
5 changes: 3 additions & 2 deletions src/Marten/Linq/Members/QueryableMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,13 @@ public virtual string SelectorForDuplication(string pgType)

public virtual ISqlFragment CreateComparison(string op, ConstantExpression constant)
{
if (constant.Value == null)
var unwrappedValue = constant.UnwrapValue();
if (unwrappedValue == null)
{
return op == "=" ? new IsNullFilter(this) : new IsNotNullFilter(this);
}

var def = new CommandParameter(constant);
var def = new CommandParameter(Expression.Constant(unwrappedValue));
return new MemberComparisonFilter(this, def, op);
}
}
35 changes: 35 additions & 0 deletions src/Marten/Linq/Parsing/ConstantExpressionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#nullable enable
using System.Linq.Expressions;
using Microsoft.FSharp.Core;

namespace Marten.Linq.Parsing;

public static class ConstantExpressionExtensions
{
public static object? UnwrapValue(this ConstantExpression constant)
{
var value = constant.Value;

// If the value is null, it is either a C# null or FSharpOption.None.
// In either case, there is nothing to unwrap.
if (value == null)
{
return null;
}

var valueType = value.GetType();

// Check if it is an F# Option
// Note: FSharpOption is a class, not a struct.
if (valueType.IsGenericType &&
valueType.GetGenericTypeDefinition() == typeof(FSharpOption<>))
{
// If we are here, 'value' is not null, so it MUST be 'Some'.
// We can safely just grab the 'Value' property.
var valueProp = valueType.GetProperty("Value");
return valueProp?.GetValue(value);
}

return value;
}
}
16 changes: 16 additions & 0 deletions src/Marten/StoreOptions.MemberFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@ public bool TryResolve(IQueryableMember parent, StoreOptions options, MemberInfo
return false;
}

if (valueType.OuterType.IsGenericType
&& valueType.OuterType.GetGenericTypeDefinition() == typeof(FSharpOption<>)
&& isSpecialFSharpOptionDateType(valueType.SimpleType))
{
member = null;
return false;
}

Type baseType;
if (valueType.OuterType.IsGenericType && valueType.OuterType.GetGenericTypeDefinition() == typeof(FSharpOption<>))
{
Expand All @@ -170,4 +178,12 @@ public bool TryResolve(IQueryableMember parent, StoreOptions options, MemberInfo

return true;
}

private static bool isSpecialFSharpOptionDateType(Type simpleType)
{
return simpleType == typeof(DateTime)
|| simpleType == typeof(DateTimeOffset)
|| simpleType == typeof(DateOnly)
|| simpleType == typeof(TimeOnly);
}
}
Loading