FractalDataWorks.Calculations.Abstractions 0.6.0-rc.1

This is a prerelease version of FractalDataWorks.Calculations.Abstractions.
dotnet add package FractalDataWorks.Calculations.Abstractions --version 0.6.0-rc.1
                    
NuGet\Install-Package FractalDataWorks.Calculations.Abstractions -Version 0.6.0-rc.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FractalDataWorks.Calculations.Abstractions" Version="0.6.0-rc.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FractalDataWorks.Calculations.Abstractions" Version="0.6.0-rc.1" />
                    
Directory.Packages.props
<PackageReference Include="FractalDataWorks.Calculations.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FractalDataWorks.Calculations.Abstractions --version 0.6.0-rc.1
                    
#r "nuget: FractalDataWorks.Calculations.Abstractions, 0.6.0-rc.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FractalDataWorks.Calculations.Abstractions@0.6.0-rc.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FractalDataWorks.Calculations.Abstractions&version=0.6.0-rc.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FractalDataWorks.Calculations.Abstractions&version=0.6.0-rc.1&prerelease
                    
Install as a Cake Tool

FractalDataWorks.Calculations.Abstractions

Core abstractions and interfaces for the FractalDataWorks calculation framework. This package provides the foundational contracts for implementing extensible calculation systems that transform input data into output data using Railway-Oriented Programming patterns.

Overview

FractalDataWorks.Calculations.Abstractions defines the base interfaces and types for building calculation systems within the FractalDataWorks ecosystem. It provides:

  • Calculation Contracts - ICalculation<TInput, TOutput> interface for type-safe transformations
  • Calculation Context - ICalculationContext for accessing data sources during execution
  • Calculation Base Class - CalculationBase<TInput, TOutput> for common implementation patterns
  • Calculation Types - ICalculationType and CalculationTypeBase TypeCollection for extensible calculation types
  • Period Comparison Types - IPeriodComparisonType TypeCollection for time-series analysis
  • Fluent Builders - Builder interfaces for constructing calculations programmatically
  • Railway-Oriented Programming - Integration with IGenericResult for consistent error handling

This package serves as the foundation for concrete calculation implementations and calculation type discovery using the TypeCollection pattern.

Target Frameworks: netstandard2.0

Dependencies:

  • FractalDataWorks.Results
  • FractalDataWorks.Collections
  • FractalDataWorks.Data.Abstractions
  • FractalDataWorks.Commands.Data.Abstractions
  • FractalDataWorks.Services.Data.Abstractions

Core Interfaces

ICalculation<TInput, TOutput>

Base interface for all calculations that transform input data into output data.

From ICalculation.cs:14-73:

public interface ICalculation<TInput, TOutput>
{
    string CalculationId { get; }
    string Name { get; }
    string? Description { get; }
    string CalculationType { get; }

    // Dependency declarations
    IReadOnlyList<string> RequiredDataSets { get; }
    IReadOnlyList<string> DependsOn { get; }

    // Execution
    Task<IGenericResult<TOutput>> Execute(
        TInput input,
        ICalculationContext context,
        CancellationToken cancellationToken = default);

    // Validation
    Task<IGenericResult> Validate(CancellationToken cancellationToken = default);
    IGenericResult ValidateDependencies(ICalculationContext context);
}

Key Characteristics:

  • Generic input and output types for type-safe transformations
  • Railway-Oriented Programming via IGenericResult return types
  • Explicit dependency declarations via RequiredDataSets and DependsOn
  • Dependency validation via ValidateDependencies()
  • Async execution with cancellation support
  • Context-aware execution for data access

ICalculationContext

Provides context and data access capabilities during calculation execution.

From ICalculationContext.cs:16-143:

public interface ICalculationContext
{
    // Core properties
    string ExecutionId { get; }
    DateTime ExecutionTime { get; }
    IDataGateway DataGateway { get; }
    IReadOnlyDictionary<string, object?> Parameters { get; }
    IDictionary<string, object?> State { get; }

    // Data access
    Task<IGenericResult<TData>> GetData<TData>(
        string connectionName,
        string containerName,
        CancellationToken cancellationToken = default);
    Task<IGenericResult<TData>> GetData<TData>(
        IDataCommand command,
        CancellationToken cancellationToken = default);

    // Dataset caching
    T? GetDataSet<T>(string name);
    bool TryGetDataSet<T>(string name, out T? dataset);
    void SetDataSet<T>(string name, T dataset);
    bool HasDataSet(string name);

    // Calculation result caching
    T? GetCalculationResult<T>(string calculationName);
    bool TryGetCalculationResult<T>(string calculationName, out T? result);
    void SetCalculationResult<T>(string calculationName, T result);
    bool HasCalculationResult(string calculationName);
}

Key Characteristics:

  • Access to IDataGateway for data operations
  • Parameter passing for configuration
  • State dictionary for intermediate storage
  • Dataset caching for multi-dataset calculations
  • Calculation result caching for dependent calculations
  • Execution tracking with ID and timestamp

CalculationBase<TInput, TOutput>

Abstract base class for calculation implementations.

From CalculationBase.cs:19-109:

public abstract class CalculationBase<TInput, TOutput> : ICalculation<TInput, TOutput>
{
    protected CalculationBase(
        string calculationId,
        string name,
        string calculationType,
        string? description = null)
    {
        CalculationId = calculationId ?? throw new ArgumentNullException(nameof(calculationId));
        Name = name ?? throw new ArgumentNullException(nameof(name));
        CalculationType = calculationType ?? throw new ArgumentNullException(nameof(calculationType));
        Description = description;
    }

    public string CalculationId { get; }
    public string Name { get; }
    public string? Description { get; }
    public string CalculationType { get; }

    // Override to declare dependencies
    public virtual IReadOnlyList<string> RequiredDataSets => Array.Empty<string>();
    public virtual IReadOnlyList<string> DependsOn => Array.Empty<string>();

    public abstract Task<IGenericResult<TOutput>> Execute(
        TInput input,
        ICalculationContext context,
        CancellationToken cancellationToken = default);

    public abstract Task<IGenericResult> Validate(
        CancellationToken cancellationToken = default);

    public virtual IGenericResult ValidateDependencies(ICalculationContext context)
    {
        // Default implementation checks State for required keys
        var missingDataSets = RequiredDataSets
            .Where(ds => !context.State.ContainsKey($"DataSet:{ds}"))
            .ToList();

        var missingCalculations = DependsOn
            .Where(calc => !context.State.ContainsKey($"Calculation:{calc}"))
            .ToList();

        if (missingDataSets.Count == 0 && missingCalculations.Count == 0)
            return GenericResult.Success();

        var errors = new List<string>();
        if (missingDataSets.Count > 0)
            errors.Add($"Missing required datasets: {string.Join(", ", missingDataSets)}");
        if (missingCalculations.Count > 0)
            errors.Add($"Missing dependent calculations: {string.Join(", ", missingCalculations)}");

        return GenericResult.Failure(string.Join("; ", errors));
    }
}

Calculation Types TypeCollection

ICalculationType

Interface for calculation types in the TypeCollection system.

From ICalculationType.cs:10-18:

public interface ICalculationType : ITypeOption<int, CalculationTypeBase>
{
    /// <summary>
    /// Performs the calculation on the provided values.
    /// </summary>
    decimal Calculate(IReadOnlyList<decimal> values);
}

CalculationTypeBase

Abstract base class for all calculation types.

From CalculationTypeBase.cs:9-26:

public abstract class CalculationTypeBase : TypeOptionBase<int, CalculationTypeBase>, ICalculationType
{
    protected CalculationTypeBase(int id, string name) : base(id, name)
    {
    }

    public abstract decimal Calculate(IReadOnlyList<decimal> values);
}

CalculationTypes Collection

TypeCollection for calculation types with compile-time discovery.

From CalculationTypes/CalculationTypes.cs:14-18:

[TypeCollection(typeof(CalculationTypeBase), typeof(ICalculationType), typeof(CalculationTypes))]
public sealed partial class CalculationTypes : TypeCollectionBase<CalculationTypeBase, ICalculationType>
{
}

Built-in Calculation Types

The package includes these calculation types:

Type ID Description
Sum 1 Adds all values together
Average 2 Calculates mean of all values
Min 3 Finds the smallest value
Max 4 Finds the largest value
Count 5 Returns the count of values

From CalculationTypes/AverageCalculationType.cs:10-28:

[TypeOption(typeof(CalculationTypes), "Average")]
public sealed class AverageCalculationType : CalculationTypeBase
{
    public AverageCalculationType() : base(id: 2, name: "Average")
    {
    }

    public override decimal Calculate(IReadOnlyList<decimal> values)
    {
        if (values.Count == 0)
            return 0;

        return values.Average();
    }
}

From CalculationTypes/SumCalculationType.cs:10-25:

[TypeOption(typeof(CalculationTypes), "Sum")]
public sealed class SumCalculationType : CalculationTypeBase
{
    public SumCalculationType() : base(id: 1, name: "Sum")
    {
    }

    public override decimal Calculate(IReadOnlyList<decimal> values)
    {
        return values.Sum();
    }
}

Period Comparison Types TypeCollection

For time-series analysis, the package provides period comparison types.

IPeriodComparisonType

From PeriodComparisonTypes/IPeriodComparisonType.cs:10-39:

public interface IPeriodComparisonType : ITypeOption<int, PeriodComparisonTypeBase>
{
    bool IsCumulative { get; }
    TimeSpan? ComparisonOffset { get; }
    DateTimeOffset? GetComparisonDate(DateTimeOffset referenceDate);
    DateTimeOffset? GetCumulativeStartDate(DateTimeOffset referenceDate);
}

PeriodComparisonTypeBase

From PeriodComparisonTypes/PeriodComparisonTypeBase.cs:12-37:

public abstract class PeriodComparisonTypeBase : TypeOptionBase<int, PeriodComparisonTypeBase>, IPeriodComparisonType
{
    protected PeriodComparisonTypeBase(int id, string name, bool isCumulative)
        : base(id, name)
    {
        IsCumulative = isCumulative;
    }

    public bool IsCumulative { get; }
    public abstract TimeSpan? ComparisonOffset { get; }
    public abstract DateTimeOffset? GetComparisonDate(DateTimeOffset referenceDate);
    public abstract DateTimeOffset? GetCumulativeStartDate(DateTimeOffset referenceDate);
}

Built-in Period Comparison Types

Type Description Cumulative
YearOverYear Compare to same period last year No
MonthOverMonth Compare to same period last month No
QuarterOverQuarter Compare to same period last quarter No
WeekOverWeek Compare to same period last week No
DayOverDay Compare to same period yesterday No
YearToDate Cumulative from start of year Yes
MonthToDate Cumulative from start of month Yes
QuarterToDate Cumulative from start of quarter Yes
None No comparison No

From PeriodComparisonTypes/YearOverYearPeriodComparisonType.cs:12-29:

[TypeOption(typeof(PeriodComparisonTypes), "YearOverYear")]
public sealed class YearOverYearPeriodComparisonType : PeriodComparisonTypeBase
{
    public YearOverYearPeriodComparisonType() : base(1, "YearOverYear", isCumulative: false) { }

    public override TimeSpan? ComparisonOffset => TimeSpan.FromDays(-365);

    public override DateTimeOffset? GetComparisonDate(DateTimeOffset referenceDate) =>
        referenceDate.AddYears(-1);

    public override DateTimeOffset? GetCumulativeStartDate(DateTimeOffset referenceDate) => null;
}

Fluent Builder Interfaces

The package provides fluent builder interfaces for constructing calculations programmatically.

ICalculationBuilder<TOutput>

From Builders/ICalculationBuilder.cs:13-70:

public interface ICalculationBuilder<TOutput>
{
    ICalculationBuilder<TOutput> WithName(string name);
    ICalculationBuilder<TOutput> WithDescription(string description);
    ICalculationBuilder<TOutput> WithAggregation(Action<IAggregationBuilder<TOutput>> configure);
    ICalculationBuilder<TOutput> WithPeriodComparison(Action<IPeriodComparisonBuilder<TOutput>> configure);
    ICalculationBuilder<TOutput> WithBusinessRule(Action<IBusinessRuleBuilder<TOutput>> configure);
    ICalculationBuilder<TOutput> WithTimeSeries(Action<ITimeSeriesBuilder<TOutput>> configure);
    ICalculationBuilder<TOutput> FromDataSource(Action<IDataSourceBuilder<TOutput>> configure);
    Task<IGenericResult<ICalculation<object, TOutput>>> Build(CancellationToken cancellationToken = default);
}

IAggregationBuilder<TOutput>

From Builders/IAggregationBuilder.cs:7-36:

public interface IAggregationBuilder<TOutput>
{
    IAggregationBuilder<TOutput> WithAggregationType(string aggregationTypeName);
    IAggregationBuilder<TOutput> OnField(string fieldName);
    IAggregationBuilder<TOutput> GroupBy(params string[] fields);
    IAggregationBuilder<TOutput> WithFilter(string filterExpression);
}

Architecture Patterns

Railway-Oriented Programming

All calculations return IGenericResult<T> to handle both success and failure cases:

// Pattern from ICalculation interface
var result = await calculation.Execute(input, context, cancellationToken);

if (result.IsSuccess)
{
    var value = result.Value;
    // Process successful result
}
else
{
    var error = result.CurrentMessage;
    // Handle failure
}

TypeCollection Integration

Calculation types use the TypeCollection pattern for extensibility and O(1) lookups:

// Access all registered types
var allTypes = CalculationTypes.All();

// Lookup by name
var averageType = CalculationTypes.ByName("Average");

// Lookup by ID
var sumType = CalculationTypes.ById(1);

// Execute calculation
var values = new[] { 10m, 20m, 30m, 40m, 50m };
var result = averageType.Calculate(values); // Returns 30

Dependency Validation

The ValidateDependencies method checks that required datasets and dependent calculations are available before execution:

// Check dependencies before execution
var depResult = calculation.ValidateDependencies(context);
if (!depResult.IsSuccess)
{
    // Handle missing dependencies
    Console.WriteLine($"Missing: {depResult.CurrentMessage}");
    return;
}

// Safe to execute
var result = await calculation.Execute(input, context, cancellationToken);

Best Practices

  1. Immutable Input - Treat input data as immutable; do not modify it during execution
  2. Use Context for Data - Always use ICalculationContext for data access, never inject repositories directly
  3. Return Results, Not Exceptions - Use IGenericResult for expected failures
  4. Validate Early - Implement Validate() to catch configuration issues before execution
  5. Cancellation Support - Honor CancellationToken for long-running calculations
  6. Declare Dependencies - Override RequiredDataSets and DependsOn to declare dependencies explicitly
  7. Meaningful IDs - Use descriptive CalculationId values for logging and tracking
  8. Type Safety - Leverage generic type parameters for compile-time safety

Implementing a Custom Calculation

To implement a custom calculation, extend CalculationBase<TInput, TOutput>:

public sealed class MyCalculation : CalculationBase<IEnumerable<decimal>, decimal>
{
    public MyCalculation()
        : base(
            calculationId: "my-calc-001",
            name: "My Calculation",
            calculationType: "Custom",
            description: "Description of what this calculation does")
    {
    }

    // Declare required datasets
    public override IReadOnlyList<string> RequiredDataSets =>
        new[] { "SalesData" };

    // Declare dependent calculations
    public override IReadOnlyList<string> DependsOn =>
        new[] { "PriorPeriodTotal" };

    public override async Task<IGenericResult<decimal>> Execute(
        IEnumerable<decimal> input,
        ICalculationContext context,
        CancellationToken cancellationToken = default)
    {
        // Access cached dataset
        var salesData = context.GetDataSet<IEnumerable<SalesRecord>>("SalesData");
        if (salesData == null)
            return GenericResult<decimal>.Failure("SalesData not loaded");

        // Access prior calculation result
        if (!context.TryGetCalculationResult<decimal>("PriorPeriodTotal", out var priorTotal))
            return GenericResult<decimal>.Failure("PriorPeriodTotal not calculated");

        // Perform calculation
        var total = input.Sum();
        var growth = priorTotal != 0 ? ((total - priorTotal) / priorTotal) * 100 : 0;

        return GenericResult<decimal>.Success(growth);
    }

    public override Task<IGenericResult> Validate(CancellationToken cancellationToken = default)
    {
        return Task.FromResult(GenericResult.Success());
    }
}

Implementing a Custom Calculation Type

To implement a custom calculation type, extend CalculationTypeBase and add the [TypeOption] attribute:

[TypeOption(typeof(CalculationTypes), "Median")]
public sealed class MedianCalculationType : CalculationTypeBase
{
    public MedianCalculationType() : base(id: 6, name: "Median")
    {
    }

    public override decimal Calculate(IReadOnlyList<decimal> values)
    {
        if (values.Count == 0)
            return 0;

        var sorted = values.OrderBy(v => v).ToList();
        int mid = sorted.Count / 2;
        return sorted.Count % 2 == 0
            ? (sorted[mid - 1] + sorted[mid]) / 2
            : sorted[mid];
    }
}

Relationship to Other Packages

FractalDataWorks.Calculations.Abstractions (this package)
    Implements interfaces from:
    +-- FractalDataWorks.Results (IGenericResult)
    +-- FractalDataWorks.Collections (TypeCollection infrastructure)
    +-- FractalDataWorks.Services.Data.Abstractions (IDataGateway)
    +-- FractalDataWorks.Commands.Data.Abstractions (IDataCommand)

    Implemented by:
    +-- FractalDataWorks.Calculations (concrete implementations)

    Extended by:
    +-- FractalDataWorks.Calculations.Aggregations (aggregation functions)

See Also

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on FractalDataWorks.Calculations.Abstractions:

Package Downloads
FractalDataWorks.Calculations

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Calculations.Aggregations

Development tools and utilities for the FractalDataWorks ecosystem. Build:

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0-rc.1 69 2/9/2026
Loading failed