< Summary

Information
Class: MyNet.UI.ViewModels.List.Filtering.Filters.CollectionContainsFilterViewModel<T1, T2>
Assembly: MyNet.UI
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/List/Filtering/Filters/CollectionContainsFilterViewModel.cs
Tag: 323_28699572109
Line coverage
0%
Covered lines: 0
Uncovered lines: 21
Coverable lines: 21
Total lines: 88
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
set_Operator(...)100%210%
set_Values(...)100%210%
set_AvailableValues(...)100%210%
get_IsEmpty()0%620%
BuildExpressionCore()0%7280%
Reset()100%210%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/List/Filtering/Filters/CollectionContainsFilterViewModel.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="CollectionContainsFilterViewModel.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Linq;
 10using System.Linq.Expressions;
 11using MyNet.Primitives;
 12
 13namespace MyNet.UI.ViewModels.List.Filtering.Filters;
 14
 15/// <summary>
 16/// Filter view model for collection properties.
 17/// Checks whether a collection property contains any/all of the specified values.
 18/// </summary>
 19/// <typeparam name="T">The type of the items being filtered.</typeparam>
 20/// <typeparam name="TElement">The type of elements in the collection property.</typeparam>
 21/// <param name="propertyName">The key that identifies this filter condition.</param>
 22/// <param name="property">The expression representing the collection property to filter on.</param>
 23/// <param name="availableValues">The available values for selection.</param>
 24/// <param name="operatorMode">The logical operator to combine checks (And = all must match, Or = any must match).</para
 25public class CollectionContainsFilterViewModel<T, TElement>(
 26    string propertyName,
 27    Expression<Func<T, IEnumerable<TElement>>> property,
 28    IEnumerable<TElement> availableValues,
 29    LogicalOperator operatorMode = LogicalOperator.Or)
 030    : FilterConditionViewModel<T>(propertyName)
 31{
 32    /// <summary>
 33    /// Gets the expression representing the collection property to filter on.
 34    /// </summary>
 035    public Expression<Func<T, IEnumerable<TElement>>> Property { get; } = property;
 36
 37    /// <summary>
 38    /// Gets or sets the logical operator (And = all values must be present, Or = any value must be present).
 39    /// </summary>
 040    public LogicalOperator Operator { get; set => SetProperty(ref field, value); } = operatorMode;
 41
 42    /// <summary>
 43    /// Gets or sets the values to search for in the collection.
 44    /// When null or empty, the filter is considered empty.
 45    /// </summary>
 046    public TElement[]? Values { get; set => SetProperty(ref field, value); }
 47
 48    /// <summary>
 49    /// Gets or sets the available values for selection.
 50    /// </summary>
 051    public IEnumerable<TElement> AvailableValues { get; set => SetProperty(ref field, value); } = availableValues;
 52
 53    /// <summary>
 54    /// Gets a value indicating whether this filter is in an empty state.
 55    /// </summary>
 056    public override bool IsEmpty => Values is null || Values.Length == 0;
 57
 58    /// <inheritdoc />
 59    protected override Expression<Func<T, bool>> BuildExpressionCore()
 60    {
 061        var parameter = Property.Parameters[0];
 062        var propertyBody = Property.Body;
 63
 064        var values = Values?.ToList() ?? [];
 65
 66        // Build individual Contains checks for each value
 067        var containsMethod = typeof(Enumerable).GetMethods()
 068            .First(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2)
 069            .MakeGenericMethod(typeof(TElement));
 70
 071        var combined = values.Select(value => Expression.Call(containsMethod, propertyBody, Expression.Constant(value, t
 072            .Aggregate<MethodCallExpression?, Expression?>(null, (current, containsCall) => current is null
 073                ? containsCall
 074                : Operator == LogicalOperator.And
 075                    ? Expression.AndAlso(current, containsCall!)
 076                    : Expression.OrElse(current, containsCall!));
 77
 078        combined ??= Expression.Constant(true);
 79
 080        return Expression.Lambda<Func<T, bool>>(combined, parameter);
 81    }
 82
 83    /// <summary>
 84    /// Resets the filter to its default state by clearing the values.
 85    /// </summary>
 086    public override void Reset() => Values = null;
 87}
 88