| | 1 | | using Fluorite.Extensions; |
| | 2 | | using Fluorite.Strainer.Collections; |
| | 3 | | using Fluorite.Strainer.Models.Configuration; |
| | 4 | | using Fluorite.Strainer.Models.Filtering; |
| | 5 | | using Fluorite.Strainer.Models.Filtering.Operators; |
| | 6 | | using Fluorite.Strainer.Models.Metadata; |
| | 7 | | using Fluorite.Strainer.Models.Sorting; |
| | 8 | | using Fluorite.Strainer.Services.Filtering; |
| | 9 | | using Fluorite.Strainer.Services.Modules; |
| | 10 | |
|
| | 11 | | namespace Fluorite.Strainer.Services.Configuration; |
| | 12 | |
|
| | 13 | | public class StrainerConfigurationBuilder : IStrainerConfigurationBuilder |
| | 14 | | { |
| | 15 | | private Dictionary<Type, IReadOnlyDictionary<string, IPropertyMetadata>> propertyMetadata; |
| | 16 | | private Dictionary<Type, IObjectMetadata> objectMetadata; |
| | 17 | | private Dictionary<string, IFilterOperator> filterOperators; |
| | 18 | | private Dictionary<Type, IPropertyMetadata> defaultMetadata; |
| | 19 | | private Dictionary<Type, IReadOnlyDictionary<string, ICustomSortMethod>> customSortMethods; |
| | 20 | | private Dictionary<Type, IReadOnlyDictionary<string, ICustomFilterMethod>> customFilterMethods; |
| | 21 | | private HashSet<string> excludedBuiltInFilterOperators; |
| | 22 | |
|
| 12 | 23 | | public StrainerConfigurationBuilder() |
| | 24 | | { |
| 12 | 25 | | propertyMetadata = new Dictionary<Type, IReadOnlyDictionary<string, IPropertyMetadata>>(); |
| 12 | 26 | | objectMetadata = new Dictionary<Type, IObjectMetadata>(); |
| 12 | 27 | | filterOperators = new Dictionary<string, IFilterOperator>(); |
| 12 | 28 | | defaultMetadata = new Dictionary<Type, IPropertyMetadata>(); |
| 12 | 29 | | customSortMethods = new Dictionary<Type, IReadOnlyDictionary<string, ICustomSortMethod>>(); |
| 12 | 30 | | customFilterMethods = new Dictionary<Type, IReadOnlyDictionary<string, ICustomFilterMethod>>(); |
| 12 | 31 | | excludedBuiltInFilterOperators = new HashSet<string>(); |
| 12 | 32 | | } |
| | 33 | |
|
| | 34 | | public IStrainerConfiguration Build() |
| | 35 | | { |
| 12 | 36 | | var filterOperatorsWithAddedBuiltIn = AddBuiltInFilterOperators( |
| 12 | 37 | | filterOperators, |
| 12 | 38 | | excludedBuiltInFilterOperators, |
| 12 | 39 | | FilterOperatorMapper.DefaultOperators); |
| | 40 | |
|
| 11 | 41 | | return new StrainerConfiguration( |
| 11 | 42 | | customFilterMethods, |
| 11 | 43 | | customSortMethods, |
| 11 | 44 | | defaultMetadata, |
| 11 | 45 | | filterOperatorsWithAddedBuiltIn, |
| 11 | 46 | | new ReadOnlyHashSet<string>(excludedBuiltInFilterOperators), |
| 11 | 47 | | objectMetadata, |
| 11 | 48 | | propertyMetadata); |
| | 49 | | } |
| | 50 | |
|
| | 51 | | public IStrainerConfigurationBuilder WithPropertyMetadata(ICollection<IStrainerModule> modules) |
| | 52 | | { |
| 9 | 53 | | Guard.Against.Null(modules); |
| | 54 | |
|
| 9 | 55 | | propertyMetadata = modules |
| 7 | 56 | | .SelectMany(module => module |
| 7 | 57 | | .PropertyMetadata |
| 7 | 58 | | .Select(pair => |
| 8 | 59 | | new KeyValuePair<Type, IReadOnlyDictionary<string, IPropertyMetadata>>( |
| 8 | 60 | | pair.Key, pair.Value.ToReadOnly()))) |
| 9 | 61 | | .Merge(); |
| | 62 | |
|
| 9 | 63 | | return this; |
| | 64 | | } |
| | 65 | |
|
| | 66 | | public IStrainerConfigurationBuilder WithObjectMetadata(ICollection<IStrainerModule> modules) |
| | 67 | | { |
| 9 | 68 | | Guard.Against.Null(modules); |
| | 69 | |
|
| 9 | 70 | | objectMetadata = modules |
| 7 | 71 | | .SelectMany(module => module.ObjectMetadata.ToReadOnly()) |
| 9 | 72 | | .Merge(); |
| | 73 | |
|
| 9 | 74 | | return this; |
| | 75 | | } |
| | 76 | |
|
| | 77 | | public IStrainerConfigurationBuilder WithCustomFilterOperators(ICollection<IStrainerModule> modules) |
| | 78 | | { |
| 9 | 79 | | Guard.Against.Null(modules); |
| | 80 | |
|
| 16 | 81 | | filterOperators = modules.SelectMany(module => module.FilterOperators).Merge(); |
| | 82 | |
|
| 9 | 83 | | return this; |
| | 84 | | } |
| | 85 | |
|
| | 86 | | public IStrainerConfigurationBuilder WithDefaultMetadata(ICollection<IStrainerModule> modules) |
| | 87 | | { |
| 9 | 88 | | Guard.Against.Null(modules); |
| | 89 | |
|
| 9 | 90 | | defaultMetadata = modules |
| 7 | 91 | | .SelectMany(module => module.DefaultMetadata) |
| 9 | 92 | | .Merge(); |
| | 93 | |
|
| 9 | 94 | | return this; |
| | 95 | | } |
| | 96 | |
|
| | 97 | | public IStrainerConfigurationBuilder WithCustomSortMethods(ICollection<IStrainerModule> modules) |
| | 98 | | { |
| 8 | 99 | | Guard.Against.Null(modules); |
| | 100 | |
|
| 8 | 101 | | customSortMethods = modules |
| 6 | 102 | | .SelectMany(module => module |
| 6 | 103 | | .CustomSortMethods |
| 6 | 104 | | .Select(pair => |
| 6 | 105 | | new KeyValuePair<Type, IReadOnlyDictionary<string, ICustomSortMethod>>( |
| 6 | 106 | | pair.Key, pair.Value.ToReadOnly()))) |
| 8 | 107 | | .Merge(); |
| | 108 | |
|
| 8 | 109 | | return this; |
| | 110 | | } |
| | 111 | |
|
| | 112 | | public IStrainerConfigurationBuilder WithCustomFilterMethods(ICollection<IStrainerModule> modules) |
| | 113 | | { |
| 8 | 114 | | Guard.Against.Null(modules); |
| | 115 | |
|
| 8 | 116 | | customFilterMethods = modules |
| 6 | 117 | | .SelectMany(module => module |
| 6 | 118 | | .CustomFilterMethods |
| 6 | 119 | | .Select(pair => |
| 6 | 120 | | new KeyValuePair<Type, IReadOnlyDictionary<string, ICustomFilterMethod>>( |
| 6 | 121 | | pair.Key, pair.Value.ToReadOnly()))) |
| 8 | 122 | | .Merge(); |
| | 123 | |
|
| 8 | 124 | | return this; |
| | 125 | | } |
| | 126 | |
|
| | 127 | | public IStrainerConfigurationBuilder WithoutBuiltInFilterOperators(ICollection<IStrainerModule> modules) |
| | 128 | | { |
| 8 | 129 | | Guard.Against.Null(modules); |
| | 130 | |
|
| 8 | 131 | | excludedBuiltInFilterOperators = new HashSet<string>( |
| 14 | 132 | | modules.SelectMany(module => module.ExcludedBuiltInFilterOperators)); |
| | 133 | |
|
| 8 | 134 | | return this; |
| | 135 | | } |
| | 136 | |
|
| | 137 | | private IReadOnlyDictionary<string, IFilterOperator> AddBuiltInFilterOperators( |
| | 138 | | IDictionary<string, IFilterOperator> customFilterOperators, |
| | 139 | | ISet<string> excludedBuiltInFilterOperators, |
| | 140 | | IReadOnlyDictionary<string, IFilterOperator> defaultOperators) |
| | 141 | | { |
| 465 | 142 | | foreach (var pair in defaultOperators) |
| | 143 | | { |
| 221 | 144 | | if (!excludedBuiltInFilterOperators.Contains(pair.Key)) |
| | 145 | | { |
| 221 | 146 | | if (customFilterOperators.ContainsKey(pair.Key)) |
| | 147 | | { |
| 1 | 148 | | throw new InvalidOperationException( |
| 1 | 149 | | $"A custom filter operator is conflicting with built-in filter operator on symbol {pair.Key}. " |
| 1 | 150 | | $"Either mark the built-in filter operator to be excluded or remove custom filter operator."); |
| | 151 | | } |
| | 152 | | else |
| | 153 | | { |
| 220 | 154 | | customFilterOperators.Add(pair.Key, pair.Value); |
| | 155 | | } |
| | 156 | | } |
| | 157 | | } |
| | 158 | |
|
| 231 | 159 | | return customFilterOperators.OrderBy(x => x.Key.Length).ToReadOnlyDictionary(); |
| | 160 | | } |
| | 161 | | } |