< 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: 66_15485642072
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>
 1823532    public bool IsEmpty => Operator != FilterOperator.IsNull && Operator != FilterOperator.NotNull && Value == null;
 33
 1766034    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    {
 1766245        var isNullableFilterOperator = filterOperator is FilterOperator.IsNull or FilterOperator.NotNull;
 1766246        if (isNullableFilterOperator)
 87247            value = default;
 1679048        else if (value == null)
 149            throw new ArgumentException($"Filter values cannot be null. If filtering for NULL is intended, use filter op
 1678950        else if (!typeof(TValue).IsFilterableProperty())
 151            throw new ArgumentException($"The type '{typeof(TValue)}' is not filterable by any known expression creator"
 52
 1766053        return new ValueFilter
 1766054        {
 1766055            Operator = filterOperator,
 1766056            Value = ValueToFilterString(value),
 1766057            _configuration = configuration
 1766058        };
 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    {
 713291        var (filterOperator, value) = ExtractFilterOperator(filterSyntax, configuration);
 713292        return Create(filterOperator, value, configuration);
 93    }
 94
 95    /// <inheritdoc />
 96    public override string? ToString()
 97    {
 1298        var configuration = _configuration ?? FilterConfiguration.Default ?? new FilterConfiguration();
 1299        var operatorSyntax = configuration.FilterOperatorMap.FirstOrDefault(x => x.Value == Operator).Key;
 12100        if (string.IsNullOrEmpty(operatorSyntax) && Value == null)
 0101            return null;
 102
 12103        return operatorSyntax + Value;
 104    }
 105
 106    private static string ValueToFilterString(object? value)
 107    {
 17660108        var result = value switch
 17660109        {
 772110            null => string.Empty,
 188111            DateTime dateTime => dateTime.ToString("o"),
 17660112#if NET6_0_OR_GREATER
 180113            DateOnly date => date.ToString("o"),
 17660114            //DateOnly date => date.ToString("yyyy-MM-dd"),
 17660115#endif
 396116            DateTimeOffset dateTime => dateTime.ToString("o"),
 16124117            _ => value.ToString() ?? string.Empty
 17660118        };
 119
 17660120        return result;
 121    }
 122
 123    private static (FilterOperator, string?) ExtractFilterOperator(string? filter, FilterConfiguration? configuration)
 124    {
 7132125        configuration ??= FilterConfiguration.Default ?? new FilterConfiguration();
 126
 7132127        if (filter == null)
 0128            return (FilterOperator.Default, null);
 129
 7132130        var trimmedFilter = filter.TrimStart();
 131
 7132132        var (filterSyntax, filterOperator) = configuration
 7132133            .FilterOperatorMap
 7132134            .OrderByDescending(x => x.Key.Length)
 7132135            .FirstOrDefault(x => trimmedFilter.StartsWith(x.Key, StringComparison.Ordinal));
 136
 7132137        var hasFilterOperator = !string.IsNullOrEmpty(filterSyntax);
 7132138        filter = hasFilterOperator ? trimmedFilter : filter;
 139
 7132140        var filterValue = filter[filterSyntax.Length..];
 141
 7132142        var escapeEscapeCharacter = Regex.Escape(configuration.EscapeCharacter.ToString());
 7132143        var escapedCharClass = @$"(?<!{escapeEscapeCharacter}){escapeEscapeCharacter}(.)";
 7132144        filterValue = Regex.Replace(filterValue, escapedCharClass, "$1", RegexOptions.None, RegexDefaults.Timeout);
 145
 7132146        return (filterOperator, filterValue);
 147    }
 148
 149    [ExcludeFromCodeCoverage]
 150    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 151    private string? DebuggerDisplay => ToString();
 152}