FractalDataWorks.Commands.Data.Abstractions 0.9.1-alpha.1036

This is a prerelease version of FractalDataWorks.Commands.Data.Abstractions.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package FractalDataWorks.Commands.Data.Abstractions --version 0.9.1-alpha.1036
                    
NuGet\Install-Package FractalDataWorks.Commands.Data.Abstractions -Version 0.9.1-alpha.1036
                    
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.Commands.Data.Abstractions" Version="0.9.1-alpha.1036" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FractalDataWorks.Commands.Data.Abstractions" Version="0.9.1-alpha.1036" />
                    
Directory.Packages.props
<PackageReference Include="FractalDataWorks.Commands.Data.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.Commands.Data.Abstractions --version 0.9.1-alpha.1036
                    
#r "nuget: FractalDataWorks.Commands.Data.Abstractions, 0.9.1-alpha.1036"
                    
#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.Commands.Data.Abstractions@0.9.1-alpha.1036
                    
#: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.Commands.Data.Abstractions&version=0.9.1-alpha.1036&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FractalDataWorks.Commands.Data.Abstractions&version=0.9.1-alpha.1036&prerelease
                    
Install as a Cake Tool

FractalDataWorks.Commands.Data.Abstractions

Universal data command abstractions for the FractalDataWorks Developer Kit.

Overview

This project provides the core abstractions for universal data commands that work across any data store type (SQL, REST, GraphQL, File, etc.). The key principle is "write once, run anywhere" - the same IDataCommand can execute against different backend stores simply by changing configuration.

Core Concepts

  • IDataCommand - Universal command interface representing data operations
  • IDataCommandTranslator - Converts universal commands to domain-specific commands (SQL, REST, etc.)
  • DataCommandTranslators - TypeCollection for compile-time and runtime translator registration
  • Built-In Translator Pattern - Connections own their translators (injected via DI or Factory)

Architecture (Built-In Translator Pattern)

IDataCommand (universal)
    ↓
DataGateway (simple routing)
    ↓
IDataConnection (owns translator)
    ├── Connection.Execute(IDataCommand)
    ├── _translator.TranslateAsync(IDataCommand)
    └── Execute IConnectionCommand

Flow Example (Built-In Pattern)

// 1. User creates universal command
var command = new QueryDataCommand
{
    ConnectionName = "PrimaryDB",  // Which connection
    ContainerName = "Users",        // Which container (table/endpoint/file)
    // ... filter, projection, etc.
};

// 2. DataGateway routes to connection (simple lookup, no translator provider)
var connection = await connectionProvider.GetConnection("PrimaryDB");

// 3. Connection owns translator - translates internally
var result = await connection.Execute<User>(command);
// Connection flow:
//   → _translator.TranslateAsync(command) → IConnectionCommand (SQL)
//   → Execute SQL: SELECT * FROM [Users] WHERE ...
//   → Return IGenericResult<User>

Core Interfaces

IDataCommand

Base interface for all data commands. Extends IGenericCommand from the Commands.Abstractions project.

public interface IDataCommand : IGenericCommand
{
    /// <summary>
    /// Gets the container name (table, collection, endpoint, file path).
    /// </summary>
    string ContainerName { get; }

    /// <summary>
    /// Gets metadata for the command (connection hints, caching, etc.).
    /// </summary>
    IReadOnlyDictionary<string, object> Metadata { get; }
}

Generic Variants:

  • IDataCommand<TResult> - Command with typed result
  • IDataCommand<TResult, TInput> - Command with typed input and result

Usage Examples:

// Simple query command
public sealed class GetUserCommand : IDataCommand<User>
{
    public string ConnectionName => "PrimaryDB";
    public string ContainerName => "Users";
    public int UserId { get; init; }
}

// Insert command
public sealed class CreateUserCommand : IDataCommand<int, UserDto>
{
    public string ConnectionName => "PrimaryDB";
    public string ContainerName => "Users";
    public UserDto User { get; init; }
}

IDataCommandTranslator

Interface for translating universal commands to domain-specific commands.

public interface IDataCommandTranslator
{
    /// <summary>
    /// Gets the domain name this translator targets (Sql, Rest, File, GraphQL, etc.).
    /// </summary>
    string DomainName { get; }

    /// <summary>
    /// Translates a data command to a connection-specific command.
    /// </summary>
    Task<IGenericResult<IConnectionCommand>> Translate(
        IDataCommand command,
        CancellationToken cancellationToken = default);
}

Translator Examples:

// SQL Server Translator
public sealed class MsSqlDataCommandTranslator : IDataCommandTranslator
{
    public string DomainName => "MsSql";

    public Task<IGenericResult<IConnectionCommand>> Translate(
        IDataCommand command,
        CancellationToken cancellationToken = default)
    {
        // Convert command.ContainerName → SELECT * FROM [TableName]
        // Convert filters → WHERE clauses
        // Convert projections → SELECT columns
        // Return SQL ConnectionCommand
    }
}

// REST API Translator
public sealed class RestDataCommandTranslator : IDataCommandTranslator
{
    public string DomainName => "Rest";

    public Task<IGenericResult<IConnectionCommand>> Translate(
        IDataCommand command,
        CancellationToken cancellationToken = default)
    {
        // Convert command.ContainerName → GET /api/endpoint
        // Convert filters → OData $filter query params
        // Convert projections → $select query params
        // Return HTTP ConnectionCommand
    }
}

DataCommandTranslators (TypeCollection)

TypeCollection for compile-time and runtime translator registration. Used for metadata and connection discovery.

[TypeCollection(typeof(DataCommandTranslatorBase), typeof(IDataCommandTranslator), typeof(DataCommandTranslators))]
public abstract partial class DataCommandTranslators : TypeCollectionBase<DataCommandTranslatorBase, IDataCommandTranslator>
{
    // Compile-time registration (via [TypeOption] attribute)
    // Source generator discovers translators and creates static properties

    // Runtime registration (called by connection types during registration)
    public static void Register(string name, Type translatorType)
    {
        // Connections register their translators for discovery/metadata
        // Example: MsSqlConnection registers MsSqlTranslator
    }

    // Get translator type by domain name (for metadata only)
    public static Type? GetTranslatorType(string domainName)
    {
        // Checks both compile-time and runtime registered translators
    }
}

Registration Examples (Built-In Pattern):

// Compile-time registration (in translator project) - for metadata
[TypeOption(typeof(DataCommandTranslators), "MsSql")]
public sealed class MsSqlTranslatorType : DataCommandTranslatorBase
{
    // ❌ WRONG - Do NOT add Instance property (old/incorrect pattern)
    // public static MsSqlTranslatorType Instance { get; } = new();
    private MsSqlTranslatorType() : base(1, "MsSql", "Sql") { }
}

// Runtime registration (in connection's ServiceTypeOption.Configure())
public override void Configure(IConfiguration configuration)
{
    // Register translator type for metadata/discovery
    DataCommandTranslators.Register("MsSql", typeof(MsSqlDataCommandTranslator));
}

public override void Register(IServiceCollection services)
{
    // Register translator in DI - connection will inject it
    services.AddScoped<IDataCommandTranslator, MsSqlDataCommandTranslator>();

    // Register connection with translator injected via DI (deterministic pattern)
    services.AddScoped<IDataConnection, MsSqlConnection>();
}

Built-In Translator Pattern

No IDataCommandTranslatorProvider - Connections own their translators directly.

Deterministic Pattern (SQL):

public sealed class MsSqlConnection : IDataConnection
{
    private readonly IDataCommandTranslator _translator;
    private readonly ILogger<MsSqlConnection> _logger;

    // Translator injected via constructor DI
    public MsSqlConnection(
        IDataCommandTranslator translator,
        ILogger<MsSqlConnection> logger)
    {
        _translator = translator;
        _logger = logger;
    }

    public async Task<IGenericResult<T>> Execute<T>(IDataCommand command)
    {
        // Translate using owned translator
        var translatedResult = await _translator.TranslateAsync(command);
        if (!translatedResult.IsSuccess) return GenericResult<T>.Failure(translatedResult.Message);

        // Execute translated command
        return await ExecuteSqlCommand<T>(translatedResult.Value);
    }
}

Flexible Pattern (HTTP):

public sealed class HttpConnection : IDataConnection
{
    private readonly IDataCommandTranslator _translator;
    private readonly ILogger<HttpConnection> _logger;

    // Translator selected by factory based on config.TranslatorLanguage
    public HttpConnection(
        HttpConnectionConfig config,
        IDataCommandTranslatorFactory translatorFactory,
        ILogger<HttpConnection> logger)
    {
        // Factory selects: "Rest", "GraphQL", "OData", etc.
        _translator = translatorFactory.GetTranslator(config.TranslatorLanguage);
        _logger = logger;
    }

    public async Task<IGenericResult<T>> Execute<T>(IDataCommand command)
    {
        // Translate using owned translator
        var translatedResult = await _translator.TranslateAsync(command);
        if (!translatedResult.IsSuccess) return GenericResult<T>.Failure(translatedResult.Message);

        // Execute HTTP request
        return await ExecuteHttpCommand<T>(translatedResult.Value);
    }
}

Project Structure

FractalDataWorks.Commands.Data.Abstractions/
├── Commands/
│   ├── IDataCommand.cs                    # Base command interface
│   ├── IDataCommand{TResult}.cs           # Generic command interface
│   ├── IDataCommand{TResult,TInput}.cs    # Generic command with input
│   ├── DataCommandBase.cs                 # Base command implementation
│   ├── DataCommandBase{TResult}.cs        # Generic base implementation
│   ├── DataCommandBase{TResult,TInput}.cs # Generic base with input
│   └── DataCommands.cs                    # TypeCollection for commands
├── Translators/
│   ├── IDataCommandTranslator.cs          # Translator interface
│   ├── DataCommandTranslatorBase.cs       # Base translator implementation
│   ├── DataCommandTranslators.cs          # TypeCollection for metadata/discovery
│   └── Logging/
│       └── DataCommandTranslatorLog.cs    # Source-generated logging
├── Expressions/
│   ├── IFilterExpression.cs               # Filter expression interface
│   ├── IProjectionExpression.cs           # Projection interface
│   └── ... (other expression types)
├── Operators/
│   ├── FilterOperators.cs                 # TypeCollection of filter operators
│   ├── LogicalOperator.cs                 # AND/OR EnhancedEnum
│   └── SortDirection.cs                   # ASC/DESC EnhancedEnum
└── Messages/
    └── DataCommandMessages.cs             # Structured messages

Usage Examples

Example 1: Simple Query Command

using FractalDataWorks.Commands.Data.Abstractions;

public sealed class GetUsersCommand : DataCommandBase<IEnumerable<User>>
{
    public GetUsersCommand(string connectionName)
        : base(connectionName, "Users")
    {
    }

    // Optional: Add filter metadata
    public string? NameFilter { get; init; }
}

// Execute via DataGateway
var command = new GetUsersCommand("PrimaryDB")
{
    NameFilter = "John"
};

var result = await dataGateway.Execute<IEnumerable<User>>(command);
if (result.IsSuccess)
{
    foreach (var user in result.Value)
    {
        Console.WriteLine($"User: {user.Name}");
    }
}

Example 2: Translator Registration (in Connection ServiceTypeOption)

[ServiceTypeOption(typeof(ConnectionTypes), "MsSql")]
public sealed class MsSqlConnectionType : ConnectionTypeBase<...>
{
    public override void Configure(IConfiguration configuration)
    {
        // Register translator at runtime
        DataCommandTranslators.Register("MsSql", typeof(MsSqlDataCommandTranslator));
    }

    public override void Register(IServiceCollection services)
    {
        // Register translator in DI
        services.AddScoped<IDataCommandTranslator, MsSqlDataCommandTranslator>();

        // Register connection
        services.AddScoped<IDataConnection, MsSqlConnection>();
    }
}

Example 3: Custom Translator Implementation

public sealed class CustomApiTranslator : IDataCommandTranslator
{
    private readonly ILogger<CustomApiTranslator> _logger;

    public CustomApiTranslator(ILogger<CustomApiTranslator> logger)
    {
        _logger = logger;
    }

    public string DomainName => "CustomApi";

    public Task<IGenericResult<IConnectionCommand>> Translate(
        IDataCommand command,
        CancellationToken cancellationToken = default)
    {
        try
        {
            // Build custom API request from command
            var apiUrl = $"/api/{command.ContainerName}";

            // Add filters from metadata
            if (command.Metadata.TryGetValue("Filter", out var filter))
            {
                apiUrl += $"?filter={filter}";
            }

            // Create HTTP connection command
            var connectionCommand = new HttpConnectionCommand
            {
                Method = "GET",
                Url = apiUrl
            };

            return Task.FromResult(GenericResult<IConnectionCommand>.Success(connectionCommand));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to translate command for {Container}", command.ContainerName);
            return Task.FromResult(GenericResult<IConnectionCommand>.Failure(ex.Message));
        }
    }
}

Best Practices

1. Translator Design

DO: Keep translators focused on one domain (SQL, REST, etc.) ✅ DO: Use source-generated logging for translation operations ✅ DO: Return descriptive failure messages ✅ DO: Validate commands before translation

DON'T: Mix multiple domain translations in one translator ❌ DON'T: Throw exceptions - use Result pattern ❌ DON'T: Use switch statements - use TypeCollections/polymorphism

2. Command Design

DO: Keep commands simple and focused ✅ DO: Use metadata for optional/hint information ✅ DO: Provide typed generic variants when possible

DON'T: Put translation logic in commands ❌ DON'T: Reference domain-specific types (SQL, REST) in commands

3. Registration

DO: Use [TypeOption] for compile-time translator discovery ✅ DO: Use DataCommandTranslators.Register() for connection-provided translators ✅ DO: Register translators in ServiceTypeOption.Configure()

DON'T: Register translators manually in Startup.cs ❌ DON'T: Skip DI registration

Integration with Other Projects

With FractalDataWorks.Services.Data (DataGateway)

// DataGateway with Built-In Translator Pattern (simplified routing)
public class DataGatewayService : IDataGateway
{
    private readonly IDataConnectionProvider _connectionProvider;
    private readonly ILogger<DataGatewayService> _logger;

    public async Task<IGenericResult<T>> Execute<T>(IDataCommand command)
    {
        // 1. Get connection by name
        var connectionResult = await _connectionProvider.GetConnection(command.ConnectionName);
        if (!connectionResult.IsSuccess) return GenericResult<T>.Failure(connectionResult.Message);

        var connection = connectionResult.Value;

        // 2. Connection owns translator - just route command to connection
        // Connection handles: Translate → Execute → Return Result
        return await connection.Execute<T>(command);
    }
}

With FractalDataWorks.Data.Translators

// Translator implementations (referenced by connections)
public class MsSqlDataCommandTranslator : IDataCommandTranslator
{
    private readonly ILogger<MsSqlDataCommandTranslator> _logger;

    public MsSqlDataCommandTranslator(ILogger<MsSqlDataCommandTranslator> logger)
    {
        _logger = logger;
    }

    public string DomainName => "MsSql";

    public async Task<IGenericResult<IConnectionCommand>> TranslateAsync(
        IDataCommand command,
        CancellationToken cancellationToken = default)
    {
        // SQL-specific translation logic
        // Builds SELECT/INSERT/UPDATE/DELETE statements from IDataCommand
    }
}

With FractalDataWorks.Services.Connections

// Connections own translators (Built-In Pattern)
public class MsSqlConnectionType : ConnectionTypeBase<...>
{
    public override void Configure(IConfiguration configuration)
    {
        // Register translator type for metadata/discovery
        DataCommandTranslators.Register("MsSql", typeof(MsSqlDataCommandTranslator));
    }

    public override void Register(IServiceCollection services)
    {
        // Register translator in DI
        services.AddScoped<IDataCommandTranslator, MsSqlDataCommandTranslator>();

        // Register connection - translator will be injected
        services.AddScoped<IDataConnection, MsSqlConnection>();
    }
}

Target Frameworks

  • .NET Standard 2.0
  • .NET 10.0

Dependencies

NuGet Packages:

  • Microsoft.Extensions.DependencyInjection.Abstractions
  • Microsoft.Extensions.Logging.Abstractions

Project References:

  • FractalDataWorks.Commands.Abstractions - Base command interfaces
  • FractalDataWorks.Collections - TypeCollection support
  • FractalDataWorks.Results - Result pattern
  • FractalDataWorks.Services.Connections.Abstractions - IConnectionCommand
  • FractalDataWorks.Data.Translators - Concrete translator implementations (MsSql, Rest, GraphQL)
  • FractalDataWorks.Services.Data - DataGateway service that orchestrates translation and execution
  • FractalDataWorks.Services.Connections - Connection implementations that execute translated commands
  • FractalDataWorks.Data.DataStores.Abstractions - DataStore abstractions that identify translator type

Contributing

When adding new translator types (Built-In Pattern):

  1. Create implementation in connection's project or separate translator project
  2. Implement IDataCommandTranslator interface
  3. Use [TypeOption(typeof(DataCommandTranslators), "YourDomain")] for compile-time discovery (optional)
  4. Register at runtime in connection's Configure(): DataCommandTranslators.Register("YourDomain", typeof(YourTranslator))
  5. Register in DI in connection's Register() method
  6. Inject translator into connection via constructor (deterministic) or factory (flexible)
  7. Add source-generated logging
  8. Write unit tests

FractalDataWorks.Commands.Data.Abstractions - Universal data command abstractions for write-once, run-anywhere data operations.

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 (13)

Showing the top 5 NuGet packages that depend on FractalDataWorks.Commands.Data.Abstractions:

Package Downloads
FractalDataWorks.Services.Connections.Abstractions

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Commands.Data

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Services.Connections

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Services.Data

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Services.Connections.MsSql

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.9.5-alpha.1008 15 11/25/2025
0.9.5-alpha.1007 21 11/25/2025
0.9.5-alpha.1006 71 11/25/2025
0.9.1-alpha.1037 12 11/25/2025
0.9.1-alpha.1036 11 11/25/2025
0.9.1-alpha.1035 26 11/25/2025
0.9.1-alpha.1033 32 11/25/2025
0.9.0-alpha.1011.ged0a6c6e98 362 11/18/2025
0.9.0-alpha.1010.gecd88aac50 350 11/18/2025
0.9.0-alpha.1009.g7f6817e985 354 11/18/2025
0.9.0-alpha.1006.gf287016c0c 366 11/18/2025
0.8.0-alpha.1011 348 11/18/2025
0.7.0-alpha.1022 144 11/3/2025
0.7.0-alpha.1021 149 11/3/2025
0.7.0-alpha.1008 112 11/2/2025
0.7.0-alpha.1006 143 10/30/2025
0.7.0-alpha.1005 139 10/30/2025
0.7.0-alpha.1004 149 10/30/2025
0.7.0-alpha.1001 137 10/29/2025
0.6.0-alpha.1006 135 10/29/2025
0.6.0-alpha.1005 140 10/28/2025
0.6.0-alpha.1004 131 10/28/2025