FractalDataWorks.Calculations.Abstractions
0.6.0-rc.1
dotnet add package FractalDataWorks.Calculations.Abstractions --version 0.6.0-rc.1
NuGet\Install-Package FractalDataWorks.Calculations.Abstractions -Version 0.6.0-rc.1
<PackageReference Include="FractalDataWorks.Calculations.Abstractions" Version="0.6.0-rc.1" />
<PackageVersion Include="FractalDataWorks.Calculations.Abstractions" Version="0.6.0-rc.1" />
<PackageReference Include="FractalDataWorks.Calculations.Abstractions" />
paket add FractalDataWorks.Calculations.Abstractions --version 0.6.0-rc.1
#r "nuget: FractalDataWorks.Calculations.Abstractions, 0.6.0-rc.1"
#:package FractalDataWorks.Calculations.Abstractions@0.6.0-rc.1
#addin nuget:?package=FractalDataWorks.Calculations.Abstractions&version=0.6.0-rc.1&prerelease
#tool nuget:?package=FractalDataWorks.Calculations.Abstractions&version=0.6.0-rc.1&prerelease
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 -
ICalculationContextfor accessing data sources during execution - Calculation Base Class -
CalculationBase<TInput, TOutput>for common implementation patterns - Calculation Types -
ICalculationTypeandCalculationTypeBaseTypeCollection for extensible calculation types - Period Comparison Types -
IPeriodComparisonTypeTypeCollection for time-series analysis - Fluent Builders - Builder interfaces for constructing calculations programmatically
- Railway-Oriented Programming - Integration with
IGenericResultfor 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
IGenericResultreturn types - Explicit dependency declarations via
RequiredDataSetsandDependsOn - 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
IDataGatewayfor 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
- Immutable Input - Treat input data as immutable; do not modify it during execution
- Use Context for Data - Always use
ICalculationContextfor data access, never inject repositories directly - Return Results, Not Exceptions - Use
IGenericResultfor expected failures - Validate Early - Implement
Validate()to catch configuration issues before execution - Cancellation Support - Honor
CancellationTokenfor long-running calculations - Declare Dependencies - Override
RequiredDataSetsandDependsOnto declare dependencies explicitly - Meaningful IDs - Use descriptive
CalculationIdvalues for logging and tracking - 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
- FractalDataWorks.Results - Result types and Railway-Oriented Programming
- FractalDataWorks.Collections - TypeCollection pattern documentation
- FractalDataWorks.Calculations - Concrete calculation implementations
- FractalDataWorks.Calculations.Aggregations - Aggregation function TypeCollection
| Product | Versions 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. |
-
.NETStandard 2.0
- FractalDataWorks.Collections (>= 0.6.0-rc.1)
- FractalDataWorks.Commands.Data.Abstractions (>= 0.6.0-rc.1)
- FractalDataWorks.Data.Abstractions (>= 0.6.0-rc.1)
- FractalDataWorks.Results (>= 0.6.0-rc.1)
- FractalDataWorks.Services.Data.Abstractions (>= 0.6.0-rc.1)
- System.Collections.Immutable (>= 10.0.1)
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.