Closed tetris69 closed 3 years ago
Hi @tetris69,
Pretty interesting scenario. The essence of the problem almost feels like a computed property that should get re-evaluated when DatFirst
changes. I don't think there's any realistic way for me to detect the situation programmatically or even a way to build some kind of dependency tree to evaluate when things need to be re-computed.
For now, I think you'll have to resort to moving those "computed property" rules last; or in their own rule set and execute them after your "primary/raw data" (un-computed) properties are set.
Here's an example:
void Main()
{
var clientFaker = new Faker<Client>()
.RuleFor(o => o.DatFirst, f => "A")
.RuleSet("use_b", r =>
{
r.RuleFor(o => o.DatFirst, f => "B");
})
.FinishWith((f, o) => {
o.DatSecond = o.DatFirst == "A" ? "X" : "Y";
});
var client = clientFaker.Generate("default, use_b");
client.Dump();
}
public class Client
{
public string DatFirst;
public string DatSecond;
}
In the code above, I used .FinishWith
, but you could have a finalize
rule set that does the same thing. Up to your coding style and preference of course.
Also, you could extend Bogus' Faker<T>
with something like ComputedFaker<T> : Faker<T>
that could automate the scenario. I'd have to think about it a little more.
Here's another way to merge rules using MergeFaker<T>
:
void Main()
{
var clientFaker = new MergeFaker<Client>()
.RuleFor(o => o.DatFirst, f => "A")
.RuleFor(o => o.DatSecond, (f, o) => o.DatFirst == "A" ? "X" : "Y")
.RuleSet("use_b", r =>
{
r.RuleFor(o => o.DatFirst, f => "B");
})
as MergeFaker<Client>;
var mergedName = clientFaker.MergeRuleSets("default, use_b");
var client = clientFaker.Generate(mergedName);
client.Dump();
}
public class MergeFaker<T> : Faker<T> where T : class
{
public string MergeRuleSets(string ruleSets = null)
{
var cleanRules = ParseDirtyRulesSets(ruleSets);
var mergedName = Guid.NewGuid().ToString("n");
this.RuleSet(mergedName, _ => {
foreach (var ruleName in cleanRules)
{
if (!this.Actions.TryGetValue(ruleName, out var allRulesForSet)) continue;
foreach(var (propName, rule) in allRulesForSet){
AddRule(propName, rule.Action);
}
}
});
return mergedName;
}
}
public class Client
{
public string DatFirst;
public string DatSecond;
}
The basic idea is,
Wow! :) I love your second solution. It works like a charm. I also added this function in my MergeFaker class to clear memory after using the merged ruleset.
public void DisposeRuleSet(string mergedName)
{
this.Actions.Remove(mergedName);
}
Thank you very much and have a nice day.
Hi, thanks for building and maintaining this awesome tool. Here's my issue.
When defining two rules for the same property in the default RuleSet, the second rule replaces the first one, without changing the order of execution. This is great.
I would like the same behavior to happen when defining two rules for the same property, but in different rulesets. In the following example, I would like my client to have it's
DatSecond
property to"Y"
.The goal is to have
DatSecond
populated no matter if the rulesetuse_b
is used, and also to not repeatDatSecond
's rule.