diff --git a/ETL-Abstractions.sln b/ETL-Abstractions.sln
index a80b8315..ab191738 100644
--- a/ETL-Abstractions.sln
+++ b/ETL-Abstractions.sln
@@ -81,84 +81,246 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{AE206253-B766-4B6A-8C08-9E70605A2B27}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wolfgang.Etl.Abstractions.Benchmarks", "benchmarks\Wolfgang.Etl.Abstractions.Benchmarks\Wolfgang.Etl.Abstractions.Benchmarks.csproj", "{7855D034-57F4-4CF0-8EB4-5677EF80EC57}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|x64.Build.0 = Debug|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Debug|x86.Build.0 = Debug|Any CPU
{C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|x64.ActiveCfg = Release|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|x64.Build.0 = Release|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|x86.ActiveCfg = Release|Any CPU
+ {C4987BAD-4513-955F-B3C1-7563D0C1A7A3}.Release|x86.Build.0 = Release|Any CPU
{B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|x64.Build.0 = Debug|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Debug|x86.Build.0 = Debug|Any CPU
{B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|x64.ActiveCfg = Release|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|x64.Build.0 = Release|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|x86.ActiveCfg = Release|Any CPU
+ {B8558C7F-934B-3DC1-AAED-D668CF964C8E}.Release|x86.Build.0 = Release|Any CPU
{F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|x64.Build.0 = Debug|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Debug|x86.Build.0 = Debug|Any CPU
{F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|x64.ActiveCfg = Release|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|x64.Build.0 = Release|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|x86.ActiveCfg = Release|Any CPU
+ {F1BA1AF5-9A71-421B-963C-E277610FBD40}.Release|x86.Build.0 = Release|Any CPU
{B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|x64.Build.0 = Debug|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Debug|x86.Build.0 = Debug|Any CPU
{B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|x64.ActiveCfg = Release|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|x64.Build.0 = Release|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|x86.ActiveCfg = Release|Any CPU
+ {B715D0C5-3F1A-485C-92D1-FFB87A801AC3}.Release|x86.Build.0 = Release|Any CPU
{F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|x64.Build.0 = Debug|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Debug|x86.Build.0 = Debug|Any CPU
{F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|x64.ActiveCfg = Release|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|x64.Build.0 = Release|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|x86.ActiveCfg = Release|Any CPU
+ {F4A2F47C-9687-0ABE-FEAE-D07873E0133A}.Release|x86.Build.0 = Release|Any CPU
{733AD8E6-D170-789A-6F61-13C041011037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{733AD8E6-D170-789A-6F61-13C041011037}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Debug|x64.Build.0 = Debug|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Debug|x86.Build.0 = Debug|Any CPU
{733AD8E6-D170-789A-6F61-13C041011037}.Release|Any CPU.ActiveCfg = Release|Any CPU
{733AD8E6-D170-789A-6F61-13C041011037}.Release|Any CPU.Build.0 = Release|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Release|x64.ActiveCfg = Release|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Release|x64.Build.0 = Release|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Release|x86.ActiveCfg = Release|Any CPU
+ {733AD8E6-D170-789A-6F61-13C041011037}.Release|x86.Build.0 = Release|Any CPU
{2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|x64.Build.0 = Debug|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Debug|x86.Build.0 = Debug|Any CPU
{2DC16382-F59F-4024-B560-D400E09EF91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DC16382-F59F-4024-B560-D400E09EF91F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Release|x64.ActiveCfg = Release|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Release|x64.Build.0 = Release|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Release|x86.ActiveCfg = Release|Any CPU
+ {2DC16382-F59F-4024-B560-D400E09EF91F}.Release|x86.Build.0 = Release|Any CPU
{5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|x64.Build.0 = Debug|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Debug|x86.Build.0 = Debug|Any CPU
{5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|x64.ActiveCfg = Release|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|x64.Build.0 = Release|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|x86.ActiveCfg = Release|Any CPU
+ {5A7CFA9D-DCE7-43FD-AF89-7418C36AAE14}.Release|x86.Build.0 = Release|Any CPU
{483AE567-071E-4797-B13B-84B142D4ED44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{483AE567-071E-4797-B13B-84B142D4ED44}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Debug|x64.Build.0 = Debug|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Debug|x86.Build.0 = Debug|Any CPU
{483AE567-071E-4797-B13B-84B142D4ED44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{483AE567-071E-4797-B13B-84B142D4ED44}.Release|Any CPU.Build.0 = Release|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Release|x64.ActiveCfg = Release|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Release|x64.Build.0 = Release|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Release|x86.ActiveCfg = Release|Any CPU
+ {483AE567-071E-4797-B13B-84B142D4ED44}.Release|x86.Build.0 = Release|Any CPU
{6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|x64.Build.0 = Debug|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Debug|x86.Build.0 = Debug|Any CPU
{6C19204D-7CC8-48D2-A475-49CD98931105}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C19204D-7CC8-48D2-A475-49CD98931105}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Release|x64.ActiveCfg = Release|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Release|x64.Build.0 = Release|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Release|x86.ActiveCfg = Release|Any CPU
+ {6C19204D-7CC8-48D2-A475-49CD98931105}.Release|x86.Build.0 = Release|Any CPU
{E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|x64.Build.0 = Debug|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Debug|x86.Build.0 = Debug|Any CPU
{E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|x64.ActiveCfg = Release|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|x64.Build.0 = Release|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|x86.ActiveCfg = Release|Any CPU
+ {E858F22E-01D7-4BE9-B8DE-0E4AFBA5B33A}.Release|x86.Build.0 = Release|Any CPU
{8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|x64.Build.0 = Debug|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Debug|x86.Build.0 = Debug|Any CPU
{8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|x64.ActiveCfg = Release|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|x64.Build.0 = Release|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|x86.ActiveCfg = Release|Any CPU
+ {8068B622-46A9-4ABA-BDA3-6AB259D1682C}.Release|x86.Build.0 = Release|Any CPU
{6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|x64.Build.0 = Debug|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Debug|x86.Build.0 = Debug|Any CPU
{6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|x64.ActiveCfg = Release|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|x64.Build.0 = Release|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|x86.ActiveCfg = Release|Any CPU
+ {6DA63E99-692F-461C-983A-270E5CBE8D45}.Release|x86.Build.0 = Release|Any CPU
{6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|x64.Build.0 = Debug|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Debug|x86.Build.0 = Debug|Any CPU
{6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|x64.ActiveCfg = Release|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|x64.Build.0 = Release|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|x86.ActiveCfg = Release|Any CPU
+ {6BD7828E-55B4-4213-8DF9-7BFBA891B8EE}.Release|x86.Build.0 = Release|Any CPU
{2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|x64.Build.0 = Debug|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Debug|x86.Build.0 = Debug|Any CPU
{2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|x64.ActiveCfg = Release|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|x64.Build.0 = Release|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|x86.ActiveCfg = Release|Any CPU
+ {2D14E222-4E44-40AB-82EF-1E8ABCED0476}.Release|x86.Build.0 = Release|Any CPU
{861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|x64.Build.0 = Debug|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Debug|x86.Build.0 = Debug|Any CPU
{861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|Any CPU.ActiveCfg = Release|Any CPU
{861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|Any CPU.Build.0 = Release|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|x64.ActiveCfg = Release|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|x64.Build.0 = Release|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|x86.ActiveCfg = Release|Any CPU
+ {861EA36D-970E-4CFE-9E72-D3D12F0BBB60}.Release|x86.Build.0 = Release|Any CPU
{80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|x64.Build.0 = Debug|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Debug|x86.Build.0 = Debug|Any CPU
{80E49C71-1073-4208-B48F-E0F399946B3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80E49C71-1073-4208-B48F-E0F399946B3B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Release|x64.ActiveCfg = Release|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Release|x64.Build.0 = Release|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Release|x86.ActiveCfg = Release|Any CPU
+ {80E49C71-1073-4208-B48F-E0F399946B3B}.Release|x86.Build.0 = Release|Any CPU
{85A15A15-D528-4542-A546-63BE0EAED986}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A15A15-D528-4542-A546-63BE0EAED986}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Debug|x64.Build.0 = Debug|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Debug|x86.Build.0 = Debug|Any CPU
{85A15A15-D528-4542-A546-63BE0EAED986}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A15A15-D528-4542-A546-63BE0EAED986}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Release|x64.ActiveCfg = Release|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Release|x64.Build.0 = Release|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Release|x86.ActiveCfg = Release|Any CPU
+ {85A15A15-D528-4542-A546-63BE0EAED986}.Release|x86.Build.0 = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|x64.Build.0 = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Debug|x86.Build.0 = Debug|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|x64.ActiveCfg = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|x64.Build.0 = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|x86.ActiveCfg = Release|Any CPU
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -186,6 +348,7 @@ Global
{85A15A15-D528-4542-A546-63BE0EAED986} = {336D72A1-8E5E-49DE-83D9-DF6BE458BA24}
{AF971B90-A335-49AF-8AB6-F387CAED12E4} = {9B9A162C-C5B8-495C-A6D0-8C3135E283B9}
{2D19706F-4199-46BD-B047-C4ED3AEDD90A} = {9B9A162C-C5B8-495C-A6D0-8C3135E283B9}
+ {7855D034-57F4-4CF0-8EB4-5677EF80EC57} = {AE206253-B766-4B6A-8C08-9E70605A2B27}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F673635D-58CE-48A5-9AE4-31F4484BED9E}
diff --git a/benchmarks/.editorconfig b/benchmarks/.editorconfig
new file mode 100644
index 00000000..0352d900
--- /dev/null
+++ b/benchmarks/.editorconfig
@@ -0,0 +1,16 @@
+# Analyzer rules relaxed for benchmark projects
+
+[*.cs]
+
+# AsyncFixer01: Remove async/await — benchmark components use async-iterator
+# conventions and intentionally minimal awaits
+dotnet_diagnostic.AsyncFixer01.severity = none
+
+# MA0004: Use ConfigureAwait(false) — not needed in the benchmark harness
+dotnet_diagnostic.MA0004.severity = none
+
+# S1215: Remove use of GC.GetTotalMemory — required for memory benchmarks
+dotnet_diagnostic.S1215.severity = none
+
+# VSTHRD200: Use Async suffix — benchmark methods follow BenchmarkDotNet naming conventions
+dotnet_diagnostic.VSTHRD200.severity = none
diff --git a/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/BenchmarkComponents.cs b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/BenchmarkComponents.cs
new file mode 100644
index 00000000..208fa400
--- /dev/null
+++ b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/BenchmarkComponents.cs
@@ -0,0 +1,161 @@
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Wolfgang.Etl.Abstractions;
+
+namespace Wolfgang.Etl.Abstractions.Benchmarks;
+
+// ----------------------------------------------------------------------
+// Base-class-derived components — exercise the ExtractorBase / TransformerBase
+// / LoaderBase machinery (Interlocked counters, progress plumbing, the async
+// iterator wrapper) over a purely in-memory sequence so the benchmark measures
+// the abstraction overhead, not any I/O.
+// ----------------------------------------------------------------------
+
+/// An extractor that yields 0..count-1 from memory.
+internal sealed class SequenceExtractor : ExtractorBase
+{
+ private readonly int _count;
+
+
+
+ public SequenceExtractor(int count)
+ {
+ _count = count;
+ }
+
+
+
+ protected override async IAsyncEnumerable ExtractWorkerAsync
+ (
+ [EnumeratorCancellation] CancellationToken token
+ )
+ {
+ for (var i = 0; i < _count; i++)
+ {
+ IncrementCurrentItemCount();
+ yield return i;
+ }
+
+ await Task.CompletedTask;
+ }
+
+
+
+ protected override Report CreateProgressReport()
+ {
+ return new Report(CurrentItemCount);
+ }
+}
+
+
+
+/// A pass-through transformer that yields each source item unchanged.
+internal sealed class PassThroughTransformer : TransformerBase
+{
+ protected override async IAsyncEnumerable TransformWorkerAsync
+ (
+ IAsyncEnumerable items,
+ [EnumeratorCancellation] CancellationToken token
+ )
+ {
+ await foreach (var item in items.WithCancellation(token))
+ {
+ IncrementCurrentItemCount();
+ yield return item;
+ }
+ }
+
+
+
+ protected override Report CreateProgressReport()
+ {
+ return new Report(CurrentItemCount);
+ }
+}
+
+
+
+/// A loader that drains the sequence, counting items.
+internal sealed class CountingLoader : LoaderBase
+{
+ protected override async Task LoadWorkerAsync
+ (
+ IAsyncEnumerable items,
+ CancellationToken token
+ )
+ {
+ await foreach (var _ in items.WithCancellation(token))
+ {
+ IncrementCurrentItemCount();
+ }
+ }
+
+
+
+ protected override Report CreateProgressReport()
+ {
+ return new Report(CurrentItemCount);
+ }
+}
+
+
+
+// ----------------------------------------------------------------------
+// Interface-only components — implement just the simplest (no-progress,
+// no-cancellation) ETL interfaces so the fluent Pipeline composition resolves
+// to its leanest path, isolating the cost of the Pipeline plumbing itself.
+// ----------------------------------------------------------------------
+
+/// A minimal over an in-memory range.
+internal sealed class RangeExtractor : IExtractAsync
+{
+ private readonly int _count;
+
+
+
+ public RangeExtractor(int count)
+ {
+ _count = count;
+ }
+
+
+
+ public async IAsyncEnumerable ExtractAsync()
+ {
+ for (var i = 0; i < _count; i++)
+ {
+ yield return i;
+ }
+
+ await Task.CompletedTask;
+ }
+}
+
+
+
+/// A minimal pass-through .
+internal sealed class IdentityTransformer : ITransformAsync
+{
+ public async IAsyncEnumerable TransformAsync(IAsyncEnumerable items)
+ {
+ await foreach (var item in items)
+ {
+ yield return item;
+ }
+ }
+}
+
+
+
+/// A minimal that drains the sequence.
+internal sealed class SinkLoader : ILoadAsync
+{
+ public async Task LoadAsync(IAsyncEnumerable items)
+ {
+ await foreach (var _ in items)
+ {
+ }
+ }
+}
diff --git a/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/ExtractorBenchmarks.cs b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/ExtractorBenchmarks.cs
new file mode 100644
index 00000000..8e915d9c
--- /dev/null
+++ b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/ExtractorBenchmarks.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Wolfgang.Etl.Abstractions;
+
+namespace Wolfgang.Etl.Abstractions.Benchmarks;
+
+///
+/// Measures the per-item overhead the
+/// machinery adds on top of a bare in-memory sequence — the async-iterator
+/// wrapper, the Interlocked-based item counter, and the progress path
+/// (timer creation + a final progress report).
+///
+[MemoryDiagnoser]
+public class ExtractorBenchmarks
+{
+ [Params(1_000, 100_000)]
+ public int RecordCount { get; set; }
+
+
+
+ [Benchmark(Baseline = true)]
+ public async Task Extract_NoProgress()
+ {
+ var extractor = new SequenceExtractor(RecordCount);
+
+ var count = 0;
+ await foreach (var _ in extractor.ExtractAsync())
+ {
+ count++;
+ }
+
+ return count;
+ }
+
+
+
+ [Benchmark]
+ public async Task Extract_WithProgress()
+ {
+ var extractor = new SequenceExtractor(RecordCount);
+ IProgress progress = new Sink();
+
+ var count = 0;
+ await foreach (var _ in extractor.ExtractAsync(progress))
+ {
+ count++;
+ }
+
+ return count;
+ }
+
+
+
+ // Synchronous no-op progress sink — avoids the SynchronizationContext
+ // posting that System.Progress would add as benchmark noise.
+ private sealed class Sink : IProgress
+ {
+ public void Report(Report value)
+ {
+ }
+ }
+}
diff --git a/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/PipelineBenchmarks.cs b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/PipelineBenchmarks.cs
new file mode 100644
index 00000000..ee8c914a
--- /dev/null
+++ b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/PipelineBenchmarks.cs
@@ -0,0 +1,59 @@
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Wolfgang.Etl.Abstractions;
+
+namespace Wolfgang.Etl.Abstractions.Benchmarks;
+
+///
+/// Measures the cost of composing and running a full Extract → Transform → Load
+/// pipeline. Compares the fluent builder against hand-wired
+/// composition over the same in-memory stages,
+/// so the delta is the builder's plumbing overhead (it should be negligible — the
+/// builder is documented as zero-extra-allocation sugar over the same composition).
+///
+[MemoryDiagnoser]
+public class PipelineBenchmarks
+{
+ [Params(1_000, 100_000)]
+ public int RecordCount { get; set; }
+
+
+
+ [Benchmark(Baseline = true)]
+ public async Task FluentPipeline()
+ {
+ await Pipeline
+ .Extract(new RangeExtractor(RecordCount))
+ .Transform(new IdentityTransformer())
+ .Load(new SinkLoader())
+ .RunAsync();
+ }
+
+
+
+ [Benchmark]
+ public async Task ManualComposition()
+ {
+ var extractor = new RangeExtractor(RecordCount);
+ var transformer = new IdentityTransformer();
+ var loader = new SinkLoader();
+
+ await loader.LoadAsync(transformer.TransformAsync(extractor.ExtractAsync()));
+ }
+
+
+
+ // Same Extract -> Transform -> Load shape, but wired with the base-class
+ // components (ExtractorBase / TransformerBase / LoaderBase) so the result
+ // captures the full abstraction overhead — Interlocked item counting and
+ // the async-iterator wrappers on every stage.
+ [Benchmark]
+ public async Task BaseClassComposition()
+ {
+ var extractor = new SequenceExtractor(RecordCount);
+ var transformer = new PassThroughTransformer();
+ var loader = new CountingLoader();
+
+ await loader.LoadAsync(transformer.TransformAsync(extractor.ExtractAsync()));
+ }
+}
diff --git a/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Program.cs b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Program.cs
new file mode 100644
index 00000000..87c286f8
--- /dev/null
+++ b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Program.cs
@@ -0,0 +1,5 @@
+using BenchmarkDotNet.Running;
+
+BenchmarkSwitcher
+ .FromAssembly(typeof(Program).Assembly)
+ .Run(args);
diff --git a/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Wolfgang.Etl.Abstractions.Benchmarks.csproj b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Wolfgang.Etl.Abstractions.Benchmarks.csproj
new file mode 100644
index 00000000..a1ef3e46
--- /dev/null
+++ b/benchmarks/Wolfgang.Etl.Abstractions.Benchmarks/Wolfgang.Etl.Abstractions.Benchmarks.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net10.0
+ latest
+ disable
+
+
+
+
+
+
+
+
+
+
+
+
+