From 23c42c2a44a14d9edf1265adff74e1ee380e86ec Mon Sep 17 00:00:00 2001 From: "elrhomari.younes" Date: Tue, 1 Aug 2023 23:39:26 +0100 Subject: [PATCH] Fix Where clause with enum supabase-community/supabase-csharp#66 --- Postgrest/Linq/WhereExpressionVisitor.cs | 28 ++++++++++++++++++++---- PostgrestTests/LinqTests.cs | 15 +++++++++++++ PostgrestTests/Models/LinkedModels.cs | 8 +++++++ PostgrestTests/db/00-schema.sql | 3 ++- PostgrestTests/db/01-dummy-data.sql | 12 +++++----- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Postgrest/Linq/WhereExpressionVisitor.cs b/Postgrest/Linq/WhereExpressionVisitor.cs index 45aadec..1f7487f 100644 --- a/Postgrest/Linq/WhereExpressionVisitor.cs +++ b/Postgrest/Linq/WhereExpressionVisitor.cs @@ -59,7 +59,15 @@ protected override Expression VisitBinary(BinaryExpression node) var left = Visit(node.Left); var right = Visit(node.Right); - var column = left is MemberExpression leftMember ? GetColumnFromMemberExpression(leftMember) : null; + string? column = null; + if (left is MemberExpression leftMember) + { + column = GetColumnFromMemberExpression(leftMember); + }//To handle properly if it's a Convert ExpressionType generally with nullable properties + else if (left is UnaryExpression leftUnary && leftUnary.NodeType == ExpressionType.Convert && leftUnary.Operand is MemberExpression leftOperandMember) + { + column = GetColumnFromMemberExpression(leftOperandMember); + } if (column == null) throw new ArgumentException($"Left side of expression: '{node}' is expected to be property with a ColumnAttribute or PrimaryKeyAttribute"); @@ -129,7 +137,15 @@ protected override Expression VisitMethodCall(MethodCallExpression node) /// private void HandleConstantExpression(string column, Operator op, ConstantExpression constantExpression) { - Filter = new QueryFilter(column, op, constantExpression.Value); + if (constantExpression.Type.IsEnum) + { + var enumValue = constantExpression.Value; + Filter = new QueryFilter(column, op, enumValue); + } + else + { + Filter = new QueryFilter(column, op, constantExpression.Value); + } } /// @@ -140,8 +156,8 @@ private void HandleConstantExpression(string column, Operator op, ConstantExpres /// private void HandleMemberExpression(string column, Operator op, MemberExpression memberExpression) { - Filter = new QueryFilter(column, op, GetMemberExpressionValue(memberExpression)); - } + Filter = new QueryFilter(column, op, GetMemberExpressionValue(memberExpression)); + } /// /// A unary expression parser (i.e. => x.Id == 1 <- where both `1` is considered unary) @@ -192,6 +208,10 @@ private void HandleNewExpression(string column, Operator op, NewExpression newEx { Filter = new QueryFilter(column, op, guid.ToString()); } + else if (instance.GetType().IsEnum) + { + Filter = new QueryFilter(column, op, instance); + } } /// diff --git a/PostgrestTests/LinqTests.cs b/PostgrestTests/LinqTests.cs index ac262fd..7d73ecb 100644 --- a/PostgrestTests/LinqTests.cs +++ b/PostgrestTests/LinqTests.cs @@ -98,6 +98,21 @@ public async Task TestLinqWhere() foreach (var q in query7.Models) Assert.IsNotNull(q.DateTimeValue); + //Testing where condition with Enum as constant + var query8 = await client.Table() + .Where(x => x.Status == MovieStatus.OnDisplay) + .Get(); + foreach (var q in query8.Models) + Assert.IsTrue(q.Status == MovieStatus.OnDisplay); + + //Test where condition with Enum as Memeber expression + var testMovie = new Movie { Status = MovieStatus.OnDisplay }; + var query9 = await client.Table() + .Where(x => x.Status == testMovie.Status) + .Get(); + foreach (var q in query9.Models) + Assert.IsTrue(q.Status == MovieStatus.OnDisplay); + await client.Table() .Where(x => x.DateTimeValue == DateTime.Now) .Get(); diff --git a/PostgrestTests/Models/LinkedModels.cs b/PostgrestTests/Models/LinkedModels.cs index 4ff9d7a..b9ddd64 100644 --- a/PostgrestTests/Models/LinkedModels.cs +++ b/PostgrestTests/Models/LinkedModels.cs @@ -12,12 +12,20 @@ public class Movie : BaseModel [Column("name")] public string? Name { get; set; } + [Column("status")] public MovieStatus? Status { get; set; } + [Reference(typeof(Person), ReferenceAttribute.JoinType.Left)] public List People { get; set; } = new(); [Column("created_at")] public DateTime CreatedAt { get; set; } } +public enum MovieStatus +{ + OnDisplay, + OffDisplay +} + [Table("person")] public class Person : BaseModel { diff --git a/PostgrestTests/db/00-schema.sql b/PostgrestTests/db/00-schema.sql index a554cd0..276e889 100644 --- a/PostgrestTests/db/00-schema.sql +++ b/PostgrestTests/db/00-schema.sql @@ -75,7 +75,8 @@ CREATE TABLE public.movie ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, created_at timestamp without time zone NOT NULL DEFAULT now(), - name character varying(255) NULL + name character varying(255) NULL, + status character varying(255) NULL ); CREATE TABLE public.person diff --git a/PostgrestTests/db/01-dummy-data.sql b/PostgrestTests/db/01-dummy-data.sql index ac378f1..4ffad80 100644 --- a/PostgrestTests/db/01-dummy-data.sql +++ b/PostgrestTests/db/01-dummy-data.sql @@ -53,12 +53,12 @@ VALUES ('f3ff356d-5803-43a7-b125-ba10cf10fdcd', '[20,50]'::int4range); -insert into "public"."movie" ("created_at", "id", "name") -values ('2022-08-20 00:29:45.400188', 'ea07bd86-a507-4c68-9545-b848bfe74c90', 'Top Gun: Maverick'); -insert into "public"."movie" ("created_at", "id", "name") -values ('2022-08-22 00:29:45.400188', 'a972a8f6-2e23-4172-be8d-7b65470ca0f4', 'Mad Max: Fury Road'); -insert into "public"."movie" ("created_at", "id", "name") -values ('2022-08-28 00:29:45.400188', '42fd15b1-3bff-431d-9fa5-314289beb246', 'Guns Away'); +insert into "public"."movie" ("created_at", "id", "name", "status") +values ('2022-08-20 00:29:45.400188', 'ea07bd86-a507-4c68-9545-b848bfe74c90', 'Top Gun: Maverick', 'OnDisplay'); +insert into "public"."movie" ("created_at", "id", "name", "status") +values ('2022-08-22 00:29:45.400188', 'a972a8f6-2e23-4172-be8d-7b65470ca0f4', 'Mad Max: Fury Road', 'OnDisplay'); +insert into "public"."movie" ("created_at", "id", "name", "status") +values ('2022-08-28 00:29:45.400188', '42fd15b1-3bff-431d-9fa5-314289beb246', 'Guns Away', 'OffDisplay'); insert into "public"."person" ("created_at", "first_name", "id", "last_name")