< Summary

Information
Class: Pozitron.QuerySpecification.IncludeEvaluator
Assembly: Pozitron.QuerySpecification.EntityFrameworkCore
File(s): /home/runner/work/QuerySpecification/QuerySpecification/src/QuerySpecification.EntityFrameworkCore/Evaluators/IncludeEvaluator.cs
Tag: 44_11195777782
Line coverage
100%
Covered lines: 44
Uncovered lines: 0
Coverable lines: 44
Total lines: 96
Line coverage: 100%
Branch coverage
100%
Covered branches: 36
Total branches: 36
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%2222100%
.ctor()100%11100%
Evaluate(...)100%88100%
BuildInclude(...)100%11100%
BuildThenInclude(...)100%22100%
IsGenericEnumerable(...)100%44100%

File(s)

/home/runner/work/QuerySpecification/QuerySpecification/src/QuerySpecification.EntityFrameworkCore/Evaluators/IncludeEvaluator.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore.Query;
 2using System.Diagnostics;
 3using System.Reflection;
 4
 5namespace Pozitron.QuerySpecification;
 6
 7public class IncludeEvaluator : IEvaluator
 8{
 19    private static readonly MethodInfo _includeMethodInfo = typeof(EntityFrameworkQueryableExtensions)
 110        .GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.Include))
 311        .Single(mi => mi.IsPublic && mi.GetGenericArguments().Length == 2
 312            && mi.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
 313            && mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>));
 14
 115    private static readonly MethodInfo _thenIncludeAfterReferenceMethodInfo
 116        = typeof(EntityFrameworkQueryableExtensions)
 117            .GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.ThenInclude))
 318            .Single(mi => mi.IsPublic && mi.GetGenericArguments().Length == 3
 319                && mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter
 320                && mi.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IIncludableQueryable<,>)
 321                && mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>));
 22
 123    private static readonly MethodInfo _thenIncludeAfterEnumerableMethodInfo
 124        = typeof(EntityFrameworkQueryableExtensions)
 125            .GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.ThenInclude))
 326            .Single(mi => mi.IsPublic && mi.GetGenericArguments().Length == 3
 327                && !mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter
 328                && mi.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IIncludableQueryable<,>)
 329                && mi.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>));
 30
 231    private IncludeEvaluator() { }
 132    public static IncludeEvaluator Instance = new();
 33
 34    public IQueryable<T> Evaluate<T>(IQueryable<T> source, Specification<T> specification) where T : class
 35    {
 12036        foreach (var includeString in specification.IncludeStrings)
 37        {
 938            source = source.Include(includeString);
 39        }
 40
 22041        foreach (var includeExpression in specification.IncludeExpressions)
 42        {
 5943            if (includeExpression.Type == IncludeTypeEnum.Include)
 44            {
 2745                source = BuildInclude<T>(source, includeExpression);
 46            }
 3247            else if (includeExpression.Type == IncludeTypeEnum.ThenInclude)
 48            {
 3249                source = BuildThenInclude<T>(source, includeExpression);
 50            }
 51        }
 52
 5153        return source;
 54    }
 55
 56    private static IQueryable<T> BuildInclude<T>(IQueryable source, IncludeExpression includeExpression)
 57    {
 58        Debug.Assert(includeExpression is not null);
 59
 2760        var result = _includeMethodInfo
 2761            .MakeGenericMethod(includeExpression.EntityType, includeExpression.PropertyType)
 2762            .Invoke(null, [source, includeExpression.LambdaExpression]);
 63
 64        Debug.Assert(result is not null);
 65
 2766        return (IQueryable<T>)result;
 67    }
 68
 69    private static IQueryable<T> BuildThenInclude<T>(IQueryable source, IncludeExpression includeExpression)
 70    {
 71        Debug.Assert(includeExpression is not null);
 72        Debug.Assert(includeExpression.PreviousPropertyType is not null);
 73
 3274        var result = (IsGenericEnumerable(includeExpression.PreviousPropertyType, out var previousPropertyType)
 3275                            ? _thenIncludeAfterEnumerableMethodInfo
 3276                            : _thenIncludeAfterReferenceMethodInfo)
 3277            .MakeGenericMethod(includeExpression.EntityType, previousPropertyType, includeExpression.PropertyType)
 3278            .Invoke(null, [source, includeExpression.LambdaExpression]);
 79
 80        Debug.Assert(result is not null);
 81
 3282        return (IQueryable<T>)result;
 83    }
 84
 85    private static bool IsGenericEnumerable(Type type, out Type propertyType)
 86    {
 3287        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
 88        {
 1789            propertyType = type.GenericTypeArguments[0];
 1790            return true;
 91        }
 92
 1593        propertyType = type;
 1594        return false;
 95    }
 96}