< Summary

Information
Class: MyNet.Observable.Collections.Filters.FilterBuilder<T>
Assembly: MyNet.Observable
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Observable/Collections/Filters/FilterBuilder.cs
Tag: 323_28699572109
Line coverage
92%
Covered lines: 25
Uncovered lines: 2
Coverable lines: 27
Total lines: 133
Line coverage: 92.5%
Branch coverage
87%
Covered branches: 7
Total branches: 8
Branch coverage: 87.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
Create()100%11100%
Where(...)100%11100%
Where(...)100%210%
And(...)100%11100%
And(...)100%11100%
Or(...)100%11100%
Or(...)100%210%
AddGroup(...)50%22100%
AddNode(...)100%11100%
Build()100%44100%
BuildTree()100%22100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Observable/Collections/Filters/FilterBuilder.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="FilterBuilder.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.Expressions;
 10using MyNet.Primitives;
 11
 12namespace MyNet.Observable.Collections.Filters;
 13
 14/// <summary>
 15/// Provides a fluent API for building complex filter expressions for collections of type T.
 16/// </summary>
 17/// <typeparam name="T">The type of items to be filtered.</typeparam>
 18public sealed class FilterBuilder<T>
 19{
 3020    private readonly List<(LogicalOperator Operator, IFilter<T> Node)> _nodes = [];
 21
 22    /// <summary>
 23    /// Creates a new instance of the <see cref="FilterBuilder{T}"/> class, providing a fluent API for constructing comp
 24    /// </summary>
 25    /// <returns>A new instance of <see cref="FilterBuilder{T}"/>.</returns>
 2726    public static FilterBuilder<T> Create() => new();
 27
 28    /// <summary>
 29    /// Adds a filter expression to the builder using the specified predicate. The predicate is a lambda expression that
 30    /// </summary>
 31    /// <param name="expr">A lambda expression that defines the filtering logic for items of type T.</param>
 32    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 2133    public FilterBuilder<T> Where(Expression<Func<T, bool>> expr) => And(expr);
 34
 35    /// <summary>
 36    /// Adds a grouped filter expression to the builder using the specified group function. The group function is a lamb
 37    /// </summary>
 38    /// <param name="group">A lambda function that defines a group of filter expressions.</param>
 39    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 040    public FilterBuilder<T> Where(Func<FilterBuilder<T>, FilterBuilder<T>> group) => And(group);
 41
 42    /// <summary>
 43    /// Adds a filter expression to the builder using the logical AND operator. The provided expression is combined with
 44    /// </summary>
 45    /// <param name="expr">A lambda expression that defines the filtering logic for items of type T.</param>
 46    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 47    public FilterBuilder<T> And(Expression<Func<T, bool>> expr)
 48    {
 2149        AddNode(LogicalOperator.And, new ExpressionFilter<T>(expr));
 2150        return this;
 51    }
 52
 53    /// <summary>
 54    /// Adds a grouped filter expression to the builder using the logical AND operator. The provided group function is u
 55    /// </summary>
 56    /// <param name="group">A lambda function that defines a group of filter expressions.</param>
 57    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 358    public FilterBuilder<T> And(Func<FilterBuilder<T>, FilterBuilder<T>> group) => AddGroup(LogicalOperator.And, group);
 59
 60    /// <summary>
 61    /// Adds a grouped filter expression to the builder using the logical OR operator. The provided group function is us
 62    /// </summary>
 63    /// <param name="expression">A lambda function that defines a group of filter expressions.</param>
 64    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 65    public FilterBuilder<T> Or(Expression<Func<T, bool>> expression)
 66    {
 367        AddNode(LogicalOperator.Or, new ExpressionFilter<T>(expression));
 368        return this;
 69    }
 70
 71    /// <summary>
 72    /// Adds a grouped filter expression to the builder using the logical OR operator. The provided group function is us
 73    /// </summary>
 74    /// <param name="group">A lambda function that defines a group of filter expressions.</param>
 75    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 076    public FilterBuilder<T> Or(Func<FilterBuilder<T>, FilterBuilder<T>> group) => AddGroup(LogicalOperator.Or, group);
 77
 78    /// <summary>
 79    /// Adds a grouped filter expression to the builder using the specified logical operator. The provided group functio
 80    /// </summary>
 81    /// <param name="op">The logical operator to use when combining the group with existing expressions.</param>
 82    /// <param name="builder">A lambda function that defines a group of filter expressions.</param>
 83    /// <returns>The current instance of <see cref="FilterBuilder{T}"/>.</returns>
 84    private FilterBuilder<T> AddGroup(LogicalOperator op, Func<FilterBuilder<T>, FilterBuilder<T>> builder)
 85    {
 386        var inner = builder(new());
 387        var node = inner.Build();
 88
 389        if (node is not null)
 390            AddNode(op, node);
 91
 392        return this;
 93    }
 94
 95    /// <summary>
 96    /// Adds a filter node to the builder with the specified logical operator. The node represents a filter expression o
 97    /// </summary>
 98    /// <param name="op">The logical operator to use when combining the node with existing expressions.</param>
 99    /// <param name="node">The filter node to add to the builder.</param>
 27100    private void AddNode(LogicalOperator op, IFilter<T> node) => _nodes.Add((op, node));
 101
 102    /// <summary>
 103    /// Builds the filter expression tree based on the nodes added to the builder. If no nodes have been added, it retur
 104    /// </summary>
 105    /// <returns>The root filter node representing the entire filter expression tree.</returns>
 106    public IFilter<T>? Build()
 30107        => _nodes.Count switch
 30108        {
 9109            0 => null,
 15110            1 => _nodes[0].Node,
 6111            _ => BuildTree()
 30112        };
 113
 114    /// <summary>
 115    /// Builds the filter expression tree by combining all nodes in the builder according to their specified logical ope
 116    /// </summary>
 117    /// <returns>The root filter node representing the entire filter expression tree.</returns>
 118    private IFilter<T> BuildTree()
 119    {
 120        // Group sequentially respecting operators
 6121        var current = _nodes[0].Node;
 122
 24123        for (var i = 1; i < _nodes.Count; i++)
 124        {
 6125            var (op, node) = _nodes[i];
 126
 6127            current = new FilterGroup<T>(op, [current, node]);
 128        }
 129
 6130        return current;
 131    }
 132}
 133