Skip to content

Commit 4ff507c

Browse files
authored
fix: filtering by guid on collections
Fixes #51
2 parents fbc4418 + 2203396 commit 4ff507c

2 files changed

Lines changed: 55 additions & 13 deletions

File tree

QueryKit.IntegrationTests/Tests/DatabaseFilteringTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,27 @@ public async Task can_filter_within_collection_long()
366366
recipes[0].Id.Should().Be(fakeRecipeOne.Id);
367367
}
368368

369+
[Fact]
370+
public async Task can_filter_by_guid_for_collection()
371+
{
372+
var testingServiceScope = new TestingServiceScope();
373+
var fakeRecipeOne = new FakeRecipeBuilder().Build();
374+
var ingredient = new FakeIngredientBuilder()
375+
.Build();
376+
377+
fakeRecipeOne.AddIngredient(ingredient);
378+
379+
await testingServiceScope.InsertAsync(fakeRecipeOne);
380+
381+
var input = $""" Ingredients.Id == "{ingredient.Id}" """;
382+
var queryableRecipes = testingServiceScope.DbContext().Recipes;
383+
var appliedQueryable = queryableRecipes.ApplyQueryKitFilter(input);
384+
var recipes = await appliedQueryable.ToListAsync();
385+
386+
recipes.Count.Should().Be(1);
387+
recipes[0].Ingredients.First().Id.Should().Be(ingredient.Id);
388+
}
389+
369390
[Fact(Skip = "Can not handle nested collections yet.")]
370391
public async Task can_filter_by_string_for_nested_collection()
371392
{

QueryKit/FilterParser.cs

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -430,20 +430,11 @@ private static Parser<Expression> ComparisonExprParser<T>(ParameterExpression pa
430430

431431
if (temp.leftExpr.Type == typeof(Guid) || temp.leftExpr.Type == typeof(Guid?))
432432
{
433-
var toStringMethod = typeof(Guid).GetMethod("ToString", Type.EmptyTypes);
434-
435-
Expression leftExpr = temp.leftExpr.Type == typeof(Guid?) ?
436-
Expression.Condition(
437-
Expression.Property(temp.leftExpr, "HasValue"),
438-
Expression.Call(Expression.Property(temp.leftExpr, "Value"), toStringMethod!),
439-
Expression.Constant(null, typeof(string))
440-
) :
441-
Expression.Call(temp.leftExpr, toStringMethod!);
442-
443-
return temp.op.GetExpression<T>(leftExpr, CreateRightExpr(temp.leftExpr, temp.right, temp.op), config?.DbContextType);
433+
var guidStringExpr = HandleGuidConversion(temp.leftExpr, temp.leftExpr.Type);
434+
return temp.op.GetExpression<T>(guidStringExpr, CreateRightExpr(temp.leftExpr, temp.right, temp.op),
435+
config?.DbContextType);
444436
}
445437

446-
447438
var rightExpr = CreateRightExpr(temp.leftExpr, temp.right, temp.op);
448439
return temp.op.GetExpression<T>(temp.leftExpr, rightExpr, config?.DbContextType);
449440
});
@@ -495,8 +486,9 @@ private static Parser<Expression> ComparisonExprParser<T>(ParameterExpression pa
495486
var propertyInfoForMethod = GetPropertyInfo(genericArgType, propName);
496487
var lambdaBody = Expression.PropertyOrField(innerParameter, propertyInfoForMethod.Name);
497488
var selectLambda = Expression.Lambda(lambdaBody, innerParameter);
489+
var selectResult = Expression.Call(null, selectMethod, member, selectLambda);
498490

499-
return Expression.Call(null, selectMethod, member, selectLambda);
491+
return HandleGuidConversion(selectResult, propertyType, "Select");
500492
}
501493
}
502494
}
@@ -582,6 +574,35 @@ private static Parser<Expression> OrExprParser<T>(ParameterExpression parameter,
582574
AndExprParser<T>(parameter, config),
583575
(op, left, right) => op.GetExpression<T>(left, right)
584576
);
577+
578+
private static Expression GetGuidToStringExpression(Expression leftExpr)
579+
{
580+
var toStringMethod = typeof(Guid).GetMethod("ToString", Type.EmptyTypes);
581+
582+
return leftExpr.Type == typeof(Guid?) ?
583+
Expression.Condition(
584+
Expression.Property(leftExpr, "HasValue"),
585+
Expression.Call(Expression.Property(leftExpr, "Value"), toStringMethod!),
586+
Expression.Constant(null, typeof(string))
587+
) :
588+
Expression.Call(leftExpr, toStringMethod!);
589+
}
590+
591+
private static Expression HandleGuidConversion(Expression expression, Type propertyType, string? selectMethodName = null)
592+
{
593+
if (propertyType != typeof(Guid) && propertyType != typeof(Guid?)) return expression;
594+
595+
if (string.IsNullOrWhiteSpace(selectMethodName)) return GetGuidToStringExpression(expression);
596+
597+
var selectMethod = typeof(Enumerable).GetMethods()
598+
.First(m => m.Name == selectMethodName && m.GetParameters().Length == 2)
599+
.MakeGenericMethod(propertyType, typeof(string));
600+
601+
var param = Expression.Parameter(propertyType, "g");
602+
var toStringLambda = Expression.Lambda(GetGuidToStringExpression(param), param);
603+
604+
return Expression.Call(selectMethod, expression, toStringLambda);
605+
}
585606
}
586607

587608

0 commit comments

Comments
 (0)