Skip to content

Commit 5f1528c

Browse files
committed
refactor!: replace conditions collection with dictionary
1 parent ec3c3be commit 5f1528c

File tree

36 files changed

+230
-317
lines changed

36 files changed

+230
-317
lines changed

samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ namespace Rules.Framework.InMemory.Sample.Engine
22
{
33
using System;
44
using System.Collections.Generic;
5-
using System.Linq;
65
using System.Threading.Tasks;
76
using global::Rules.Framework.InMemory.Sample.Enums;
87
using global::Rules.Framework.InMemory.Sample.Exceptions;
@@ -21,18 +20,14 @@ public async Task<T> MatchOneAsync<T>(
2120
DateTime dateTime,
2221
IDictionary<ConditionNames, object> conditions)
2322
{
24-
var rulesConditions = (conditions is null) ? new Condition<ConditionNames>[] { } :
25-
conditions.Select(x => new Condition<ConditionNames>(x.Key, x.Value))
26-
.ToArray();
27-
2823
var rulesEngine = await
2924
rulesEngineProvider
3025
.GetRulesEngineAsync()
3126
.ConfigureAwait(false);
3227

3328
var match = await rulesEngine
3429
.MakeGeneric<RulesetNames, ConditionNames>()
35-
.MatchOneAsync(ruleset, dateTime, rulesConditions)
30+
.MatchOneAsync(ruleset, dateTime, conditions)
3631
.ConfigureAwait(false);
3732

3833
if (match is null)

src/Rules.Framework/Condition.cs

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/Rules.Framework/Generic/IRulesEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public interface IRulesEngine<TRuleset, TCondition>
101101
/// <para>All rules matching supplied conditions are returned.</para>
102102
/// </remarks>
103103
/// <returns>the matched rule; otherwise, null.</returns>
104-
Task<IEnumerable<Rule<TRuleset, TCondition>>> MatchManyAsync(TRuleset ruleset, DateTime matchDateTime, IEnumerable<Condition<TCondition>> conditions);
104+
Task<IEnumerable<Rule<TRuleset, TCondition>>> MatchManyAsync(TRuleset ruleset, DateTime matchDateTime, IDictionary<TCondition, object> conditions);
105105

106106
/// <summary>
107107
/// Provides a rule match (if any) to the given <paramref name="ruleset"/> at the specified
@@ -121,7 +121,7 @@ public interface IRulesEngine<TRuleset, TCondition>
121121
/// </para>
122122
/// </remarks>
123123
/// <returns>the matched rule; otherwise, null.</returns>
124-
Task<Rule<TRuleset, TCondition>> MatchOneAsync(TRuleset ruleset, DateTime matchDateTime, IEnumerable<Condition<TCondition>> conditions);
124+
Task<Rule<TRuleset, TCondition>> MatchOneAsync(TRuleset ruleset, DateTime matchDateTime, IDictionary<TCondition, object> conditions);
125125

126126
/// <summary>
127127
/// Searches for rules that match on supplied <paramref name="searchArgs"/>.

src/Rules.Framework/Generic/RulesEngine.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,14 @@ public async Task<IEnumerable<TCondition>> GetUniqueConditionsAsync(TRuleset rul
8787
public async Task<IEnumerable<Rule<TRuleset, TCondition>>> MatchManyAsync(
8888
TRuleset ruleset,
8989
DateTime matchDateTime,
90-
IEnumerable<Condition<TCondition>> conditions)
90+
IDictionary<TCondition, object> conditions)
9191
{
9292
var rulesetAsString = GenericConversions.Convert(ruleset);
93+
var conditionsConverted = conditions.ToDictionary(c => GenericConversions.Convert(c.Key), c => c.Value, StringComparer.Ordinal);
9394
var rules = await this.wrappedRulesEngine.MatchManyAsync(
9495
rulesetAsString,
9596
matchDateTime,
96-
conditions
97-
.Select(c => new Condition<string>(GenericConversions.Convert(c.Type), c.Value))
98-
.ToArray()).ConfigureAwait(false);
97+
conditionsConverted).ConfigureAwait(false);
9998

10099
return rules.Select(r => r.ToGenericRule<TRuleset, TCondition>()).ToArray();
101100
}
@@ -104,15 +103,14 @@ public async Task<IEnumerable<Rule<TRuleset, TCondition>>> MatchManyAsync(
104103
public async Task<Rule<TRuleset, TCondition>> MatchOneAsync(
105104
TRuleset ruleset,
106105
DateTime matchDateTime,
107-
IEnumerable<Condition<TCondition>> conditions)
106+
IDictionary<TCondition, object> conditions)
108107
{
109108
var rulesetAsString = GenericConversions.Convert(ruleset);
109+
var conditionsConverted = conditions.ToDictionary(c => GenericConversions.Convert(c.Key), c => c.Value, StringComparer.Ordinal);
110110
var rule = await this.wrappedRulesEngine.MatchOneAsync(
111111
rulesetAsString,
112112
matchDateTime,
113-
conditions
114-
.Select(c => new Condition<string>(GenericConversions.Convert(c.Type), c.Value))
115-
.ToArray()).ConfigureAwait(false);
113+
conditionsConverted).ConfigureAwait(false);
116114

117115
return rule?.ToGenericRule<TRuleset, TCondition>()!;
118116
}
@@ -128,7 +126,7 @@ public async Task<IEnumerable<Rule<TRuleset, TCondition>>> SearchAsync(SearchArg
128126
var rulesetAsString = GenericConversions.Convert(searchArgs.Ruleset);
129127
var searchArgsNew = new SearchArgs<string, string>(rulesetAsString, searchArgs.DateBegin, searchArgs.DateEnd)
130128
{
131-
Conditions = searchArgs.Conditions.Select(c => new Condition<string>(GenericConversions.Convert(c.Type), c.Value)).ToArray(),
129+
Conditions = searchArgs.Conditions.ToDictionary(c => GenericConversions.Convert(c.Key), c => c.Value, StringComparer.Ordinal),
132130
ExcludeRulesWithoutSearchConditions = searchArgs.ExcludeRulesWithoutSearchConditions,
133131
};
134132

src/Rules.Framework/IRulesEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public interface IRulesEngine
9696
/// <para>All rules matching supplied conditions are returned.</para>
9797
/// </remarks>
9898
/// <returns>the matched rule; otherwise, null.</returns>
99-
Task<IEnumerable<Rule>> MatchManyAsync(string ruleset, DateTime matchDateTime, IEnumerable<Condition<string>> conditions);
99+
Task<IEnumerable<Rule>> MatchManyAsync(string ruleset, DateTime matchDateTime, IDictionary<string, object> conditions);
100100

101101
/// <summary>
102102
/// Provides a rule match (if any) to the given <paramref name="ruleset"/> at the specified
@@ -116,7 +116,7 @@ public interface IRulesEngine
116116
/// </para>
117117
/// </remarks>
118118
/// <returns>the matched rule; otherwise, null.</returns>
119-
Task<Rule> MatchOneAsync(string ruleset, DateTime matchDateTime, IEnumerable<Condition<string>> conditions);
119+
Task<Rule> MatchOneAsync(string ruleset, DateTime matchDateTime, IDictionary<string, object> conditions);
120120

121121
/// <summary>
122122
/// Searches for rules that match on supplied <paramref name="searchArgs"/>.

src/Rules.Framework/RulesEngine.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public async Task<IEnumerable<string>> GetUniqueConditionsAsync(string ruleset,
132132
public async Task<IEnumerable<Rule>> MatchManyAsync(
133133
string ruleset,
134134
DateTime matchDateTime,
135-
IEnumerable<Condition<string>> conditions)
135+
IDictionary<string, object> conditions)
136136
{
137137
if (string.IsNullOrWhiteSpace(ruleset))
138138
{
@@ -152,16 +152,15 @@ public async Task<IEnumerable<Rule>> MatchManyAsync(
152152
DateEnd = matchDateTime,
153153
};
154154

155-
var conditionsAsDictionary = conditions.ToDictionary(ks => ks.Type, ks => ks.Value, StringComparer.Ordinal);
156155
var orderedRules = await this.GetRulesOrderedAscendingAsync(getRulesArgs).ConfigureAwait(false);
157-
return this.EvalAll(orderedRules, evaluationOptions, conditionsAsDictionary, active: true);
156+
return this.EvalAll(orderedRules, evaluationOptions, conditions, active: true);
158157
}
159158

160159
/// <inheritdoc/>
161160
public async Task<Rule> MatchOneAsync(
162161
string ruleset,
163162
DateTime matchDateTime,
164-
IEnumerable<Condition<string>> conditions)
163+
IDictionary<string, object> conditions)
165164
{
166165
if (string.IsNullOrWhiteSpace(ruleset))
167166
{
@@ -181,11 +180,10 @@ public async Task<Rule> MatchOneAsync(
181180
DateEnd = matchDateTime,
182181
};
183182

184-
var conditionsAsDictionary = conditions.ToDictionary(ks => ks.Type, ks => ks.Value);
185183
var orderedRules = await this.GetRulesOrderedAscendingAsync(getRulesArgs).ConfigureAwait(false);
186184
return this.Options.PriorityCriteria == PriorityCriterias.TopmostRuleWins
187-
? EvalOneTraverse(orderedRules, evaluationOptions, conditionsAsDictionary, active: true)
188-
: EvalOneReverse(orderedRules, evaluationOptions, conditionsAsDictionary, active: true);
185+
? EvalOneTraverse(orderedRules, evaluationOptions, conditions, active: true)
186+
: EvalOneReverse(orderedRules, evaluationOptions, conditions, active: true);
189187
}
190188

191189
/// <inheritdoc/>
@@ -226,9 +224,8 @@ public async Task<IEnumerable<Rule>> SearchAsync(SearchArgs<string, string> sear
226224
DateEnd = searchArgs.DateEnd,
227225
};
228226

229-
var conditionsAsDictionary = searchArgs.Conditions.ToDictionary(ks => ks.Type, ks => ks.Value);
230227
var orderedRules = await this.GetRulesOrderedAscendingAsync(getRulesArgs).ConfigureAwait(false);
231-
return this.EvalAll(orderedRules, evaluationOptions, conditionsAsDictionary, searchArgs.Active);
228+
return this.EvalAll(orderedRules, evaluationOptions, searchArgs.Conditions, searchArgs.Active);
232229
}
233230

234231
/// <inheritdoc/>
@@ -384,7 +381,7 @@ private async Task<OperationResult> CreateRulesetInternalAsync(string ruleset)
384381
private IEnumerable<Rule> EvalAll(
385382
List<Rule> orderedRules,
386383
EvaluationOptions evaluationOptions,
387-
Dictionary<string, object> conditionsAsDictionary,
384+
IDictionary<string, object> conditionsAsDictionary,
388385
bool? active)
389386
{
390387
// Begins evaluation at the first element of the given list as parameter. Returns all
@@ -404,7 +401,7 @@ private IEnumerable<Rule> EvalAll(
404401
private Rule EvalOneReverse(
405402
List<Rule> rules,
406403
EvaluationOptions evaluationOptions,
407-
Dictionary<string, object> conditionsAsDictionary,
404+
IDictionary<string, object> conditionsAsDictionary,
408405
bool? active)
409406
{
410407
// Begins evaluation at the last element of the given list as parameter. Returns the
@@ -424,7 +421,7 @@ private Rule EvalOneReverse(
424421
private Rule EvalOneTraverse(
425422
List<Rule> rules,
426423
EvaluationOptions evaluationOptions,
427-
Dictionary<string, object> conditionsAsDictionary,
424+
IDictionary<string, object> conditionsAsDictionary,
428425
bool? active)
429426
{
430427
// Begins evaluation at the first element of the given list as parameter. Returns the
@@ -445,7 +442,7 @@ private Rule EvalOneTraverse(
445442
private bool EvalRule(
446443
Rule rule,
447444
EvaluationOptions evaluationOptions,
448-
Dictionary<string, object> conditionsAsDictionary,
445+
IDictionary<string, object> conditionsAsDictionary,
449446
bool? active)
450447
=> rule.Active == active.GetValueOrDefault(defaultValue: true) && (rule.RootCondition == null || this.conditionsEvalEngine.Eval(rule.RootCondition, conditionsAsDictionary, evaluationOptions));
451448

src/Rules.Framework/SearchArgs.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ namespace Rules.Framework
22
{
33
using System;
44
using System.Collections.Generic;
5-
using System.Linq;
65

76
/// <summary>
87
/// The set of search arguments to find rules.
@@ -19,7 +18,7 @@ public class SearchArgs<TRuleset, TCondition>
1918
/// <param name="dateEnd">The date end.</param>
2019
public SearchArgs(TRuleset ruleset, DateTime dateBegin, DateTime dateEnd)
2120
{
22-
this.Conditions = Enumerable.Empty<Condition<TCondition>>();
21+
this.Conditions = new Dictionary<TCondition, object>();
2322
this.Ruleset = ruleset;
2423
this.DateBegin = dateBegin;
2524
this.DateEnd = dateEnd;
@@ -36,7 +35,7 @@ public SearchArgs(TRuleset ruleset, DateTime dateBegin, DateTime dateEnd)
3635
/// <param name="active">The active status.</param>
3736
public SearchArgs(TRuleset ruleset, DateTime dateBegin, DateTime dateEnd, bool active)
3837
{
39-
this.Conditions = Enumerable.Empty<Condition<TCondition>>();
38+
this.Conditions = new Dictionary<TCondition, object>();
4039
this.Ruleset = ruleset;
4140
this.DateBegin = dateBegin;
4241
this.DateEnd = dateEnd;
@@ -54,7 +53,7 @@ public SearchArgs(TRuleset ruleset, DateTime dateBegin, DateTime dateEnd, bool a
5453
/// Gets or sets the search conditions.
5554
/// </summary>
5655
/// <value>The conditions.</value>
57-
public IEnumerable<Condition<TCondition>> Conditions { get; set; }
56+
public IDictionary<TCondition, object> Conditions { get; set; }
5857

5958
/// <summary>
6059
/// Gets or sets the date begin.

src/Rules.Framework/Validation/SearchArgsValidator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ public SearchArgsValidator()
3535
this.RuleForEach(sa => sa.Conditions)
3636
.ChildRules(conditionValidator =>
3737
{
38-
conditionValidator.RuleFor(condition => condition.Type)
39-
.Must(conditionType =>
38+
conditionValidator.RuleFor(condition => condition.Key)
39+
.Must(conditionKey =>
4040
{
41-
if (this.conditionTypeRuntimeType.IsClass && conditionType is null)
41+
if (this.conditionTypeRuntimeType.IsClass && conditionKey is null)
4242
{
4343
return false;
4444
}
4545

46-
if (this.conditionTypeRuntimeType.IsEnum && !Enum.IsDefined(this.conditionTypeRuntimeType, conditionType))
46+
if (this.conditionTypeRuntimeType.IsEnum && !Enum.IsDefined(this.conditionTypeRuntimeType, conditionKey))
4747
{
4848
return false;
4949
}

tests/Rules.Framework.IntegrationTests.Common/Scenarios/IScenarioData.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ namespace Rules.Framework.BenchmarkTests.Tests
22
{
33
using System;
44
using System.Collections.Generic;
5-
using Rules.Framework;
65
using Rules.Framework.Generic;
76

87
public interface IScenarioData<TRuleset, TCondition>
98
{
10-
IEnumerable<Condition<TCondition>> Conditions { get; }
9+
IDictionary<TCondition, object> Conditions { get; }
1110

1211
DateTime MatchDate { get; }
1312

tests/Rules.Framework.IntegrationTests.Common/Scenarios/Scenario6/Scenario6Data.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ namespace Rules.Framework.BenchmarkTests.Tests.Benchmark1
88

99
public class Scenario6Data : IScenarioData<Rulesets, ConditionNames>
1010
{
11-
public IEnumerable<Condition<ConditionNames>> Conditions => new[]
11+
public IDictionary<ConditionNames, object> Conditions => new Dictionary<ConditionNames, object>
1212
{
13-
new Condition<ConditionNames>(ConditionNames.StringCondition, "Let's benchmark this!")
13+
{ ConditionNames.StringCondition, "Let's benchmark this!" },
1414
};
1515

1616
public DateTime MatchDate => DateTime.Parse("2022-10-01");

0 commit comments

Comments
 (0)