Versioned fact factory usage - GetcuReone/FactFactory GitHub Wiki
We will analyze how to use the versioned fact factory using the example that we considered here.
You can find the complete example code here.
To install a version, we first need to create a custom fact that will indicate the version. In order not to fool with method implementations, we will take the base class supplied with the library as a basis.
public sealed class Version2019 : DateTimeVersionBase
{
public Version2019() : base(new DateTime(2019, 1, 1))
{
}
}
public sealed class Version2020 : DateTimeVersionBase
{
public Version2020() : base(new DateTime(2020, 1, 1))
{
}
}
Everything is very simple. We've just created a fact that points to a version. Intuitively, the higher the date, the higher the version.
public class Discount
{
public int Id { get; set; }
public int UserId { get; set; }
public int MovieId { get; set; }
public int MovieDiscount { get; set; }
public bool Enabled { get; set; } = true;
}
Instead of the old rule without version, we will put two new ones.
// If we have a user and a movie, then we can add a user discount amount.
(Version2019 _, UserFact userFact, MovieFact movieFact) =>
{
int result = 0;
var dicounts = DiscountDB.Where(dicount => dicount.UserId == userFact.Value.Id && dicount.MovieId == movieFact.Value.Id).ToList();
if (dicounts != null)
{
foreach(var dicount in dicounts)
{
result += dicount.MovieDiscount;
}
if (result > movieFact.Value.Cost)
result = movieFact.Value.Cost;
}
return new MovieDiscountFact(result);
},
(Version2020 _, UserFact userFact, MovieFact movieFact) =>
{
int result = 0;
var dicounts = DiscountDB.Where(dicount => dicount.UserId == userFact.Value.Id && dicount.MovieId == movieFact.Value.Id).ToList();
if (dicounts != null)
{
foreach(var dicount in dicounts)
{
if (dicount.Enabled)
result += dicount.MovieDiscount;
}
if (result > movieFact.Value.Cost)
result = movieFact.Value.Cost;
}
return new MovieDiscountFact(result);
},
If a rule has no version, then it is considered to have a maximum version.
VersionedFactFactory Factory;
/// <summary>
/// The method returns instances of all versions used in the rules.
/// </summary>
/// <returns></returns>
private List<IVersionFact> GetAllVersion(IWantActionContext<WantAction, VersionedFactContainer> context)
{
return new List<IVersionFact>
{
new Version2019(),
new Version2020(),
};
}
[TestInitialize]
public void Initialize()
{
//...
Factory = new VersionedFactFactory(GetAllVersion);
//...
}
Add an examples that will demonstrate how verioned works.
[TestMethod]
[Description("Calculate the cost of a 'My Hero Academia: Heroes Rising' movie for a 'Judy Gonzalez' user.")]
public void CalculatingCostBuyingMovie_1()
{
// We have information about the user's mail and the identifier of the film, what he wants to buy.
string email = "[email protected]";
int movieId = 1;
// Let's tell the factory what we know
var container = new VersionedFactContainer
{
new UserEmailFact(email),
new MovieIdFact(movieId),
};
// We ask the factory to calculate the cost of buying a movie for our user.
int price = Factory.DeriveFact<MoviePurchasePriceFact, Version2019>(container).Value;
// If we look at the database, we will see that for this user the discount on the purchase of this film is 5. The movie itself costs 11.
Assert.AreEqual(6, price, "We expected a different purchase price.");
}
[TestMethod]
[Description("Calculate the cost of a 'My Hero Academia: Heroes Rising' movie for a 'John Cornero' user.")]
public void CalculatingCostBuyingMovie_2()
{
// We have information about the user's mail and the identifier of the film, what he wants to buy.
string email = "[email protected]";
int movieId = 1;
// Let's tell the factory what we know
var container = new VersionedFactContainer
{
new UserEmailFact(email),
new MovieIdFact(movieId),
};
// We ask the factory to calculate the cost of buying a movie for our user.
int price = Factory.DeriveFact<MoviePurchasePriceFact, Version2019>(container).Value;
// For this user, the discount for this movie is not configured. Therefore we expect full value.
Assert.AreEqual(MovieDB.Single(m => m.Id == movieId).Cost, price, "We expected a different purchase price.");
}
[TestMethod]
[Description("Calculate the cost of the movie 'My Hero's Academy: Rise of the Heroes' for the user 'Judy Gonzalez' according to the new rule.")]
public void CalculatingCostBuyingMovie_3()
{
// We have information about the user's mail and the identifier of the film, what he wants to buy.
string email = "[email protected]";
int movieId = 1;
// Let's tell the factory what we know
var container = new VersionedFactContainer
{
new UserEmailFact(email),
new MovieIdFact(movieId),
};
// We ask the factory to calculate the cost of buying a movie for our user.
int price = Factory.DeriveFact<MoviePurchasePriceFact, Version2020>(container).Value;
// Calculate the cost of the movie "My Hero's Academy: Rise of the Heroes" for the user "Judy Gonzalez" according to the new rule.
Assert.AreEqual(MovieDB.First(movie => movie.Id == movieId).Cost, price, "We expected a different purchase price.");
}