Versioned fact factory usage - GetcuReone/FactFactory GitHub Wiki

How to use the versioned fact factory

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.

Part 1. Create version

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.

Part 2. Change Discount entity

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;
}

Part 3. Add rule with version

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.

Part 4. Create versioned fact factory

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);
    //...
}

Part 5. Finall.

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.");
}
⚠️ **GitHub.com Fallback** ⚠️