< Summary - Code Coverage

Information
Class: Plainquire.Sort.Swashbuckle.OpenApiOperationExtensions
Assembly: Plainquire.Sort.Swashbuckle
File(s): /home/runner/work/plainquire/plainquire/Plainquire.Sort/Plainquire.Sort.Swashbuckle/Extensions/OpenApiOperationExtensions.cs
Tag: 64_13932151703
Line coverage
100%
Covered lines: 74
Uncovered lines: 0
Coverable lines: 74
Total lines: 138
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage
100%
Covered methods: 8
Total methods: 8
Method coverage: 100%

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
ReplaceSortParameters(...)100%22100%
GroupByHttpQueryParameterName(...)100%11100%
MarkExistingParametersForDeletion(...)100%22100%
RemoveParametersMarkedForDeletion(...)100%22100%
GetSortPrefixes(...)100%11100%
CreatePropertyNamePattern(...)100%11100%
GetSortablePropertyNames(...)100%11100%
GetSortPropertyNames(...)100%11100%

File(s)

/home/runner/work/plainquire/plainquire/Plainquire.Sort/Plainquire.Sort.Swashbuckle/Extensions/OpenApiOperationExtensions.cs

#LineLine coverage
 1using Microsoft.OpenApi.Any;
 2using Microsoft.OpenApi.Interfaces;
 3using Microsoft.OpenApi.Models;
 4using Plainquire.Filter.Abstractions;
 5using Plainquire.Sort.Swashbuckle.Models;
 6using System;
 7using System.Collections.Generic;
 8using System.Linq;
 9using System.Reflection;
 10using System.Text.RegularExpressions;
 11
 12namespace Plainquire.Sort.Swashbuckle;
 13
 14/// <summary>
 15/// Extension methods for <see cref="OpenApiOperation"/>.
 16/// </summary>
 17public static class OpenApiOperationExtensions
 18{
 19    private const string ENTITY_SORT_EXTENSION = "x-entity-sort";
 20    private const string ENTITY_DELETE_EXTENSION = "x-entity-sort-delete";
 21
 22    /// <summary>
 23    /// Replaces <see cref="EntitySort{TEntity}"/> and with the sort parameters.
 24    /// </summary>
 25    /// <param name="operation">The <see cref="OpenApiOperation"/> to operate on.</param>
 26    /// <param name="parametersToReplace">The parameters to replace.</param>
 27    public static void ReplaceSortParameters(this OpenApiOperation operation, IList<SortParameterReplacement> parameters
 28    {
 5829        MarkExistingParametersForDeletion(parametersToReplace);
 30
 5831        var httpQueryParameterGroup = GroupByHttpQueryParameterName(parametersToReplace);
 19832        foreach (var (queryParameter, parameters) in httpQueryParameterGroup)
 33        {
 4134            var (prefixes, postfixes, primaryAscendingPostfix, primaryDescendingPostfix) = GetSortPrefixes(parameters);
 4135            var allowedPropertyNamePattern = CreatePropertyNamePattern(parameters, prefixes, postfixes);
 36
 4137            var openApiParameter = new OpenApiParameter
 4138            {
 4139                Name = queryParameter,
 4140                Description = $"Sorts the result by the given property in ascending ({primaryAscendingPostfix}) or desce
 4141                Schema = new OpenApiSchema
 4142                {
 4143                    Type = "array",
 4144                    Items = new OpenApiSchema
 4145                    {
 4146                        Type = "string",
 4147                        Example = new OpenApiString(string.Empty),
 4148                        Pattern = allowedPropertyNamePattern
 4149                    },
 4150                },
 4151                In = ParameterLocation.Query,
 4152                Extensions = new Dictionary<string, IOpenApiExtension>(StringComparer.Ordinal)
 4153                {
 4154                    [ENTITY_SORT_EXTENSION] = new OpenApiBoolean(true)
 4155                }
 4156            };
 57
 4158            var insertionIndex = operation.Parameters.IndexOf(parameters[0].OpenApiParameter);
 4159            operation.Parameters.Insert(insertionIndex, openApiParameter);
 60        }
 61
 5862        RemoveParametersMarkedForDeletion(operation);
 5863    }
 64
 65    private static Dictionary<string, List<SortParameterReplacement>> GroupByHttpQueryParameterName(IList<SortParameterR
 5866        => parametersToReplace
 5867            .GroupBy(parameter =>
 5868            {
 5869                var bindingParameterName = parameter.OpenApiDescription.ParameterDescriptor.BindingInfo?.BinderModelName
 5870                var actionParameterName = parameter.OpenApiDescription.ParameterDescriptor.Name;
 5871                return bindingParameterName ?? actionParameterName;
 5872            }, StringComparer.Ordinal)
 5873            .ToDictionary(
 5874                group => group.Key,
 5875                group => group.ToList(),
 5876                StringComparer.Ordinal
 5877            );
 78
 79    private static void MarkExistingParametersForDeletion(IList<SortParameterReplacement> parameters)
 80    {
 26681        foreach (var parameter in parameters)
 7582            parameter.OpenApiParameter.Extensions.TryAdd(ENTITY_DELETE_EXTENSION, new OpenApiBoolean(true));
 5883    }
 84
 85    private static void RemoveParametersMarkedForDeletion(OpenApiOperation operation)
 86    {
 5887        var parametersToRemove = operation.Parameters
 5888            .Where(parameter => parameter.Extensions.ContainsKey(ENTITY_DELETE_EXTENSION))
 5889            .ToList();
 90
 24691        foreach (var parameter in parametersToRemove)
 6592            operation.Parameters.Remove(parameter);
 5893    }
 94
 95    private static (List<string>, List<string>, string, string) GetSortPrefixes(IReadOnlyCollection<SortParameterReplace
 96    {
 4197        var ascendingPrefixes = parameters.Select(parameter => parameter.Configuration.AscendingPrefixes).SelectMany(x =
 4198        var descendingPrefixes = parameters.Select(parameter => parameter.Configuration.DescendingPrefixes).SelectMany(x
 4199        var ascendingPostfixes = parameters.Select(parameter => parameter.Configuration.AscendingPostfixes).SelectMany(x
 41100        var descendingPostfixes = parameters.Select(parameter => parameter.Configuration.DescendingPostfixes).SelectMany
 101
 41102        var prefixes = ascendingPrefixes.Concat(descendingPrefixes).Distinct(StringComparer.OrdinalIgnoreCase).Select(Re
 41103        var postfixes = ascendingPostfixes.Concat(descendingPostfixes).Distinct(StringComparer.OrdinalIgnoreCase).Select
 104
 41105        var primaryAscendingPostfix = ascendingPostfixes[0];
 41106        var primaryDescendingPostfix = descendingPostfixes[0];
 107
 41108        return (prefixes, postfixes, primaryAscendingPostfix, primaryDescendingPostfix);
 109    }
 110
 111    private static string CreatePropertyNamePattern(IEnumerable<SortParameterReplacement> parameters, IEnumerable<string
 112    {
 41113        var sortablePropertyNames = GetSortablePropertyNames(parameters);
 114
 41115        var allowedPropertyNamePattern = $"^({string.Join("|", prefixes)})?({string.Join("|", sortablePropertyNames)})(\
 41116        return allowedPropertyNamePattern;
 117    }
 118
 119    private static List<string> GetSortablePropertyNames(IEnumerable<SortParameterReplacement> parameters)
 41120        => parameters
 41121            .Select(parameter => parameter.SortedType)
 41122            .SelectMany(sortedType => sortedType.GetSortPropertyNames())
 41123            .Distinct(StringComparer.Ordinal)
 41124            .Select(Regex.Escape)
 41125            .ToList();
 126
 127    private static List<string> GetSortPropertyNames(this Type sortedType)
 128    {
 75129        var entityFilterAttribute = sortedType.GetCustomAttribute<EntityFilterAttribute>();
 130
 75131        var sortableProperties = sortedType
 75132            .GetSortableProperties()
 75133            .Select(property => property.GetSortParameterName(entityFilterAttribute?.Prefix))
 75134            .ToList();
 135
 75136        return sortableProperties;
 137    }
 138}