< Summary - Code Coverage

Information
Class: Plainquire.Filter.ValueFilter
Assembly: Plainquire.Filter
File(s): /home/runner/work/plainquire/plainquire/Plainquire.Filter/Plainquire.Filter/Filters/ValueFilter.cs
Tag: 64_13932151703
Line coverage
92%
Covered lines: 50
Uncovered lines: 4
Coverable lines: 54
Total lines: 152
Line coverage: 92.5%
Branch coverage
88%
Covered branches: 37
Total branches: 42
Branch coverage: 88%
Method coverage
88%
Covered methods: 8
Total methods: 9
Method coverage: 88.8%

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%11100%
Create(...)100%88100%
Create(...)50%4475%
Create(...)100%110%
Create(...)100%11100%
ToString()87.5%8880%
ValueToFilterString(...)90%1010100%
ExtractFilterOperator(...)87.5%8893.33%

File(s)

/home/runner/work/plainquire/plainquire/Plainquire.Filter/Plainquire.Filter/Filters/ValueFilter.cs

#LineLine coverage
 1using Plainquire.Filter.Abstractions;
 2using System;
 3using System.Diagnostics;
 4using System.Diagnostics.CodeAnalysis;
 5using System.Linq;
 6using System.Text.RegularExpressions;
 7
 8namespace Plainquire.Filter;
 9
 10/// <summary>
 11/// Defines a single filter.
 12/// </summary>
 13[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "Provided as library, can be used from outside")]
 14[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
 15public class ValueFilter
 16{
 17    private FilterConfiguration? _configuration;
 18
 19    /// <summary>
 20    /// Gets the filter operator. See <see cref="Operator"/> for details.
 21    /// </summary>
 22    public FilterOperator Operator { get; private set; }
 23
 24    /// <summary>
 25    /// JSON or Chronic representation of the value to filter for. Unused, if <see cref="Operator"/> is <see cref="Filte
 26    /// </summary>
 27    public string? Value { get; private set; }
 28
 29    /// <summary>
 30    /// Indicates whether this filter is empty.
 31    /// </summary>
 1823232    public bool IsEmpty => Operator != FilterOperator.IsNull && Operator != FilterOperator.NotNull && Value == null;
 33
 1765334    private ValueFilter() { }
 35
 36    /// <summary>
 37    /// Creates the specified filter
 38    /// </summary>
 39    /// <typeparam name="TValue">The type of the value.</typeparam>
 40    /// <param name="filterOperator">The filter operator.</param>
 41    /// <param name="value">The value to filter for. Unused, if <paramref name="filterOperator"/> is <see cref="FilterOp
 42    /// <param name="configuration">The filter configuration to use.</param>
 43    public static ValueFilter Create<TValue>(FilterOperator filterOperator, TValue? value, FilterConfiguration? configur
 44    {
 1765545        var isNullableFilterOperator = filterOperator is FilterOperator.IsNull or FilterOperator.NotNull;
 1765546        if (isNullableFilterOperator)
 87247            value = default;
 1678348        else if (value == null)
 149            throw new ArgumentException($"Filter values cannot be null. If filtering for NULL is intended, use filter op
 1678250        else if (!typeof(TValue).IsFilterableProperty())
 151            throw new ArgumentException($"The type '{typeof(TValue)}' is not filterable by any known expression creator"
 52
 1765353        return new ValueFilter
 1765354        {
 1765355            Operator = filterOperator,
 1765356            Value = ValueToFilterString(value),
 1765357            _configuration = configuration
 1765358        };
 59    }
 60
 61    /// <summary>
 62    /// Creates the specified filter
 63    /// </summary>
 64    /// <param name="filterOperator">The filter operator.</param>
 65    /// <param name="configuration">The filter configuration to use.</param>
 66    public static ValueFilter Create(FilterOperator filterOperator, FilterConfiguration? configuration = null)
 67    {
 1268        var isNullableFilterOperator = filterOperator is FilterOperator.IsNull or FilterOperator.NotNull;
 1269        if (!isNullableFilterOperator)
 070            throw new InvalidOperationException("A value is required for operators other than NULL/NOT NULL.");
 71
 1272        return Create<object>(filterOperator, null, configuration);
 73    }
 74
 75    /// <summary>
 76    /// Creates the specified filter using the default operator.
 77    /// </summary>
 78    /// <typeparam name="TValue">The type of the value.</typeparam>
 79    /// <param name="value">The value to filter for.</param>
 80    /// <param name="configuration">The filter configuration to use.</param>
 81    public static ValueFilter Create<TValue>(TValue value, FilterConfiguration? configuration = null)
 082        => Create(FilterOperator.Default, value, configuration);
 83
 84    /// <summary>
 85    /// Creates the specified filter.
 86    /// </summary>
 87    /// <param name="filterSyntax">The filter micro syntax to create the filter from.</param>
 88    /// <param name="configuration">The filter configuration to use.</param>
 89    public static ValueFilter Create(string? filterSyntax, FilterConfiguration? configuration = null)
 90    {
 712791        var (filterOperator, value) = ExtractFilterOperator(filterSyntax, configuration);
 712792        return Create(filterOperator, value, configuration);
 93    }
 94
 95    /// <inheritdoc />
 96    public override string? ToString()
 97    {
 998        var configuration = _configuration ?? FilterConfiguration.Default ?? new FilterConfiguration();
 999        var operatorSyntax = configuration.FilterOperatorMap.FirstOrDefault(x => x.Value == Operator).Key;
 9100        if (string.IsNullOrEmpty(operatorSyntax) && Value == null)
 0101            return null;
 102
 9103        return operatorSyntax + Value;
 104    }
 105
 106    private static string ValueToFilterString(object? value)
 107    {
 17653108        var result = value switch
 17653109        {
 772110            null => string.Empty,
 188111            DateTime dateTime => dateTime.ToString("o"),
 17653112#if NET6_0_OR_GREATER
 180113            DateOnly date => date.ToString("o"),
 17653114            //DateOnly date => date.ToString("yyyy-MM-dd"),
 17653115#endif
 396116            DateTimeOffset dateTime => dateTime.ToString("o"),
 16117117            _ => value.ToString() ?? string.Empty
 17653118        };
 119
 17653120        return result;
 121    }
 122
 123    private static (FilterOperator, string?) ExtractFilterOperator(string? filter, FilterConfiguration? configuration)
 124    {
 7127125        configuration ??= FilterConfiguration.Default ?? new FilterConfiguration();
 126
 7127127        if (filter == null)
 0128            return (FilterOperator.Default, null);
 129
 7127130        var trimmedFilter = filter.TrimStart();
 131
 7127132        var (filterSyntax, filterOperator) = configuration
 7127133            .FilterOperatorMap
 7127134            .OrderByDescending(x => x.Key.Length)
 7127135            .FirstOrDefault(x => trimmedFilter.StartsWith(x.Key, StringComparison.Ordinal));
 136
 7127137        var hasFilterOperator = !string.IsNullOrEmpty(filterSyntax);
 7127138        filter = hasFilterOperator ? trimmedFilter : filter;
 139
 7127140        var filterValue = filter[filterSyntax.Length..];
 141
 7127142        var escapeEscapeCharacter = Regex.Escape(configuration.EscapeCharacter.ToString());
 7127143        var escapedCharClass = @$"(?<!{escapeEscapeCharacter}){escapeEscapeCharacter}(.)";
 7127144        filterValue = Regex.Replace(filterValue, escapedCharClass, "$1", RegexOptions.None, RegexDefaults.Timeout);
 145
 7127146        return (filterOperator, filterValue);
 147    }
 148
 149    [ExcludeFromCodeCoverage]
 150    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 151    private string? DebuggerDisplay => ToString();
 152}