Skip to content

Commit ba91a05

Browse files
committed
Fixed the != querying against nullable booleans. Closes GH-3953
1 parent 4bb30a2 commit ba91a05

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/LinqTests/Acceptance/nullable_types.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.Threading.Tasks;
4+
using Marten;
45
using Marten.Testing.Documents;
56
using Marten.Testing.Harness;
67
using Shouldly;
@@ -70,6 +71,50 @@ public async Task query_against_null_3()
7071
.ShouldBe(1);
7172
}
7273

74+
[Fact]
75+
public async Task query_against_nullable_bool_not_true()
76+
{
77+
var target1 = new Target { NullableBoolean = null };
78+
theSession.Store(target1);
79+
80+
var target2 = new Target { NullableBoolean = true };
81+
theSession.Store(target2);
82+
83+
var target3 = new Target { NullableBoolean = false };
84+
theSession.Store(target3);
85+
86+
await theSession.SaveChangesAsync();
87+
88+
theSession.Logger = new TestOutputMartenLogger(_output);
89+
90+
var list = await theSession.Query<Target>().Where(x => x.NullableBoolean != true).ToListAsync();
91+
list.Count.ShouldBe(2);
92+
list.Any(x => x.Id == target1.Id).ShouldBeTrue();
93+
list.Any(x => x.Id == target3.Id).ShouldBeTrue();
94+
}
95+
96+
[Fact]
97+
public async Task query_against_nullable_bool_not_false()
98+
{
99+
var target1 = new Target { NullableBoolean = null };
100+
theSession.Store(target1);
101+
102+
var target2 = new Target { NullableBoolean = true };
103+
theSession.Store(target2);
104+
105+
var target3 = new Target { NullableBoolean = false };
106+
theSession.Store(target3);
107+
108+
await theSession.SaveChangesAsync();
109+
110+
theSession.Logger = new TestOutputMartenLogger(_output);
111+
112+
var list = await theSession.Query<Target>().Where(x => x.NullableBoolean != false).ToListAsync();
113+
list.Count.ShouldBe(2);
114+
list.Any(x => x.Id == target1.Id).ShouldBeTrue();
115+
list.Any(x => x.Id == target2.Id).ShouldBeTrue();
116+
}
117+
73118
[Fact]
74119
public async Task query_against_null_4()
75120
{
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,49 @@
11
#nullable enable
2+
using System;
3+
using System.Linq.Expressions;
24
using System.Reflection;
5+
using JasperFx.Core.Reflection;
36
using Marten.Linq.SqlGeneration.Filters;
47
using Weasel.Postgresql.SqlGeneration;
58

69
namespace Marten.Linq.Members;
710

811
internal class BooleanMember: QueryableMember, IComparableMember, IBooleanMember
912
{
13+
private readonly bool _isNullable;
14+
1015
public BooleanMember(IQueryableMember parent, Casing casing, MemberInfo member, string pgType): base(parent,
1116
casing, member)
1217
{
1318
TypedLocator = $"CAST({RawLocator} as {pgType})";
19+
20+
_isNullable = member.GetRawMemberType().IsNullable();
1421
}
1522

1623
public ISqlFragment BuildIsTrueFragment()
1724
{
1825
return new BooleanFieldIsTrue(this);
1926
}
27+
28+
public override ISqlFragment CreateComparison(string op, ConstantExpression constant)
29+
{
30+
if (constant.Value == null)
31+
{
32+
return op == "=" ? new IsNullFilter(this) : new IsNotNullFilter(this);
33+
}
34+
35+
if (_isNullable && op == "!=")
36+
{
37+
if (constant.Value.Equals(true))
38+
{
39+
return CompoundWhereFragment.Or(new IsNullFilter(this), base.CreateComparison(op, constant));
40+
}
41+
else
42+
{
43+
return CompoundWhereFragment.Or(new IsNullFilter(this), base.CreateComparison(op, constant));
44+
}
45+
}
46+
47+
return base.CreateComparison(op, constant);
48+
}
2049
}

0 commit comments

Comments
 (0)