diff --git a/packages/Postgrest/Postgrest.Tests/Linq/WhereClauseTests.cs b/packages/Postgrest/Postgrest.Tests/Linq/WhereClauseTests.cs index c3197417..718d7af0 100644 --- a/packages/Postgrest/Postgrest.Tests/Linq/WhereClauseTests.cs +++ b/packages/Postgrest/Postgrest.Tests/Linq/WhereClauseTests.cs @@ -164,6 +164,20 @@ public void Where_ShouldTranslateNegatedBooleanMemberIntoNotEqTrue() .GenerateUrl().Should().Be($"{BaseUrl}/kitchen_sink?bool_value=not.eq.True"); } + [TestMethod] + public void Where_ShouldUseColumnName_GivenBareNullableBooleanValueMember() + { + this.client.Table().Where(x => x.IsActive!.Value) + .GenerateUrl().Should().Be($"{BaseUrl}/nullable_flag?is_active=eq.True"); + } + + [TestMethod] + public void Where_ShouldUseColumnName_GivenNegatedNullableBooleanValueMember() + { + this.client.Table().Where(x => !x.IsActive!.Value) + .GenerateUrl().Should().Be($"{BaseUrl}/nullable_flag?is_active=not.eq.True"); + } + [TestMethod] public void Where_ShouldNestBooleanMember_GivenAnAndPredicate() { diff --git a/packages/Postgrest/Postgrest.Tests/Models/NullableFlag.cs b/packages/Postgrest/Postgrest.Tests/Models/NullableFlag.cs new file mode 100644 index 00000000..0318fb42 --- /dev/null +++ b/packages/Postgrest/Postgrest.Tests/Models/NullableFlag.cs @@ -0,0 +1,18 @@ +#nullable enable +using Supabase.Postgrest.Attributes; +using Supabase.Postgrest.Models; + +namespace Postgrest.Tests.Models; + +/// +/// A model with a nullable boolean column, used to assert that a bare `Nullable<bool>.Value` +/// predicate (i.e. `x => x.IsActive!.Value`) resolves to the mapped column rather than `Value`. +/// URL-generation only; it is not backed by a seeded table. +/// +[Table("nullable_flag")] +public class NullableFlag : BaseModel +{ + [PrimaryKey("id")] public int? Id { get; set; } + + [Column("is_active")] public bool? IsActive { get; set; } +} diff --git a/packages/Postgrest/Postgrest/Linq/WhereExpressionVisitor.cs b/packages/Postgrest/Postgrest/Linq/WhereExpressionVisitor.cs index bc23a702..c245e924 100644 --- a/packages/Postgrest/Postgrest/Linq/WhereExpressionVisitor.cs +++ b/packages/Postgrest/Postgrest/Linq/WhereExpressionVisitor.cs @@ -182,8 +182,9 @@ protected override Expression VisitConditional(ConditionalExpression node) => Expression.AndAlso(Expression.Not(node.Test), node.IfFalse))); /// - /// Handles a boolean column used directly as a predicate (i.e. `x => x.IsActive`, or negated via - /// `x => !x.IsActive`), translating it into a `column.eq.true` filter. + /// Handles a boolean column used directly as a predicate (i.e. `x => x.IsActive`, its nullable + /// `x => x.IsActive!.Value` form, or negated via `x => !x.IsActive`), + /// translating it into a `column.eq.true` filter. /// /// /// @@ -192,7 +193,9 @@ protected override Expression VisitMember(MemberExpression node) if (node.Type != typeof(bool) || !this.ContainsParameter(node)) return base.VisitMember(node); - this.Filter = new QueryFilter(this.GetColumnFromMemberExpression(node), Operator.Equals, true); + var column = this.ResolveColumn(node) ?? throw new ArgumentException( + $"Expression: '{node}' is expected to be property with a ColumnAttribute or PrimaryKeyAttribute"); + this.Filter = new QueryFilter(column, Operator.Equals, true); return node; }