< Summary

Information
Class: Fluorite.Strainer.Services.Modules.StrainerModuleBuilder
Assembly: Fluorite.Strainer
File(s): /builds/fluorite/strainer/src/Strainer/Services/Modules/StrainerModuleBuilder.cs
Line coverage
100%
Covered lines: 59
Uncovered lines: 0
Coverable lines: 59
Total lines: 207
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Options()100%11100%
get_Module()100%11100%
get_PropertyInfoProvider()100%11100%
AddCustomFilterMethod(...)100%22100%
AddCustomSortMethod(...)100%22100%
AddFilterOperator(...)100%22100%
AddObject(...)100%22100%
AddProperty(...)100%44100%
RemoveBuiltInFilterOperator(...)100%11100%

File(s)

/builds/fluorite/strainer/src/Strainer/Services/Modules/StrainerModuleBuilder.cs

#LineLine coverage
 1using Fluorite.Strainer.Models;
 2using Fluorite.Strainer.Models.Filtering;
 3using Fluorite.Strainer.Models.Filtering.Operators;
 4using Fluorite.Strainer.Models.Metadata;
 5using Fluorite.Strainer.Models.Sorting;
 6using Fluorite.Strainer.Services.Filtering;
 7using Fluorite.Strainer.Services.Metadata;
 8using Fluorite.Strainer.Services.Sorting;
 9using System.Linq.Expressions;
 10using System.Reflection;
 11
 12namespace Fluorite.Strainer.Services.Modules;
 13
 14/// <summary>
 15/// Default implementation of Strainer Module builder service.
 16/// </summary>
 17public class StrainerModuleBuilder : IStrainerModuleBuilder
 18{
 19    /// <summary>
 20    /// Initializes a new instance of the <see cref="StrainerModuleBuilder"/>
 21    /// class.
 22    /// </summary>
 23    /// <param name="strainerModule">
 24    /// The Strainer moduel to operate on.
 25    /// </param>
 26    /// <param name="strainerOptions">
 27    /// The Stariner options.
 28    /// </param>
 29    /// <param name="propertyInfoProvider">
 30    /// The <see cref="PropertyInfo"/> provider.
 31    /// </param>
 32    /// <exception cref="ArgumentNullException">
 33    /// <paramref name="strainerModule"/> is <see langword="null"/>.
 34    /// </exception>
 35    /// <exception cref="ArgumentNullException">
 36    /// <paramref name="strainerOptions"/> is <see langword="null"/>.
 37    /// </exception>
 38    /// <exception cref="ArgumentNullException">
 39    /// <paramref name="propertyInfoProvider"/> is <see langword="null"/>.
 40    /// </exception>
 1441    public StrainerModuleBuilder(
 1442        IPropertyInfoProvider propertyInfoProvider,
 1443        IStrainerModule strainerModule,
 1444        StrainerOptions strainerOptions)
 45    {
 1446        PropertyInfoProvider = Guard.Against.Null(propertyInfoProvider);
 1447        Module = Guard.Against.Null(strainerModule);
 1448        Options = Guard.Against.Null(strainerOptions);
 1449    }
 50
 51    /// <inheritdoc/>
 952    public StrainerOptions Options { get; }
 53
 54    /// <summary>
 55    /// Gets the Strainer module on which this builder operates on.
 56    /// </summary>
 2057    protected IStrainerModule Module { get; }
 58
 59    /// <summary>
 60    /// Gets the property info provider.
 61    /// </summary>
 762    protected IPropertyInfoProvider PropertyInfoProvider { get; }
 63
 64    /// <inheritdoc/>
 65    /// <exception cref="ArgumentException">
 66    /// <paramref name="buildingDelegate"/> is <see langword="null"/>.
 67    /// </exception>
 68    public IStrainerModuleBuilder AddCustomFilterMethod<TEntity>(
 69        Func<ICustomFilterMethodBuilder<TEntity>, ICustomFilterMethod<TEntity>> buildingDelegate)
 70    {
 171        Guard.Against.Null(buildingDelegate);
 72
 173        var builder = new CustomFilterMethodBuilder<TEntity>();
 174        var customMethod = buildingDelegate.Invoke(builder);
 75
 176        if (!Module.CustomFilterMethods.ContainsKey(typeof(TEntity)))
 77        {
 178            Module.CustomFilterMethods[typeof(TEntity)] = new Dictionary<string, ICustomFilterMethod>();
 79        }
 80
 181        Module.CustomFilterMethods[typeof(TEntity)][customMethod.Name] = customMethod;
 82
 183        return this;
 84    }
 85
 86    /// <inheritdoc/>
 87    /// <exception cref="ArgumentException">
 88    /// <paramref name="buildingDelegate"/> is <see langword="null"/>.
 89    /// </exception>
 90    public IStrainerModuleBuilder AddCustomSortMethod<TEntity>(
 91        Func<ICustomSortMethodBuilder<TEntity>, ICustomSortMethod<TEntity>> buildingDelegate)
 92    {
 193        Guard.Against.Null(buildingDelegate);
 94
 195        var builder = new CustomSortMethodBuilder<TEntity>();
 196        var customMethod = buildingDelegate.Invoke(builder);
 97
 198        if (!Module.CustomSortMethods.ContainsKey(typeof(TEntity)))
 99        {
 1100            Module.CustomSortMethods[typeof(TEntity)] = new Dictionary<string, ICustomSortMethod>();
 101        }
 102
 1103        Module.CustomSortMethods[typeof(TEntity)][customMethod.Name] = customMethod;
 104
 1105        return this;
 106    }
 107
 108    /// <inheritdoc/>
 109    /// <exception cref="ArgumentException">
 110    /// <paramref name="buildingDelegate"/> is <see langword="null"/>.
 111    /// </exception>
 112    /// <exception cref="InvalidOperationException">
 113    /// <paramref name="buildingDelegate"/> is used by already defined filter operator.
 114    /// </exception>
 115    public IStrainerModuleBuilder AddFilterOperator(Func<IFilterOperatorBuilder, IFilterOperator> buildingDelegate)
 116    {
 2117        Guard.Against.Null(buildingDelegate);
 118
 2119        var builder = new FilterOperatorBuilder();
 2120        var filterOperator = buildingDelegate.Invoke(builder);
 121
 2122        if (Module.FilterOperators.Keys.Contains(filterOperator.Symbol))
 123        {
 1124            throw new InvalidOperationException(
 1125                $"There is an already existing operator with a symbol {filterOperator.Symbol}. " +
 1126                $"Please, choose a different symbol.");
 127        }
 128
 1129        Module.FilterOperators.Add(filterOperator.Symbol, filterOperator);
 130
 1131        return this;
 132    }
 133
 134    /// <inheritdoc/>
 135    /// <exception cref="ArgumentException">
 136    /// <paramref name="defaultSortingPropertyExpression"/> is <see langword="null"/>.
 137    /// </exception>
 138    /// <exception cref="NotSupportedException">
 139    /// Fluent API is not supported.
 140    /// </exception>
 141    public IObjectMetadataBuilder<TEntity> AddObject<TEntity>(
 142        Expression<Func<TEntity, object>> defaultSortingPropertyExpression)
 143    {
 7144        Guard.Against.Null(defaultSortingPropertyExpression);
 145
 7146        if (!Options.MetadataSourceType.HasFlag(MetadataSourceType.FluentApi))
 147        {
 1148            throw new NotSupportedException(
 1149                $"Current {nameof(MetadataSourceType)} setting does not " +
 1150                $"support {nameof(MetadataSourceType.FluentApi)}. " +
 1151                $"Include {nameof(MetadataSourceType.FluentApi)} option to " +
 1152                $"be able to use it.");
 153        }
 154
 6155        return new ObjectMetadataBuilder<TEntity>(
 6156            PropertyInfoProvider,
 6157            Module.ObjectMetadata,
 6158            defaultSortingPropertyExpression);
 159    }
 160
 161    /// <inheritdoc/>
 162    /// <exception cref="ArgumentException">
 163    /// <paramref name="propertyExpression"/> is <see langword="null"/>.
 164    /// </exception>
 165    /// <exception cref="NotSupportedException">
 166    /// Fluent API is not supported.
 167    /// </exception>
 168    public IPropertyMetadataBuilder<TEntity> AddProperty<TEntity>(
 169        Expression<Func<TEntity, object>> propertyExpression)
 170    {
 2171        Guard.Against.Null(propertyExpression);
 172
 2173        if (!Options.MetadataSourceType.HasFlag(MetadataSourceType.FluentApi))
 174        {
 1175            throw new NotSupportedException(
 1176                $"Current {nameof(MetadataSourceType)} setting does not " +
 1177                $"support {nameof(MetadataSourceType.FluentApi)}. " +
 1178                $"Include {nameof(MetadataSourceType.FluentApi)} option to " +
 1179                $"be able to use it.");
 180        }
 181
 1182        if (!Module.PropertyMetadata.ContainsKey(typeof(TEntity)))
 183        {
 1184            Module.PropertyMetadata[typeof(TEntity)] = new Dictionary<string, IPropertyMetadata>();
 185        }
 186
 1187        var (propertyInfo, fullName) = PropertyInfoProvider.GetPropertyInfoAndFullName(propertyExpression);
 188
 1189        return new PropertyMetadataBuilder<TEntity>(Module.PropertyMetadata, Module.DefaultMetadata, propertyInfo, fullN
 190    }
 191
 192    /// <inheritdoc/>
 193    /// <exception cref="ArgumentNullException">
 194    /// <paramref name="symbol"/> is <see langword="null"/>.
 195    /// </exception>
 196    /// <exception cref="ArgumentException">
 197    /// <paramref name="symbol"/> is empty or whitespace.
 198    /// </exception>
 199    public IStrainerModuleBuilder RemoveBuiltInFilterOperator(string symbol)
 200    {
 1201        Guard.Against.NullOrWhiteSpace(symbol);
 202
 1203        Module.ExcludedBuiltInFilterOperators.Add(symbol);
 204
 1205        return this;
 206    }
 207}