Wolfgang.Etl.Transformers
0.5.2
Prefix Reserved
dotnet add package Wolfgang.Etl.Transformers --version 0.5.2
NuGet\Install-Package Wolfgang.Etl.Transformers -Version 0.5.2
<PackageReference Include="Wolfgang.Etl.Transformers" Version="0.5.2" />
<PackageVersion Include="Wolfgang.Etl.Transformers" Version="0.5.2" />
<PackageReference Include="Wolfgang.Etl.Transformers" />
paket add Wolfgang.Etl.Transformers --version 0.5.2
#r "nuget: Wolfgang.Etl.Transformers, 0.5.2"
#:package Wolfgang.Etl.Transformers@0.5.2
#addin nuget:?package=Wolfgang.Etl.Transformers&version=0.5.2
#tool nuget:?package=Wolfgang.Etl.Transformers&version=0.5.2
Wolfgang.Etl.Transformers
A collection of generic, composable transformers for ETL pipelines built on Wolfgang.Etl.Abstractions.
Installation
dotnet add package Wolfgang.Etl.Transformers
Quick Start
using Wolfgang.Etl.Transformers;
// Build a pipeline: parse → filter → project → buffer
var pipeline = new SelectTransformer<string, Order>(ParseOrder)
.Then(new WhereTransformer<Order>(o => o.IsValid))
.Then(new SelectTransformer<Order, InvoiceRow>(ToInvoice));
await foreach (var row in pipeline.TransformAsync(rawLines))
{
await loader.LoadAsync(row);
}
// Or buffer inline between pipeline stages:
var buffered = rawLines.Buffered(capacity: 500);
var filtered = new WhereTransformer<Order>(o => o.IsValid);
var projected = new SelectTransformer<Order, InvoiceRow>(ToInvoice);
await foreach (var row in projected.TransformAsync(filtered.TransformAsync(buffered)))
{
await loader.LoadAsync(row);
}
Transformers
LINQ-style
| Transformer | Description |
|---|---|
WhereTransformer<T> |
Filters items by a sync or async predicate |
SelectTransformer<TSource, TDestination> |
Projects each item with a sync or async selector |
SelectManyTransformer<TSource, TDestination> |
Fan-out: maps each item to a sequence (sync or async) |
OfTypeTransformer<TSource, TDestination> |
Passes only items that are assignable to TDestination |
CastTransformer<TSource, TDestination> |
Casts each item; throws on incompatible types |
DistinctTransformer<T> |
Deduplicates using the default or a supplied IEqualityComparer<T> |
DistinctByTransformer<TSource, TKey> |
Deduplicates by a key selector |
TakeTransformer<T> |
Yields only the first N items |
TakeWhileTransformer<T> |
Yields items while a predicate holds |
SkipTransformer<T> |
Skips the first N items |
SkipWhileTransformer<T> |
Skips items while a predicate holds |
ChunkTransformer<T> |
Batches items into fixed-size arrays |
Pipeline infrastructure
| Transformer | Description |
|---|---|
PassThroughTransformer<T> |
Identity pass-through; also implements ITransformWithCancellationAsync<T, T> |
BufferedTransformer<T> |
Decouples producer from consumer via a System.Threading.Channels buffer |
ProgressReportingTransformer<T> |
Calls a sync or async callback per item without altering the stream |
ThrottleTransformer<T> |
Paces items at least a minimum TimeSpan apart (adaptive; honours cancellation) without altering the stream |
Composition
| Type / Method | Description |
|---|---|
ChainTransformer<TSource, TIntermediate, TDestination> |
Composes two ITransformAsync transformers into one |
ChainTransformerWithCancellation<TSource, TIntermediate, TDestination> |
Same as above but propagates CancellationToken through both stages |
TransformerExtensions.Then(...) |
Fluent composition — two overloads: one for ITransformAsync pairs, one for ITransformWithCancellationAsync pairs |
TransformerExtensions.Buffered(...) |
Inline buffer insertion — sugar for new BufferedTransformer<T>(n).TransformAsync(source) |
Pipeline operators
Referencing this package lights up LINQ-flavored operators on IEtlPipeline<T> (the pipeline core from Wolfgang.Etl.Abstractions). Each operator is a thin wrapper over the matching transformer, so they slot between the source (From(...)) and sink (To(...)) stages of a fluent pipeline:
using Wolfgang.Etl.Transformers;
await EtlPipeline
.Create()
.From(records)
.Where(r => r.Amount > 0)
.Select(r => r.Id)
.Distinct()
.Chunk(500)
.To(loader)
.RunAsync();
Data-shape operators: Where, Select, SelectMany (each with sync and async overloads), Distinct, DistinctBy, Take, Skip, TakeWhile, SkipWhile, Chunk, Buffered, Cast, and OfType.
Observability operators (watch or pace the stream without changing its shape): Tap (sync/async side effect per item, passed through unchanged); Log (Log(format, sink) — one formatted message per item via a delegate sink, no logging-framework dependency); Throttle (Throttle(minInterval) — paces items at least a TimeSpan apart to rate-limit a downstream sink).
🎯 Supported Frameworks
This library targets:
- .NET Framework: 4.6.2, 4.7.2, 4.8, 4.8.1
- .NET Standard: 2.0
- .NET: 5.0, 6.0, 7.0, 8.0, 9.0, 10.0
See the NuGet package page for the authoritative per-TFM compatibility matrix.
Code Quality & Static Analysis
This project enforces strict code quality standards through 7 specialized analyzers and custom async-first rules:
Analyzers in Use
- Microsoft.CodeAnalysis.NetAnalyzers — Correctness, performance, and security rules
- Roslynator.Analyzers — 500+ refactoring and code quality rules
- AsyncFixer — Async/await best practices and anti-pattern detection
- Microsoft.VisualStudio.Threading.Analyzers — Thread safety and async patterns
- Microsoft.CodeAnalysis.BannedApiAnalyzers — Blocks synchronous APIs listed in
BannedSymbols.txt - Meziantou.Analyzer — Comprehensive code quality checks
- SonarAnalyzer.CSharp — Industry-standard code analysis
Async-First Enforcement
This library prohibits synchronous blocking calls via BannedSymbols.txt:
// ❌ Banned
task.Wait();
task.Result;
File.ReadAllText(path);
Thread.Sleep(1000);
// ✅ Required
await task;
await File.ReadAllTextAsync(path);
await Task.Delay(1000);
Building from Source
Prerequisites
- .NET 10.0 SDK or later (required to build the full TFM matrix)
- Optional: PowerShell Core for formatting scripts
Build Steps
# Clone the repository
git clone https://github.com/Chris-Wolfgang/ETL-Transformers.git
cd ETL-Transformers
# Restore dependencies
dotnet restore
# Build (Release enforces all analyzers as errors)
dotnet build --configuration Release
# Run tests
dotnet test --configuration Release
# Format code
pwsh ./scripts/format.ps1
Building Documentation
This project uses DocFX for API documentation:
dotnet tool install -g docfx
cd docfx_project
docfx build --serve
# Open http://localhost:8080
Documentation is automatically built and deployed to GitHub Pages when a GitHub Release is published.
Documentation: https://Chris-Wolfgang.github.io/ETL-Transformers/
Verify the build
This package is built reproducibly: rebuilding a tagged
release with the pinned SDK produces byte-for-byte identical assemblies and packages.
Every release attaches a reproducible-build-manifest.json with the expected SHA-256 of
each artifact, and CI proves cross-OS reproducibility on every pull request.
To confirm a published release was built from source — and to publish your own independent verification attestation — follow the step-by-step guide in REPRODUCIBLE-BUILD.md.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for code quality standards, build instructions, and pull request guidelines.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Acknowledgments
Built on Wolfgang.Etl.Abstractions — the base class library providing ExtractorBase<TSource, TProgress>, LoaderBase<TDestination, TProgress>, and TransformerBase<TSource, TDestination, TProgress>.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. 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 is compatible. 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 is compatible. 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 is compatible. 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 is compatible. 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 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 is compatible. net481 is compatible. |
| 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. |
-
.NETFramework 4.6.2
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
.NETFramework 4.7.2
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
.NETFramework 4.8
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
.NETFramework 4.8.1
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net10.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net5.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net6.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net7.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net8.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
-
net9.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.11)
- System.Threading.Channels (>= 10.0.11)
- Wolfgang.Etl.Abstractions (>= 0.23.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.