From 16f426c36e0f40eba62bd804718003db0a2b85c8 Mon Sep 17 00:00:00 2001 From: Andrei Ignat Date: Tue, 16 Sep 2025 21:51:06 +0300 Subject: [PATCH 1/2] unflat1 --- README.md | 97 ++- later.md | 30 +- v2/Generator/MultiGeneratorV2.cs | 5 + v2/Generator/all.csv | 1 + v2/RSCGExamplesData/GeneratorDataRec.json | 6 + v2/RSCGExamplesData/NoExample.json | 5 - v2/rscg_examples/Unflat/description.json | 22 + v2/rscg_examples/Unflat/nuget.txt | 1 + v2/rscg_examples/Unflat/readme.txt | 157 ++++ .../Unflat/src/.tours/Unflat.tour | 42 + v2/rscg_examples/Unflat/src/Unflat.sln | 34 + .../Unflat/src/UnflatDemo/Person.cs | 10 + .../Unflat/src/UnflatDemo/Program.cs | 30 + .../Unflat/src/UnflatDemo/UnflatDemo.csproj | 19 + v2/rscg_examples/Unflat/video.json | 39 + .../docs/Categories/Database.md | 4 +- .../docs/Categories/_PrimitiveDatabase.mdx | 2 + v2/rscg_examples_site/docs/NoExamples.md | 194 +++-- .../docs/RSCG-Examples/Facet.md | 2 +- .../docs/RSCG-Examples/Unflat.md | 732 ++++++++++++++++++ .../docs/RSCG-Examples/index.md | 13 +- v2/rscg_examples_site/docs/about.md | 2 +- v2/rscg_examples_site/docs/indexRSCG.md | 5 +- .../src/components/HomepageFeatures/index.js | 2 +- .../static/exports/RSCG.json | 8 + .../static/exports/RSCG.xlsx | Bin 12425 -> 12458 bytes 26 files changed, 1290 insertions(+), 172 deletions(-) create mode 100644 v2/rscg_examples/Unflat/description.json create mode 100644 v2/rscg_examples/Unflat/nuget.txt create mode 100644 v2/rscg_examples/Unflat/readme.txt create mode 100644 v2/rscg_examples/Unflat/src/.tours/Unflat.tour create mode 100644 v2/rscg_examples/Unflat/src/Unflat.sln create mode 100644 v2/rscg_examples/Unflat/src/UnflatDemo/Person.cs create mode 100644 v2/rscg_examples/Unflat/src/UnflatDemo/Program.cs create mode 100644 v2/rscg_examples/Unflat/src/UnflatDemo/UnflatDemo.csproj create mode 100644 v2/rscg_examples/Unflat/video.json create mode 100644 v2/rscg_examples_site/docs/RSCG-Examples/Unflat.md diff --git a/README.md b/README.md index 09faafa44..90845fb76 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# RSCG - 229 Examples of Roslyn Source Code Generators / 14 created by Microsoft / +# RSCG - 230 Examples of Roslyn Source Code Generators / 14 created by Microsoft / -## Latest Update : 2025-08-17 => 17 August 2025 +## Latest Update : 2025-08-18 => 18 August 2025 If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)*** @@ -20,8 +20,30 @@ If you want to be notified each time I add a new RSCG example , please click htt ## Content -Those are the 229 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 230 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 14 from Microsoft ) +### 230. [Unflat](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat) , in the [Database](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#database) category + +Generated on : 2025-08-18 => 18 August 2025 + +
+ Expand + + + +Author: pstlnce + +AOT ORM Сode generator for fast parsing DataReader into complex classes/structs with zero allocations + +Nuget: [https://www.nuget.org/packages/Unflat/](https://www.nuget.org/packages/Unflat/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat) + +Source: [https://github.com/pstlnce/unflat](https://github.com/pstlnce/unflat) + +
+ ### 229. [Facet](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Facet) , in the [Mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) category Generated on : 2025-08-17 => 17 August 2025 @@ -5446,224 +5468,217 @@ Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/pierre3/PlantUmlClassDiagramGenerator&body=https://github.com/pierre3/PlantUmlClassDiagramGenerator -32) [https://github.com/pstlnce/unflat]( https://github.com/pstlnce/unflat) , https://github.com/pstlnce/unflat - -Why I have not tested : later - -https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/pstlnce/unflat&body=https://github.com/pstlnce/unflat - - -33) [https://github.com/stbychkov/AutoLoggerMessage]( https://github.com/stbychkov/AutoLoggerMessage) , https://github.com/stbychkov/AutoLoggerMessage +32) [https://github.com/stbychkov/AutoLoggerMessage]( https://github.com/stbychkov/AutoLoggerMessage) , https://github.com/stbychkov/AutoLoggerMessage Why I have not tested : Microsoft have done same feature https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/stbychkov/AutoLoggerMessage&body=https://github.com/stbychkov/AutoLoggerMessage -34) [https://github.com/Stepami/visitor-net]( https://github.com/Stepami/visitor-net) , https://github.com/Stepami/visitor-net +33) [https://github.com/Stepami/visitor-net]( https://github.com/Stepami/visitor-net) , https://github.com/Stepami/visitor-net Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/Stepami/visitor-net&body=https://github.com/Stepami/visitor-net -35) [https://github.com/svee4/RequiredStaticMembers]( https://github.com/svee4/RequiredStaticMembers) , https://github.com/svee4/RequiredStaticMembers +34) [https://github.com/svee4/RequiredStaticMembers]( https://github.com/svee4/RequiredStaticMembers) , https://github.com/svee4/RequiredStaticMembers Why I have not tested : issue opened https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/svee4/RequiredStaticMembers&body=https://github.com/svee4/RequiredStaticMembers -36) [https://github.com/SzymonHalucha/Minerals.AutoCommands]( https://github.com/SzymonHalucha/Minerals.AutoCommands) , https://github.com/SzymonHalucha/Minerals.AutoCommands +35) [https://github.com/SzymonHalucha/Minerals.AutoCommands]( https://github.com/SzymonHalucha/Minerals.AutoCommands) , https://github.com/SzymonHalucha/Minerals.AutoCommands Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/SzymonHalucha/Minerals.AutoCommands&body=https://github.com/SzymonHalucha/Minerals.AutoCommands -37) [https://github.com/Teleopti/Saspect]( https://github.com/Teleopti/Saspect) , https://github.com/Teleopti/Saspect +36) [https://github.com/Teleopti/Saspect]( https://github.com/Teleopti/Saspect) , https://github.com/Teleopti/Saspect Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/Teleopti/Saspect&body=https://github.com/Teleopti/Saspect -38) [https://github.com/TheFo2sh/AsyncFlow]( https://github.com/TheFo2sh/AsyncFlow) , https://github.com/TheFo2sh/AsyncFlow +37) [https://github.com/TheFo2sh/AsyncFlow]( https://github.com/TheFo2sh/AsyncFlow) , https://github.com/TheFo2sh/AsyncFlow Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/TheFo2sh/AsyncFlow&body=https://github.com/TheFo2sh/AsyncFlow -39) [https://github.com/wieslawsoltes/ReactiveGenerator]( https://github.com/wieslawsoltes/ReactiveGenerator) , https://github.com/wieslawsoltes/ReactiveGenerator +38) [https://github.com/wieslawsoltes/ReactiveGenerator]( https://github.com/wieslawsoltes/ReactiveGenerator) , https://github.com/wieslawsoltes/ReactiveGenerator Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=https://github.com/wieslawsoltes/ReactiveGenerator&body=https://github.com/wieslawsoltes/ReactiveGenerator -40) [Intellenum]( https://github.com/SteveDunn/Intellenum) , https://github.com/SteveDunn/Intellenum +39) [Intellenum]( https://github.com/SteveDunn/Intellenum) , https://github.com/SteveDunn/Intellenum Why I have not tested : not understand how to use https://github.com/ignatandrei/RSCG_Examples/issues/new?title=Intellenum&body=https://github.com/SteveDunn/Intellenum -41) [laker]( https://github.com/Lakerfield/Lakerfield.Rpc) , https://github.com/Lakerfield/Lakerfield.Rpc +40) [laker]( https://github.com/Lakerfield/Lakerfield.Rpc) , https://github.com/Lakerfield/Lakerfield.Rpc Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=laker&body=https://github.com/Lakerfield/Lakerfield.Rpc -42) [LoggingDecoratorGenerator]( https://github.com/DavidFineboym/LoggingDecoratorGenerator) , https://github.com/DavidFineboym/LoggingDecoratorGenerator +41) [LoggingDecoratorGenerator]( https://github.com/DavidFineboym/LoggingDecoratorGenerator) , https://github.com/DavidFineboym/LoggingDecoratorGenerator Why I have not tested : Microsoft have done same feature https://github.com/ignatandrei/RSCG_Examples/issues/new?title=LoggingDecoratorGenerator&body=https://github.com/DavidFineboym/LoggingDecoratorGenerator -43) [lucide-blazor]( https://github.com/brecht-vde/lucide-blazor/) , https://github.com/brecht-vde/lucide-blazor/ +42) [lucide-blazor]( https://github.com/brecht-vde/lucide-blazor/) , https://github.com/brecht-vde/lucide-blazor/ Why I have not tested : issue opened https://github.com/ignatandrei/RSCG_Examples/issues/new?title=lucide-blazor&body=https://github.com/brecht-vde/lucide-blazor/ -44) [ManagedDotnetProfiler]( https://github.com/kevingosse/ManagedDotnetProfiler) , https://github.com/kevingosse/ManagedDotnetProfiler +43) [ManagedDotnetProfiler]( https://github.com/kevingosse/ManagedDotnetProfiler) , https://github.com/kevingosse/ManagedDotnetProfiler Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=ManagedDotnetProfiler&body=https://github.com/kevingosse/ManagedDotnetProfiler -45) [Maui.BindableProperty.Generator]( https://github.com/rrmanzano/maui-bindableproperty-generator) , https://github.com/rrmanzano/maui-bindableproperty-generator +44) [Maui.BindableProperty.Generator]( https://github.com/rrmanzano/maui-bindableproperty-generator) , https://github.com/rrmanzano/maui-bindableproperty-generator Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=Maui.BindableProperty.Generator&body=https://github.com/rrmanzano/maui-bindableproperty-generator -46) [Minerals.AutoCQRS]( https://github.com/SzymonHalucha/Minerals.AutoCQRS) , https://github.com/SzymonHalucha/Minerals.AutoCQRS +45) [Minerals.AutoCQRS]( https://github.com/SzymonHalucha/Minerals.AutoCQRS) , https://github.com/SzymonHalucha/Minerals.AutoCQRS Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=Minerals.AutoCQRS&body=https://github.com/SzymonHalucha/Minerals.AutoCQRS -47) [Minerals.AutoDomain]( https://github.com/SzymonHalucha/Minerals.AutoDomain) , https://github.com/SzymonHalucha/Minerals.AutoDomain +46) [Minerals.AutoDomain]( https://github.com/SzymonHalucha/Minerals.AutoDomain) , https://github.com/SzymonHalucha/Minerals.AutoDomain Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=Minerals.AutoDomain&body=https://github.com/SzymonHalucha/Minerals.AutoDomain -48) [observable]( https://github.com/notanaverageman/Bindables) , https://github.com/notanaverageman/Bindables +47) [observable]( https://github.com/notanaverageman/Bindables) , https://github.com/notanaverageman/Bindables Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=observable&body=https://github.com/notanaverageman/Bindables -49) [PolySharp]( https://github.com/Sergio0694/PolySharp) , https://github.com/Sergio0694/PolySharp +48) [PolySharp]( https://github.com/Sergio0694/PolySharp) , https://github.com/Sergio0694/PolySharp Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=PolySharp&body=https://github.com/Sergio0694/PolySharp -50) [RazorGen]( https://github.com/dartk/RazorGen) , https://github.com/dartk/RazorGen +49) [RazorGen]( https://github.com/dartk/RazorGen) , https://github.com/dartk/RazorGen Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=RazorGen&body=https://github.com/dartk/RazorGen -51) [SerdeDn]( https://github.com/serdedotnet/serde) , https://github.com/serdedotnet/serde +50) [SerdeDn]( https://github.com/serdedotnet/serde) , https://github.com/serdedotnet/serde Why I have not tested : serializer. Done by MSFT with System.Text.Json https://github.com/ignatandrei/RSCG_Examples/issues/new?title=SerdeDn&body=https://github.com/serdedotnet/serde -52) [SogePoco]( https://github.com/d-p-y/SogePoco) , https://github.com/d-p-y/SogePoco +51) [SogePoco]( https://github.com/d-p-y/SogePoco) , https://github.com/d-p-y/SogePoco Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=SogePoco&body=https://github.com/d-p-y/SogePoco -53) [SourceCrafter.HttpServiceClientGenerator]( https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/) , https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ +52) [SourceCrafter.HttpServiceClientGenerator]( https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/) , https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=SourceCrafter.HttpServiceClientGenerator&body=https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ -54) [ST.NSwag.ServerSourceGenerator]( https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator) , https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator +53) [ST.NSwag.ServerSourceGenerator]( https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator) , https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=ST.NSwag.ServerSourceGenerator&body=https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator -55) [StrongInject]( https://github.com/YairHalberstadt/stronginject/) , https://github.com/YairHalberstadt/stronginject/ +54) [StrongInject]( https://github.com/YairHalberstadt/stronginject/) , https://github.com/YairHalberstadt/stronginject/ Why I have not tested : later https://github.com/ignatandrei/RSCG_Examples/issues/new?title=StrongInject&body=https://github.com/YairHalberstadt/stronginject/ -56) [TeuJson]( https://github.com/Terria-K/TeuJson) , https://github.com/Terria-K/TeuJson +55) [TeuJson]( https://github.com/Terria-K/TeuJson) , https://github.com/Terria-K/TeuJson Why I have not tested : json a class, was done in System.Text.Json https://github.com/ignatandrei/RSCG_Examples/issues/new?title=TeuJson&body=https://github.com/Terria-K/TeuJson -57) [Tinyhand]( https://github.com/archi-Doc/Tinyhand) , https://github.com/archi-Doc/Tinyhand +56) [Tinyhand]( https://github.com/archi-Doc/Tinyhand) , https://github.com/archi-Doc/Tinyhand Why I have not tested : tried, need documentation https://github.com/ignatandrei/RSCG_Examples/issues/new?title=Tinyhand&body=https://github.com/archi-Doc/Tinyhand -58) [TupleOverloadGenerator]( https://github.com/ProphetLamb/TupleOverloadGenerator) , https://github.com/ProphetLamb/TupleOverloadGenerator +57) [TupleOverloadGenerator]( https://github.com/ProphetLamb/TupleOverloadGenerator) , https://github.com/ProphetLamb/TupleOverloadGenerator Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=TupleOverloadGenerator&body=https://github.com/ProphetLamb/TupleOverloadGenerator -59) [TypealizR]( https://github.com/earloc/TypealizR) , https://github.com/earloc/TypealizR +58) [TypealizR]( https://github.com/earloc/TypealizR) , https://github.com/earloc/TypealizR Why I have not tested : depends on Microsoft.Extensions.Localization https://github.com/ignatandrei/RSCG_Examples/issues/new?title=TypealizR&body=https://github.com/earloc/TypealizR -60) [UnitTestBlazor]( https://github.com/bUnit-dev/bUnit) , https://github.com/bUnit-dev/bUnit +59) [UnitTestBlazor]( https://github.com/bUnit-dev/bUnit) , https://github.com/bUnit-dev/bUnit Why I have not tested : issue opened https://github.com/ignatandrei/RSCG_Examples/issues/new?title=UnitTestBlazor&body=https://github.com/bUnit-dev/bUnit -61) [ValueLink]( https://github.com/archi-Doc/ValueLink) , https://github.com/archi-Doc/ValueLink +60) [ValueLink]( https://github.com/archi-Doc/ValueLink) , https://github.com/archi-Doc/ValueLink Why I have not tested : too complicated https://github.com/ignatandrei/RSCG_Examples/issues/new?title=ValueLink&body=https://github.com/archi-Doc/ValueLink -62) [VisitorPatternGenerator]( https://github.com/hikarin522/VisitorPatternGenerator/) , https://github.com/hikarin522/VisitorPatternGenerator/ +61) [VisitorPatternGenerator]( https://github.com/hikarin522/VisitorPatternGenerator/) , https://github.com/hikarin522/VisitorPatternGenerator/ Why I have not tested : issue opened https://github.com/ignatandrei/RSCG_Examples/issues/new?title=VisitorPatternGenerator&body=https://github.com/hikarin522/VisitorPatternGenerator/ -63) [WrapperValueObject]( https://github.com/martinothamar/WrapperValueObject) , https://github.com/martinothamar/WrapperValueObject +62) [WrapperValueObject]( https://github.com/martinothamar/WrapperValueObject) , https://github.com/martinothamar/WrapperValueObject Why I have not tested : not maintained as in readme diff --git a/later.md b/later.md index c0665e407..5d6b42091 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2025-08-17 => 17 August 2025 +## Latest Update : 2025-08-18 => 18 August 2025 @@ -62,73 +62,67 @@ Why I have not tested : later -10) [https://github.com/pstlnce/unflat]( https://github.com/pstlnce/unflat) , https://github.com/pstlnce/unflat +10) [https://github.com/Stepami/visitor-net]( https://github.com/Stepami/visitor-net) , https://github.com/Stepami/visitor-net Why I have not tested : later -11) [https://github.com/Stepami/visitor-net]( https://github.com/Stepami/visitor-net) , https://github.com/Stepami/visitor-net +11) [https://github.com/SzymonHalucha/Minerals.AutoCommands]( https://github.com/SzymonHalucha/Minerals.AutoCommands) , https://github.com/SzymonHalucha/Minerals.AutoCommands Why I have not tested : later -12) [https://github.com/SzymonHalucha/Minerals.AutoCommands]( https://github.com/SzymonHalucha/Minerals.AutoCommands) , https://github.com/SzymonHalucha/Minerals.AutoCommands +12) [https://github.com/Teleopti/Saspect]( https://github.com/Teleopti/Saspect) , https://github.com/Teleopti/Saspect Why I have not tested : later -13) [https://github.com/Teleopti/Saspect]( https://github.com/Teleopti/Saspect) , https://github.com/Teleopti/Saspect +13) [Maui.BindableProperty.Generator]( https://github.com/rrmanzano/maui-bindableproperty-generator) , https://github.com/rrmanzano/maui-bindableproperty-generator Why I have not tested : later -14) [Maui.BindableProperty.Generator]( https://github.com/rrmanzano/maui-bindableproperty-generator) , https://github.com/rrmanzano/maui-bindableproperty-generator +14) [Minerals.AutoCQRS]( https://github.com/SzymonHalucha/Minerals.AutoCQRS) , https://github.com/SzymonHalucha/Minerals.AutoCQRS Why I have not tested : later -15) [Minerals.AutoCQRS]( https://github.com/SzymonHalucha/Minerals.AutoCQRS) , https://github.com/SzymonHalucha/Minerals.AutoCQRS +15) [Minerals.AutoDomain]( https://github.com/SzymonHalucha/Minerals.AutoDomain) , https://github.com/SzymonHalucha/Minerals.AutoDomain Why I have not tested : later -16) [Minerals.AutoDomain]( https://github.com/SzymonHalucha/Minerals.AutoDomain) , https://github.com/SzymonHalucha/Minerals.AutoDomain +16) [observable]( https://github.com/notanaverageman/Bindables) , https://github.com/notanaverageman/Bindables Why I have not tested : later -17) [observable]( https://github.com/notanaverageman/Bindables) , https://github.com/notanaverageman/Bindables +17) [RazorGen]( https://github.com/dartk/RazorGen) , https://github.com/dartk/RazorGen Why I have not tested : later -18) [RazorGen]( https://github.com/dartk/RazorGen) , https://github.com/dartk/RazorGen +18) [SourceCrafter.HttpServiceClientGenerator]( https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/) , https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ Why I have not tested : later -19) [SourceCrafter.HttpServiceClientGenerator]( https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/) , https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ +19) [ST.NSwag.ServerSourceGenerator]( https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator) , https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator Why I have not tested : later -20) [ST.NSwag.ServerSourceGenerator]( https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator) , https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator - -Why I have not tested : later - - - -21) [StrongInject]( https://github.com/YairHalberstadt/stronginject/) , https://github.com/YairHalberstadt/stronginject/ +20) [StrongInject]( https://github.com/YairHalberstadt/stronginject/) , https://github.com/YairHalberstadt/stronginject/ Why I have not tested : later diff --git a/v2/Generator/MultiGeneratorV2.cs b/v2/Generator/MultiGeneratorV2.cs index 40158b07f..f4e442c35 100644 --- a/v2/Generator/MultiGeneratorV2.cs +++ b/v2/Generator/MultiGeneratorV2.cs @@ -930,8 +930,13 @@ private async Task WroteDocusaurus(Description it, string pathDocusaurus) var templateScriban = Scriban.Template.Parse(template); var output = templateScriban.Render(new {Description=it,HasFilesGenerated, otherDesc, category}, member => member.Name); output = output + .Replace("a Result type", "a Result<TTarget> type") + .Replace("(e.g., Converter)", "(e.g., Converter<T>)") + .Replace("width=\"400\">", "width=\"400\" />") + .Replace("
","
") .Replace(" { ", " \\{ ") .Replace(" } ", " \\} ") + .Replace("", "<column_index>") .Replace("Action<>", "Action<>") .Replace("Func<>", "Func<>") .Replace("{Type}", "\\{Type}\\}") diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index a4a6679bd..23166f8a4 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -228,3 +228,4 @@ Nr,Key,Source,Category 227,UtilityVerse.Copy, https://github.com/purkayasta/TheUtilityVerse,Clone 228,mvvmgen, https://github.com/thomasclaudiushuber/mvvmgen,Serializer 229,Facet, https://github.com/Tim-Maes/Facet/,Mapper +230,Unflat, https://github.com/pstlnce/unflat,Database diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index d81a4831d..86c81b172 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1383,5 +1383,11 @@ "Category": 6, "dtStart": "2025-08-17T00:00:00", "show": true +}, +{ + "ID":"Unflat", + "Category": 14, + "dtStart": "2025-08-18T00:00:00", + "show": true } ] \ No newline at end of file diff --git a/v2/RSCGExamplesData/NoExample.json b/v2/RSCGExamplesData/NoExample.json index a604cf96f..1e3695448 100644 --- a/v2/RSCGExamplesData/NoExample.json +++ b/v2/RSCGExamplesData/NoExample.json @@ -871,11 +871,6 @@ "name":"https://github.com/buchmiet/FastFsm", "why":"later" }, - { - "ID":224, - "name":"https://github.com/pstlnce/unflat", - "why":"later" - }, { "ID":225, "name":"https://github.com/pierre3/PlantUmlClassDiagramGenerator", diff --git a/v2/rscg_examples/Unflat/description.json b/v2/rscg_examples/Unflat/description.json new file mode 100644 index 000000000..aaa57f6ee --- /dev/null +++ b/v2/rscg_examples/Unflat/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"Unflat", + "nuget":[ + "https://www.nuget.org/packages/Unflat/" + ], + "link":"https://github.com/pstlnce/unflat", + "author":"pstlnce", + "source":"https://github.com/pstlnce/unflat" + }, + "data":{ + "goodFor":["DataReader to Object Model"], + "csprojDemo":"UnflatDemo.csproj", + "csFiles":["Program.cs","Person.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/Unflat/nuget.txt b/v2/rscg_examples/Unflat/nuget.txt new file mode 100644 index 000000000..779f39ce8 --- /dev/null +++ b/v2/rscg_examples/Unflat/nuget.txt @@ -0,0 +1 @@ +AOT ORM Сode generator for fast parsing DataReader into complex classes/structs with zero allocations \ No newline at end of file diff --git a/v2/rscg_examples/Unflat/readme.txt b/v2/rscg_examples/Unflat/readme.txt new file mode 100644 index 000000000..5de5b2aec --- /dev/null +++ b/v2/rscg_examples/Unflat/readme.txt @@ -0,0 +1,157 @@ +# Unflat + +[![Unflat](https://img.shields.io/nuget/v/Unflat?style=flat-square)](https://www.nuget.org/packages/Unflat/) + +Unflat is an AOT ORM Сode generator for fast parsing DataReader into complex classes/structs with zero allocations + +## How To Use + +### Generating Parser + +Unflat generates parsers for classes or structs that have the UnflatMarkerAttribute applied to them. Target types can contain any number of nested complex fields or properties, with no depth limit. Circular references are resolved using default values. + + ```csharp +[UnflatMarker(Case = MatchCase.IgnoreCase)] +public sealed class TestClass +{ + ... +} +``` + +### Custom Converters + +Unflat supports custom converters by applying the UnflatParserAttribute to a method that should be called during parsing. Unflat searches for converters by matching the property types with the return types of marked methods, and selects the method that is closest in namespace to the target type. +For example, if there are two converters—one in Namespace1 and the other in Namespace1.Namespace2: + - If the target type is in Namespace1.Namespace2.Namespace3, the second converter will be chosen. + - If the target is in Namespace1.Namespace4, the first converter will be chosen. + - If the target is in Namespace5, the one marked with IsDefault = true will be selected. + +There are several options to control how converters are called and matched: + - CallFormat: Specifies how the converter should be invoked. It is used as the format string for string.Format(...), where {0} is replaced with reader.GetValue() and {1} with . + - IsDefault: Indicates that this converter is the default and should be used when no closer match is found by namespace. + - NamespaceScope: Tells Unflat to treat the converter as if it resides in the specified namespace, regardless of its actual location. + +```csharp +[UnflatParser(CallFormat = "Example.ExampleClass.Parse({0}, {1}, reader)", IsDefault = false, NamespaceScope = "Example2")] +public static int Parse(object v, int index, IDataReader reader) +{ + return Convert.ToInt32(v); +} +``` + +### Per Property/Field converter + +For different parsing behavior on specific properties or fields, use the SettableParserAttribute. It takes a single argument—the format string for string.Format(...), where {0} is replaced with reader.GetValue() and {1} with . + +```csharp +[SettableParser("Convert.ToString({0})")] +public string Description { get; set; } +``` + +### SplitOn, Column Prefix + +Unflat does not currently support split_on like Dapper. + +Instead, you can use the UnflatPrefixAttribute to differentiate properties or fields of complex types that share the same names as properties or fields of primitive types. + +If all names are unique (or if a field source is explicitly specified to resolve naming conflicts), no additional configuration is needed—nested complex types will be automatically assigned to their corresponding properties, unlike in Dapper. + +```csharp +public sealed class Example +{ + [UnflatPrefix("nested_class_")] + public required NestedClassExample NestedClass { get; set; } + + [UnflatPrefix("nested_class_2_")] + public required NestedClassExample NestedClass { get; set; } +} +``` + +### Per Property/Field Field Source + +Unflat allows you to specify a field source using the UnflatSourceAttribute. It can be a concrete column name, a column ordinal, or multiple column names. + +```csharp +[UnflatSource("column_1")] +public required strign Field1 { get; set; } + +[UnflatSource(1)] +public required strign Field2 { get; set; } + +[UnflatSource(["column_1", "column_2", "column_3"])] +public required strign Field3 { get; set; } +``` + +## Planned Features / Limitations + - Parameterless constructor requirement: Unflat currently only works if the target type has a parameterless constructor. I plan to add support for constructor argument matching (similar to Dapper) and the ability to call methods where parameters correspond to fields in the reader. + - Method argument support: The ability to pass arguments to parsing methods, including injecting custom code into generated parsing logic. + - Code templating: Support for templated code generation—such as automatically generating method extensions—to reduce boilerplate. For example, generating helper methods that use Dapper to fetch data and parse it with Unflat. + - Alternative error handling: Currently, errors result in exceptions. Future support may include returning a Result type (if the user chooses), which could provide detailed error information—such as missing columns for required fields, invalid casts, etc. + - Generic converters: Support for generic converter types (e.g., Converter), which are not currently supported. + - Multi-column converters: Converters that require values from multiple columns. (I haven’t yet determined how to design the API for this without conflicting with class or struct field declarations.) + - "Split On" support: Potential future support for a split_on-like feature, if there is a clear need. + - Tuple parsing: Currently, Unflat cannot parse tuples. This limitation may be addressed in a future update. + +## Perfomane + +#### Raw test against Dapper + +Parsing an in-memory DataTable using a DataTableReader into a model with 18 properties. + +````csharp +[UnflatMarker] +public class TestClass +{ + public string String1 { get; set; } + public string String2 { get; set; } + public string String3 { get; set; } + public string Int { get; set; } + public string Int2 { get; set; } + public int IntNullable { get; set; } + + public string String1_1 { get; set; } + public string String2_1 { get; set; } + public string String3_1 { get; set; } + public string Int_1 { get; set; } + public string Int2_1 { get; set; } + public int IntNullable_1 { get; set; } + + public string String1_2 { get; set; } + public string String2_2 { get; set; } + public string String3_2 { get; set; } + public string Int_2 { get; set; } + public string Int2_2 { get; set; } + public int IntNullable_2 { get; set; } +} +```` + +```` +BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.4652) +11th Gen Intel Core i5-1135G7 2.40GHz, 1 CPU, 8 logical and 4 physical cores +.NET SDK 10.0.100-preview.5.25277.114 + [Host] : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + DefaultJob : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI +```` + +| Method | count | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | +|------- |------ |-------------:|-----------:|-------------:|-------------:|----------:|----------:|---------:|------------:| +| Unflat | 100 | 22.68 us | 0.259 us | 0.242 us | 22.61 us | 7.2021 | - | - | 29.49 KB | +| Dapper | 100 | 27.61 us | 0.549 us | 0.933 us | 27.44 us | 7.9956 | - | - | 32.69 KB | +| Unflat | 1000 | 260.84 us | 5.161 us | 5.069 us | 258.15 us | 68.8477 | 18.5547 | - | 282.63 KB | +| Dapper | 1000 | 297.94 us | 4.265 us | 4.380 us | 296.87 us | 76.1719 | 8.7891 | - | 313.95 KB | +| Unflat | 10000 | 5,680.10 us | 113.556 us | 308.937 us | 5,555.69 us | 546.8750 | 343.7500 | 93.7500 | 2913.38 KB | +| Dapper | 10000 | 7,420.81 us | 146.523 us | 271.590 us | 7,444.71 us | 609.3750 | 375.0000 | 109.3750 | 3226 KB | +| Unflat | 50000 | 33,989.82 us | 352.901 us | 330.104 us | 33,963.35 us | 2600.0000 | 1600.0000 | 466.6667 | 14306.6 KB | +| Dapper | 50000 | 41,203.97 us | 815.625 us | 1,551.811 us | 41,597.04 us | 2833.3333 | 1666.6667 | 416.6667 | 15869.31 KB | + +## What's the purpose? + +Unflat allows you to debug the parsing process and see exactly which converters or parsers are used—at compile time. In contrast, debugging the parsing logic in Dapper is difficult and often requires tools like WinDbg. With Dapper, you must manually verify whether a type parser is registered, and since only one parser can be registered per type, you may end up writing general-purpose converters that perform unnecessary checks, hurting performance. + +Additionally, Unflat does not allocate any memory beyond what is required to create the target object—which is unavoidable, as object creation is the core purpose of any ORM. + +## What About Other Libraries? + +I couldn't find any source generators that address the most frustrating aspects of Dapper — specifically, the inability to debug the parsing process and the need to manually register type parsers. + +Some similar libraries only support flat types, while others lack support for custom type parsers altogether. diff --git a/v2/rscg_examples/Unflat/src/.tours/Unflat.tour b/v2/rscg_examples/Unflat/src/.tours/Unflat.tour new file mode 100644 index 000000000..0cf5ad646 --- /dev/null +++ b/v2/rscg_examples/Unflat/src/.tours/Unflat.tour @@ -0,0 +1,42 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "Unflat", + "steps": + [ + { + "file": "UnflatDemo/UnflatDemo.csproj", + "description": "First, we add Nuget [Unflat](https://www.nuget.org/packages/Unflat/) in csproj ", + "pattern": "Unflat" + } + + ,{ + "file": "UnflatDemo/Person.cs", + "description": "File Person.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "UnflatDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project UnflatDemo/UnflatDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "UnflatDemo/obj/GX/Unflat/Unflat.SourceGen/UnflatDemo.PersonParser.g.cs", + "description": "Generated File 2 from 2 : UnflatDemo.PersonParser.g.cs ", + "line": 1 + } + + ,{ + "file": "UnflatDemo/obj/GX/Unflat/Unflat.SourceGen/Unflat.UnflatMarkerAttribute.g.cs", + "description": "Generated File 1 from 2 : Unflat.UnflatMarkerAttribute.g.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/rscg_examples/Unflat/src/Unflat.sln b/v2/rscg_examples/Unflat/src/Unflat.sln new file mode 100644 index 000000000..751c52f99 --- /dev/null +++ b/v2/rscg_examples/Unflat/src/Unflat.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnflatDemo", "UnflatDemo\UnflatDemo.csproj", "{AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}" +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 + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|x64.Build.0 = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|x86.ActiveCfg = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Debug|x86.Build.0 = Debug|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|Any CPU.Build.0 = Release|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|x64.ActiveCfg = Release|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|x64.Build.0 = Release|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|x86.ActiveCfg = Release|Any CPU + {AABCCD7D-3A67-9BB3-A54E-1C2C604851E7}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/v2/rscg_examples/Unflat/src/UnflatDemo/Person.cs b/v2/rscg_examples/Unflat/src/UnflatDemo/Person.cs new file mode 100644 index 000000000..beca2673b --- /dev/null +++ b/v2/rscg_examples/Unflat/src/UnflatDemo/Person.cs @@ -0,0 +1,10 @@ +namespace UnflatDemo +{ + [Unflat.UnflatMarker] + public partial class Person + { + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + public int Age { get; set; } + } +} diff --git a/v2/rscg_examples/Unflat/src/UnflatDemo/Program.cs b/v2/rscg_examples/Unflat/src/UnflatDemo/Program.cs new file mode 100644 index 000000000..eaa23c5c9 --- /dev/null +++ b/v2/rscg_examples/Unflat/src/UnflatDemo/Program.cs @@ -0,0 +1,30 @@ +using System; +using System.Data; +using Unflat; + +namespace UnflatDemo +{ + + class Program + { + static void Main(string[] args) + { + // Create a DataTable and fill with sample data + var table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Age", typeof(int)); + + table.Rows.Add(1, "Andrei", 30); + table.Rows.Add(2, "Ignat", 55); + + using var reader = table.CreateDataReader(); + + var persons = PersonParser.ReadList(reader); + foreach (var person in persons) + { + Console.WriteLine($"Id: {person.Id}, Name: {person.Name}, Age: {person.Age}"); + } + } + } +} diff --git a/v2/rscg_examples/Unflat/src/UnflatDemo/UnflatDemo.csproj b/v2/rscg_examples/Unflat/src/UnflatDemo/UnflatDemo.csproj new file mode 100644 index 000000000..2a694b109 --- /dev/null +++ b/v2/rscg_examples/Unflat/src/UnflatDemo/UnflatDemo.csproj @@ -0,0 +1,19 @@ + + + + + + + + + Exe + net9.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + diff --git a/v2/rscg_examples/Unflat/video.json b/v2/rscg_examples/Unflat/video.json new file mode 100644 index 000000000..7f4b43852 --- /dev/null +++ b/v2/rscg_examples/Unflat/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "Unflat", + "steps": +[ + {"typeStep":"exec","arg":"clipchamp.exe launch"}, + {"typeStep":"text","arg": "Welcome to Roslyn Examples"}, + {"typeStep":"text","arg":"If you want to see more examples , see List Of RSCG"}, + {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"}, + {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "}, + +{"typeStep":"text","arg": "Today I will present Unflat . DataReader to Object Model ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/Unflat/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat#download-example-net--c-"}, +{"typeStep":"text","arg":"Here is the code downloaded "}, +{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\Unflat\\src\\Unflat.sln"}, +{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "}, +{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\Unflat\\src"}, + +{"typeStep":"text","arg": "To use it ,you will put the Nuget Unflat into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\Unflat\\src\\UnflatDemo\\UnflatDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using Unflat"}, + +{"typeStep":"hide","arg": "now execute the tour in VSCode"}, +{"typeStep":"tour", "arg": "src/.tours/"}, +{"typeStep":"text","arg":" And I will execute the project"}, +{"typeStep":"showproj", "arg":"UnflatDemo.csproj"}, +{"typeStep":"text","arg":" This concludes the project"}, +{"typeStep":"waitseconds","arg":"30"}, +{"typeStep":"text","arg": "Remember, you can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Categories/Database.md b/v2/rscg_examples_site/docs/Categories/Database.md index cb7ac44be..5301eac12 100644 --- a/v2/rscg_examples_site/docs/Categories/Database.md +++ b/v2/rscg_examples_site/docs/Categories/Database.md @@ -1,6 +1,6 @@

Database

-Number RSCG: 6 +Number RSCG: 7 1 [Breezy](/docs/Breezy) @@ -13,4 +13,6 @@ Number RSCG: 6 5 [Gedaq](/docs/Gedaq) 6 [TableStorage](/docs/TableStorage) + + 7 [Unflat](/docs/Unflat) \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveDatabase.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveDatabase.mdx index 3c0e15464..5cd249db2 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveDatabase.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveDatabase.mdx @@ -12,6 +12,8 @@ 6 [TableStorage](/docs/TableStorage) + 7 [Unflat](/docs/Unflat) + ### See category [Database](/docs/Categories/Database) diff --git a/v2/rscg_examples_site/docs/NoExamples.md b/v2/rscg_examples_site/docs/NoExamples.md index f9a7a0239..f61f2c00c 100644 --- a/v2/rscg_examples_site/docs/NoExamples.md +++ b/v2/rscg_examples_site/docs/NoExamples.md @@ -322,387 +322,383 @@ Why I have not put example: issue opened Why I have not put example: later -80)https://github.com/pstlnce/unflat https://github.com/pstlnce/unflat - -Why I have not put example: later - -81)https://github.com/ramhari-dev/PropGenAoT https://github.com/ramhari-dev/PropGenAoT +80)https://github.com/ramhari-dev/PropGenAoT https://github.com/ramhari-dev/PropGenAoT Why I have not put example: no readme -82)https://github.com/stbychkov/AutoLoggerMessage https://github.com/stbychkov/AutoLoggerMessage +81)https://github.com/stbychkov/AutoLoggerMessage https://github.com/stbychkov/AutoLoggerMessage Why I have not put example: Microsoft have done same feature -83)https://github.com/Stepami/visitor-net https://github.com/Stepami/visitor-net +82)https://github.com/Stepami/visitor-net https://github.com/Stepami/visitor-net Why I have not put example: later -84)https://github.com/svee4/RequiredStaticMembers https://github.com/svee4/RequiredStaticMembers +83)https://github.com/svee4/RequiredStaticMembers https://github.com/svee4/RequiredStaticMembers Why I have not put example: issue opened -85)https://github.com/SzymonHalucha/Minerals.AutoCommands https://github.com/SzymonHalucha/Minerals.AutoCommands +84)https://github.com/SzymonHalucha/Minerals.AutoCommands https://github.com/SzymonHalucha/Minerals.AutoCommands Why I have not put example: later -86)https://github.com/Teleopti/Saspect https://github.com/Teleopti/Saspect +85)https://github.com/Teleopti/Saspect https://github.com/Teleopti/Saspect Why I have not put example: later -87)https://github.com/TheFo2sh/AsyncFlow https://github.com/TheFo2sh/AsyncFlow +86)https://github.com/TheFo2sh/AsyncFlow https://github.com/TheFo2sh/AsyncFlow Why I have not put example: too complicated -88)https://github.com/wieslawsoltes/ReactiveGenerator https://github.com/wieslawsoltes/ReactiveGenerator +87)https://github.com/wieslawsoltes/ReactiveGenerator https://github.com/wieslawsoltes/ReactiveGenerator Why I have not put example: too complicated -89)HubClientProxyGenerator https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client.SourceGenerator +88)HubClientProxyGenerator https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client.SourceGenerator Why I have not put example: not having nuget, but having IIncrementalGenerator -90)Imp.NET https://github.com/DouglasDwyer/Imp.NET +89)Imp.NET https://github.com/DouglasDwyer/Imp.NET Why I have not put example: old ISourceGenerator -91)Intellenum https://github.com/SteveDunn/Intellenum +90)Intellenum https://github.com/SteveDunn/Intellenum Why I have not put example: not understand how to use -92)InterfaceGenerator https://github.com/daver32/InterfaceGenerator +91)InterfaceGenerator https://github.com/daver32/InterfaceGenerator Why I have not put example: old ISourceGenerator -93)IoTHubClientGenerator https://github.com/alonf/IoTHubClientGenerator +92)IoTHubClientGenerator https://github.com/alonf/IoTHubClientGenerator Why I have not put example: old ISourceGenerator -94)JsonByExampleGenerator https://github.com/hermanussen/JsonByExampleGenerator +93)JsonByExampleGenerator https://github.com/hermanussen/JsonByExampleGenerator Why I have not put example: old ISourceGenerator -95)JsonDeserializeResourceSourceGenerator https://github.com/musictopia2/JsonDeserializeResourceSourceGenerator +94)JsonDeserializeResourceSourceGenerator https://github.com/musictopia2/JsonDeserializeResourceSourceGenerator Why I have not put example: no readme -96)JsonMergePatch https://github.com/ladeak/JsonMergePatch +95)JsonMergePatch https://github.com/ladeak/JsonMergePatch Why I have not put example: old ISourceGenerator -97)JsonSerializerContextGenerator https://github.com/musictopia2/JsonSerializerContextGenerator +96)JsonSerializerContextGenerator https://github.com/musictopia2/JsonSerializerContextGenerator Why I have not put example: no readme -98)JsonSourceGenerator https://github.com/Pilchie/JsonSourceGenerator +97)JsonSourceGenerator https://github.com/Pilchie/JsonSourceGenerator Why I have not put example: not having nuget, but having IIncrementalGenerator -99)JsonSrcGen https://github.com/trampster/JsonSrcGen +98)JsonSrcGen https://github.com/trampster/JsonSrcGen Why I have not put example: old ISourceGenerator -100)kli.Localize https://github.com/kl1mm/localize +99)kli.Localize https://github.com/kl1mm/localize Why I have not put example: old ISourceGenerator -101)laker https://github.com/Lakerfield/Lakerfield.Rpc +100)laker https://github.com/Lakerfield/Lakerfield.Rpc Why I have not put example: too complicated -102)lambdajection https://github.com/cythral/lambdajection +101)lambdajection https://github.com/cythral/lambdajection Why I have not put example: old ISourceGenerator -103)Lazysh https://github.com/B1Z0N/LazyshGen +102)Lazysh https://github.com/B1Z0N/LazyshGen Why I have not put example: old ISourceGenerator -104)LoggingDecoratorGenerator https://github.com/DavidFineboym/LoggingDecoratorGenerator +103)LoggingDecoratorGenerator https://github.com/DavidFineboym/LoggingDecoratorGenerator Why I have not put example: Microsoft have done same feature -105)lucide-blazor https://github.com/brecht-vde/lucide-blazor/ +104)lucide-blazor https://github.com/brecht-vde/lucide-blazor/ Why I have not put example: issue opened -106)ManagedDotnetProfiler https://github.com/kevingosse/ManagedDotnetProfiler +105)ManagedDotnetProfiler https://github.com/kevingosse/ManagedDotnetProfiler Why I have not put example: too complicated -107)MapDataReader https://github.com/jitbit/MapDataReader +106)MapDataReader https://github.com/jitbit/MapDataReader Why I have not put example: old ISourceGenerator -108)MappingCloningExtensions https://github.com/musictopia2/MappingCloningExtensions +107)MappingCloningExtensions https://github.com/musictopia2/MappingCloningExtensions Why I have not put example: no readme -109)Maui.BindableProperty.Generator https://github.com/rrmanzano/maui-bindableproperty-generator +108)Maui.BindableProperty.Generator https://github.com/rrmanzano/maui-bindableproperty-generator Why I have not put example: later -110)MediatR https://github.com/Burgyn/MMLib.MediatR.Generators +109)MediatR https://github.com/Burgyn/MMLib.MediatR.Generators Why I have not put example: old ISourceGenerator -111)MemberAccessGenerator https://github.com/ufcpp/MemberAccessGenerator +110)MemberAccessGenerator https://github.com/ufcpp/MemberAccessGenerator Why I have not put example: old ISourceGenerator -112)MemoizeSourceGenerator https://github.com/Zoxive/MemoizeSourceGenerator +111)MemoizeSourceGenerator https://github.com/Zoxive/MemoizeSourceGenerator Why I have not put example: old ISourceGenerator -113)Minerals.AutoCQRS https://github.com/SzymonHalucha/Minerals.AutoCQRS +112)Minerals.AutoCQRS https://github.com/SzymonHalucha/Minerals.AutoCQRS Why I have not put example: later -114)Minerals.AutoDomain https://github.com/SzymonHalucha/Minerals.AutoDomain +113)Minerals.AutoDomain https://github.com/SzymonHalucha/Minerals.AutoDomain Why I have not put example: later -115)MiniRazor https://github.com/Tyrrrz/MiniRazor/ +114)MiniRazor https://github.com/Tyrrrz/MiniRazor/ Why I have not put example: archived -116)MockableStaticGenerator https://github.com/HamedFathi/MockableStaticGenerator +115)MockableStaticGenerator https://github.com/HamedFathi/MockableStaticGenerator Why I have not put example: old ISourceGenerator -117)MockGen https://github.com/thomas-girotto/MockGen +116)MockGen https://github.com/thomas-girotto/MockGen Why I have not put example: old ISourceGenerator -118)MockSourceGenerator https://github.com/hermanussen/MockSourceGenerator +117)MockSourceGenerator https://github.com/hermanussen/MockSourceGenerator Why I have not put example: old ISourceGenerator -119)MrMeeseeks.DIE https://github.com/Yeah69/MrMeeseeks.DIE +118)MrMeeseeks.DIE https://github.com/Yeah69/MrMeeseeks.DIE Why I have not put example: old ISourceGenerator -120)MrMeeseeks.ResXToViewModelGenerator https://github.com/Yeah69/MrMeeseeks.ResXToViewModelGenerator +119)MrMeeseeks.ResXToViewModelGenerator https://github.com/Yeah69/MrMeeseeks.ResXToViewModelGenerator Why I have not put example: old ISourceGenerator -121)MrMeeseeks.StaticDelegateGenerator https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator +120)MrMeeseeks.StaticDelegateGenerator https://github.com/Yeah69/MrMeeseeks.StaticDelegateGenerator Why I have not put example: old ISourceGenerator -122)MrMeeseeks.Visitor https://github.com/Yeah69/MrMeeseeks.Visitor +121)MrMeeseeks.Visitor https://github.com/Yeah69/MrMeeseeks.Visitor Why I have not put example: old ISourceGenerator -123)Neon.Roslyn https://www.nuget.org/packages/Neon.Roslyn +122)Neon.Roslyn https://www.nuget.org/packages/Neon.Roslyn Why I have not put example: old ISourceGenerator -124)net_automatic_interface https://github.com/codecentric/net_automatic_interface +123)net_automatic_interface https://github.com/codecentric/net_automatic_interface Why I have not put example: old ISourceGenerator -125)NSourceGenerators https://github.com/NeVeSpl/NSourceGenerators/ +124)NSourceGenerators https://github.com/NeVeSpl/NSourceGenerators/ Why I have not put example: old ISourceGenerator -126)observable https://github.com/notanaverageman/Bindables +125)observable https://github.com/notanaverageman/Bindables Why I have not put example: later -127)Pipelines https://github.com/DumplingsDevs/Pipelines/ +126)Pipelines https://github.com/DumplingsDevs/Pipelines/ Why I have not put example: old ISourceGenerator -128)Plastic https://github.com/sang-hyeon/Plastic +127)Plastic https://github.com/sang-hyeon/Plastic Why I have not put example: old ISourceGenerator -129)PolySharp https://github.com/Sergio0694/PolySharp +128)PolySharp https://github.com/Sergio0694/PolySharp Why I have not put example: too complicated -130)PrimaryConstructor https://github.com/chaowlert/PrimaryConstructor +129)PrimaryConstructor https://github.com/chaowlert/PrimaryConstructor Why I have not put example: old ISourceGenerator -131)PrimitiveStaticDataGenerator https://github.com/iiweis/PrimitiveStaticDataGenerator +130)PrimitiveStaticDataGenerator https://github.com/iiweis/PrimitiveStaticDataGenerator Why I have not put example: old ISourceGenerator -132)PrintMembersGenerator https://github.com/Youssef1313/PrintMembersGenerator +131)PrintMembersGenerator https://github.com/Youssef1313/PrintMembersGenerator Why I have not put example: old ISourceGenerator -133)ProxyInterfaceGenerator https://github.com/StefH/ProxyInterfaceSourceGenerator +132)ProxyInterfaceGenerator https://github.com/StefH/ProxyInterfaceSourceGenerator Why I have not put example: old ISourceGenerator -134)PureHDF https://github.com/Apollo3zehn/PureHDF +133)PureHDF https://github.com/Apollo3zehn/PureHDF Why I have not put example: old ISourceGenerator -135)RazorGen https://github.com/dartk/RazorGen +134)RazorGen https://github.com/dartk/RazorGen Why I have not put example: later -136)RazorPageRouteGenerator https://github.com/surgicalcoder/RazorPageRouteGenerator +135)RazorPageRouteGenerator https://github.com/surgicalcoder/RazorPageRouteGenerator Why I have not put example: old ISourceGenerator -137)ReForge.Union https://github.com/nalcorso/ReForge.Union +136)ReForge.Union https://github.com/nalcorso/ReForge.Union Why I have not put example: not having nuget, but having IIncrementalGenerator -138)RoslynWeave https://github.com/Jishun/RoslynWeave +137)RoslynWeave https://github.com/Jishun/RoslynWeave Why I have not put example: old ISourceGenerator -139)ScenarioTests https://github.com/koenbeuk/ScenarioTests +138)ScenarioTests https://github.com/koenbeuk/ScenarioTests Why I have not put example: old ISourceGenerator -140)SerdeDn https://github.com/serdedotnet/serde +139)SerdeDn https://github.com/serdedotnet/serde Why I have not put example: serializer. Done by MSFT with System.Text.Json -141)SmallSharp https://github.com/devlooped/SmallSharp +140)SmallSharp https://github.com/devlooped/SmallSharp Why I have not put example: old ISourceGenerator -142)SmartAnnotations https://github.com/fiseni/SmartAnnotations +141)SmartAnnotations https://github.com/fiseni/SmartAnnotations Why I have not put example: old ISourceGenerator -143)SogePoco https://github.com/d-p-y/SogePoco +142)SogePoco https://github.com/d-p-y/SogePoco Why I have not put example: too complicated -144)SourceApi https://github.com/alekshura/SourceApi +143)SourceApi https://github.com/alekshura/SourceApi Why I have not put example: old ISourceGenerator -145)SourceConfig https://github.com/alekshura/SourceConfig +144)SourceConfig https://github.com/alekshura/SourceConfig Why I have not put example: old ISourceGenerator -146)SourceCrafter.HttpServiceClientGenerator https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ +145)SourceCrafter.HttpServiceClientGenerator https://github.com/pedro-gilmora/SourceCrafter.HttpServiceClientGenerator/ Why I have not put example: later -147)SourceGeneratorQuery https://github.com/roeibajayo/SourceGeneratorQuery +146)SourceGeneratorQuery https://github.com/roeibajayo/SourceGeneratorQuery Why I have not put example: old ISourceGenerator -148)SourceInject https://github.com/giggio/sourceinject/ +147)SourceInject https://github.com/giggio/sourceinject/ Why I have not put example: old ISourceGenerator -149)SourceMapper https://github.com/alekshura/SourceMapper +148)SourceMapper https://github.com/alekshura/SourceMapper Why I have not put example: old ISourceGenerator -150)SourceMapper https://github.com/paiden/SourceMapper/ +149)SourceMapper https://github.com/paiden/SourceMapper/ Why I have not put example: old ISourceGenerator -151)SqlMarshal https://github.com/kant2002/SqlMarshal +150)SqlMarshal https://github.com/kant2002/SqlMarshal Why I have not put example: old ISourceGenerator -152)ST.NSwag.ServerSourceGenerator https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator +151)ST.NSwag.ServerSourceGenerator https://github.com/s-tarasov/ST.NSwag.ServerSourceGenerator Why I have not put example: later -153)StackXML https://github.com/ZingBallyhoo/StackXML +152)StackXML https://github.com/ZingBallyhoo/StackXML Why I have not put example: old ISourceGenerator -154)StaticProxyGenerator https://github.com/robertturner/StaticProxyGenerator +153)StaticProxyGenerator https://github.com/robertturner/StaticProxyGenerator Why I have not put example: old ISourceGenerator -155)StrongInject https://github.com/YairHalberstadt/stronginject/ +154)StrongInject https://github.com/YairHalberstadt/stronginject/ Why I have not put example: later -156)StronglyTypedEmbeddedResources https://github.com/surgicalcoder/StronglyTypedEmbeddedResources +155)StronglyTypedEmbeddedResources https://github.com/surgicalcoder/StronglyTypedEmbeddedResources Why I have not put example: old ISourceGenerator -157)StructPacker https://github.com/RudolfKurka/StructPacker +156)StructPacker https://github.com/RudolfKurka/StructPacker Why I have not put example: old ISourceGenerator -158)Svg https://github.com/wieslawsoltes/Svg.Skia +157)Svg https://github.com/wieslawsoltes/Svg.Skia Why I have not put example: old ISourceGenerator -159)tecli https://github.com/tyevco/TeCLI +158)tecli https://github.com/tyevco/TeCLI Why I have not put example: old ISourceGenerator -160)TeuJson https://github.com/Terria-K/TeuJson +159)TeuJson https://github.com/Terria-K/TeuJson Why I have not put example: json a class, was done in System.Text.Json -161)Thunderboltloc https://github.com/AlyElhaddad/ThunderboltIoc +160)Thunderboltloc https://github.com/AlyElhaddad/ThunderboltIoc Why I have not put example: old ISourceGenerator -162)Tinyhand https://github.com/archi-Doc/Tinyhand +161)Tinyhand https://github.com/archi-Doc/Tinyhand Why I have not put example: tried, need documentation -163)ToString https://github.com/Burgyn/MMLib.ToString +162)ToString https://github.com/Burgyn/MMLib.ToString Why I have not put example: old ISourceGenerator -164)Transplator https://github.com/atifaziz/Transplator +163)Transplator https://github.com/atifaziz/Transplator Why I have not put example: old ISourceGenerator -165)TupleOverloadGenerator https://github.com/ProphetLamb/TupleOverloadGenerator +164)TupleOverloadGenerator https://github.com/ProphetLamb/TupleOverloadGenerator Why I have not put example: too complicated -166)TxtToListGenerator https://github.com/musictopia2/TxtToListGenerator +165)TxtToListGenerator https://github.com/musictopia2/TxtToListGenerator Why I have not put example: no readme -167)TypealizR https://github.com/earloc/TypealizR +166)TypealizR https://github.com/earloc/TypealizR Why I have not put example: depends on Microsoft.Extensions.Localization -168)UnitTestBlazor https://github.com/bUnit-dev/bUnit +167)UnitTestBlazor https://github.com/bUnit-dev/bUnit Why I have not put example: issue opened -169)ValueChangedGenerator https://github.com/ufcpp/ValueChangedGenerator +168)ValueChangedGenerator https://github.com/ufcpp/ValueChangedGenerator Why I have not put example: old ISourceGenerator -170)ValueLink https://github.com/archi-Doc/ValueLink +169)ValueLink https://github.com/archi-Doc/ValueLink Why I have not put example: too complicated -171)ValueObjectGenerator https://github.com/RyotaMurohoshi/ValueObjectGenerator +170)ValueObjectGenerator https://github.com/RyotaMurohoshi/ValueObjectGenerator Why I have not put example: old ISourceGenerator -172)VisitorPatternGenerator https://github.com/hikarin522/VisitorPatternGenerator/ +171)VisitorPatternGenerator https://github.com/hikarin522/VisitorPatternGenerator/ Why I have not put example: issue opened -173)Visor https://github.com/Tinkoff/Visor +172)Visor https://github.com/Tinkoff/Visor Why I have not put example: archived -174)WrapperValueObject https://github.com/martinothamar/WrapperValueObject +173)WrapperValueObject https://github.com/martinothamar/WrapperValueObject Why I have not put example: not maintained as in readme -175)Xtz.StronglyTyped https://github.com/dev-experience/Xtz.StronglyTyped +174)Xtz.StronglyTyped https://github.com/dev-experience/Xtz.StronglyTyped Why I have not put example: old ISourceGenerator diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/Facet.md b/v2/rscg_examples_site/docs/RSCG-Examples/Facet.md index a49edb484..b4eb01fc0 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/Facet.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/Facet.md @@ -60,7 +60,7 @@ Tim Maes "One part of a subject, situation, object that has many parts." -
+
diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/Unflat.md b/v2/rscg_examples_site/docs/RSCG-Examples/Unflat.md new file mode 100644 index 000000000..a0ffd5402 --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/Unflat.md @@ -0,0 +1,732 @@ +--- +sidebar_position: 2300 +title: 230 - Unflat +description: DataReader to Object Model +slug: /Unflat +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveDatabase.mdx'; + +# Unflat by pstlnce + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/Unflat?label=Unflat)](https://www.nuget.org/packages/Unflat/) +[![GitHub last commit](https://img.shields.io/github/last-commit/pstlnce/unflat?label=updated)](https://github.com/pstlnce/unflat) +![GitHub Repo stars](https://img.shields.io/github/stars/pstlnce/unflat?style=social) + +## Details + +### Info +:::info + +Name: **Unflat** + +AOT ORM Сode generator for fast parsing DataReader into complex classes/structs with zero allocations + +Author: pstlnce + +NuGet: +*https://www.nuget.org/packages/Unflat/* + + +You can find more details at https://github.com/pstlnce/unflat + +Source: https://github.com/pstlnce/unflat + +::: + +### Author +:::note +pstlnce +![Alt text](https://github.com/pstlnce.png) +::: + +### Original Readme +:::note + +# Unflat + +[![Unflat](https://img.shields.io/nuget/v/Unflat?style=flat-square)](https://www.nuget.org/packages/Unflat/) + +Unflat is an AOT ORM Сode generator for fast parsing DataReader into complex classes/structs with zero allocations + +## How To Use + +### Generating Parser + +Unflat generates parsers for classes or structs that have the UnflatMarkerAttribute applied to them. Target types can contain any number of nested complex fields or properties, with no depth limit. Circular references are resolved using default values. + + ```csharp +[UnflatMarker(Case = MatchCase.IgnoreCase)] +public sealed class TestClass +{ + ... +} +``` + +### Custom Converters + +Unflat supports custom converters by applying the UnflatParserAttribute to a method that should be called during parsing. Unflat searches for converters by matching the property types with the return types of marked methods, and selects the method that is closest in namespace to the target type. +For example, if there are two converters—one in Namespace1 and the other in Namespace1.Namespace2: + - If the target type is in Namespace1.Namespace2.Namespace3, the second converter will be chosen. + - If the target is in Namespace1.Namespace4, the first converter will be chosen. + - If the target is in Namespace5, the one marked with IsDefault = true will be selected. + +There are several options to control how converters are called and matched: + - CallFormat: Specifies how the converter should be invoked. It is used as the format string for string.Format(...), where {0} is replaced with reader.GetValue(<column_index>) and {1} with <column_index>. + - IsDefault: Indicates that this converter is the default and should be used when no closer match is found by namespace. + - NamespaceScope: Tells Unflat to treat the converter as if it resides in the specified namespace, regardless of its actual location. + +```csharp +[UnflatParser(CallFormat = "Example.ExampleClass.Parse({0}, {1}, reader)", IsDefault = false, NamespaceScope = "Example2")] +public static int Parse(object v, int index, IDataReader reader) +{ + return Convert.ToInt32(v); +} +``` + +### Per Property/Field converter + +For different parsing behavior on specific properties or fields, use the SettableParserAttribute. It takes a single argument—the format string for string.Format(...), where {0} is replaced with reader.GetValue(<column_index>) and {1} with <column_index>. + +```csharp +[SettableParser("Convert.ToString({0})")] +public string Description \{ get; set; } +``` + +### SplitOn, Column Prefix + +Unflat does not currently support split_on like Dapper. + +Instead, you can use the UnflatPrefixAttribute to differentiate properties or fields of complex types that share the same names as properties or fields of primitive types. + +If all names are unique (or if a field source is explicitly specified to resolve naming conflicts), no additional configuration is needed—nested complex types will be automatically assigned to their corresponding properties, unlike in Dapper. + +```csharp +public sealed class Example +{ + [UnflatPrefix("nested_class_")] + public required NestedClassExample NestedClass \{ get; set; } + + [UnflatPrefix("nested_class_2_")] + public required NestedClassExample NestedClass \{ get; set; } +} +``` + +### Per Property/Field Field Source + +Unflat allows you to specify a field source using the UnflatSourceAttribute. It can be a concrete column name, a column ordinal, or multiple column names. + +```csharp +[UnflatSource("column_1")] +public required strign Field1 \{ get; set; } + +[UnflatSource(1)] +public required strign Field2 \{ get; set; } + +[UnflatSource(["column_1", "column_2", "column_3"])] +public required strign Field3 \{ get; set; } +``` + +## Planned Features / Limitations + - Parameterless constructor requirement: Unflat currently only works if the target type has a parameterless constructor. I plan to add support for constructor argument matching (similar to Dapper) and the ability to call methods where parameters correspond to fields in the reader. + - Method argument support: The ability to pass arguments to parsing methods, including injecting custom code into generated parsing logic. + - Code templating: Support for templated code generation—such as automatically generating method extensions—to reduce boilerplate. For example, generating helper methods that use Dapper to fetch data and parse it with Unflat. + - Alternative error handling: Currently, errors result in exceptions. Future support may include returning a Result<TTarget> type (if the user chooses), which could provide detailed error information—such as missing columns for required fields, invalid casts, etc. + - Generic converters: Support for generic converter types (e.g., Converter<T>), which are not currently supported. + - Multi-column converters: Converters that require values from multiple columns. (I haven’t yet determined how to design the API for this without conflicting with class or struct field declarations.) + - "Split On" support: Potential future support for a split_on-like feature, if there is a clear need. + - Tuple parsing: Currently, Unflat cannot parse tuples. This limitation may be addressed in a future update. + +## Perfomane + +#### Raw test against Dapper + +Parsing an in-memory DataTable using a DataTableReader into a model with 18 properties. + +````csharp +[UnflatMarker] +public class TestClass +{ + public string String1 \{ get; set; } + public string String2 \{ get; set; } + public string String3 \{ get; set; } + public string Int \{ get; set; } + public string Int2 \{ get; set; } + public int IntNullable \{ get; set; } + + public string String1_1 \{ get; set; } + public string String2_1 \{ get; set; } + public string String3_1 \{ get; set; } + public string Int_1 \{ get; set; } + public string Int2_1 \{ get; set; } + public int IntNullable_1 \{ get; set; } + + public string String1_2 \{ get; set; } + public string String2_2 \{ get; set; } + public string String3_2 \{ get; set; } + public string Int_2 \{ get; set; } + public string Int2_2 \{ get; set; } + public int IntNullable_2 \{ get; set; } +} +```` + +```` +BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.4652) +11th Gen Intel Core i5-1135G7 2.40GHz, 1 CPU, 8 logical and 4 physical cores +.NET SDK 10.0.100-preview.5.25277.114 + [Host] : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + DefaultJob : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI +```` + +| Method | count | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | +|------- |------ |-------------:|-----------:|-------------:|-------------:|----------:|----------:|---------:|------------:| +| Unflat | 100 | 22.68 us | 0.259 us | 0.242 us | 22.61 us | 7.2021 | - | - | 29.49 KB | +| Dapper | 100 | 27.61 us | 0.549 us | 0.933 us | 27.44 us | 7.9956 | - | - | 32.69 KB | +| Unflat | 1000 | 260.84 us | 5.161 us | 5.069 us | 258.15 us | 68.8477 | 18.5547 | - | 282.63 KB | +| Dapper | 1000 | 297.94 us | 4.265 us | 4.380 us | 296.87 us | 76.1719 | 8.7891 | - | 313.95 KB | +| Unflat | 10000 | 5,680.10 us | 113.556 us | 308.937 us | 5,555.69 us | 546.8750 | 343.7500 | 93.7500 | 2913.38 KB | +| Dapper | 10000 | 7,420.81 us | 146.523 us | 271.590 us | 7,444.71 us | 609.3750 | 375.0000 | 109.3750 | 3226 KB | +| Unflat | 50000 | 33,989.82 us | 352.901 us | 330.104 us | 33,963.35 us | 2600.0000 | 1600.0000 | 466.6667 | 14306.6 KB | +| Dapper | 50000 | 41,203.97 us | 815.625 us | 1,551.811 us | 41,597.04 us | 2833.3333 | 1666.6667 | 416.6667 | 15869.31 KB | + +## What's the purpose? + +Unflat allows you to debug the parsing process and see exactly which converters or parsers are used—at compile time. In contrast, debugging the parsing logic in Dapper is difficult and often requires tools like WinDbg. With Dapper, you must manually verify whether a type parser is registered, and since only one parser can be registered per type, you may end up writing general-purpose converters that perform unnecessary checks, hurting performance. + +Additionally, Unflat does not allocate any memory beyond what is required to create the target object—which is unavoidable, as object creation is the core purpose of any ORM. + +## What About Other Libraries? + +I couldn't find any source generators that address the most frustrating aspects of Dapper — specifically, the inability to debug the parsing process and the need to manually register type parsers. + +Some similar libraries only support flat types, while others lack support for custom type parsers altogether. + + +::: + +### About +:::note + +DataReader to Object Model + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **Unflat** +```xml showLineNumbers {4} + + + + + + + + + Exe + net9.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + + +``` + + + + + + This is the use of **Unflat** in *Program.cs* + +```csharp showLineNumbers +using System; +using System.Data; +using Unflat; + +namespace UnflatDemo +{ + + class Program + { + static void Main(string[] args) + { + // Create a DataTable and fill with sample data + var table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Age", typeof(int)); + + table.Rows.Add(1, "Andrei", 30); + table.Rows.Add(2, "Ignat", 55); + + using var reader = table.CreateDataReader(); + + var persons = PersonParser.ReadList(reader); + foreach (var person in persons) + { + Console.WriteLine($"Id: {person.Id}, Name: {person.Name}, Age: {person.Age}"); + } + } + } +} + +``` + + + + + This is the use of **Unflat** in *Person.cs* + +```csharp showLineNumbers +namespace UnflatDemo +{ + [Unflat.UnflatMarker] + public partial class Person + { + public int Id \{ get; set; } + public string Name \{ get; set; \} = string.Empty; + public int Age \{ get; set; } + } +} + +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +using System; + +namespace Unflat +{ + [AttributeUsage(AttributeTargets.Class)] + internal sealed class UnflatMarkerAttribute : Attribute + { + public string? ClassName \{ get; set; } + public MatchCase Case \{ get; set; \} = MatchCase.All; + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + internal sealed class SettableParserAttribute : Attribute + { + /// + /// + /// {0} - reader[i] + /// {1} - i + /// i - related column index + /// reader - reader... + /// + /// + /// an argument for string.Format(callFormat, "reader[i]", i) + public SettableParserAttribute(string callFormat) {} + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + internal sealed class UnflatPrefixAttribute : Attribute + { + public UnflatPrefixAttribute(string prefix) \{ } + } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + internal sealed class UnflatSourceAttribute : Attribute + { + public UnflatSourceAttribute(params string[] fields) {} + public UnflatSourceAttribute(int fieldOrder) {} + } + + [Flags] + public enum MatchCase : int + { + None = 0, + IgnoreCase = 1, + MatchOriginal = 1 << 1, + SnakeCase = 1 << 2, + CamalCase = 1 << 3, + PascalCase = 1 << 4, + ApplyOnOverritenName = 1 << 5, + All = IgnoreCase | MatchOriginal | SnakeCase | CamalCase | PascalCase | ApplyOnOverritenName + } + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + internal sealed class UnflatParserAttribute : Attribute + { + /// + /// + /// {0} - reader[i] + /// {1} - i + /// i - related column index + /// reader - reader... + /// + /// + /// an argument for string.Format(callFormat, "reader[i]", i) + public string CallFormat \{ get; set; } + + /// + /// If true than this would be a fallback way + /// for parsing reader's column value to returning type + /// if not found parsers in closest namespaces + /// + public bool IsDefault \{ get; set; } + + /// + /// If set this value will replace the namespace that contains this parser. + /// Parser searcher will look to closest parser available to the model. + /// Parser in Test namespace, the target in Test.Test1 => matched. + /// Parser in Test.Test1.Test2, the target in Test.Test1 => not matched. + /// Parser in Test.Test1, the target in Test.Test2 => not matched, etc... + /// + public string NamespaceScope \{ get; set; } + } + + [Serializable] + internal sealed class NotEnoughFieldsForRequiredException : Exception + { + public NotEnoughFieldsForRequiredException(int expected, int actual) + : base($"Required field/properties count: {expected}, actual reader's fields count: {actual}") + { + Expected = expected; + Actual = actual; + } + + public int Expected \{ get; init; } + public int Actual \{ get; init; } + } + + [Serializable] + public class MissingRequiredFieldOrPropertyException : System.Exception + { + public MissingRequiredFieldOrPropertyException(string[] propertiesOrFields) + : base("There is no matched data for required properties or fields") + { + PropertiesOrFields = propertiesOrFields; + } + + public string[] PropertiesOrFields \{ get; init; } + } +} +``` + + + + +```csharp showLineNumbers +using System; +using System.Data; +using System.Data.Common; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace UnflatDemo +{ + internal sealed partial class PersonParser + { + internal static List ReadList(TReader reader) + where TReader : IDataReader + { + var result = new List(); + + if(!reader.Read()) + { + return result; + } + + ReadSchemaIndexes(reader, out int col_Age, out int col_Name, out int col_Id); + + do + { + UnflatDemo.Person parsed = new UnflatDemo.Person(); + + if(col_Age != -1) + { + parsed.Age = reader[col_Age] is int pcol_Age ? pcol_Age : default; + } + + if(col_Name != -1) + { + parsed.Name = reader[col_Name] is string pcol_Name ? pcol_Name : default; + } + + if(col_Id != -1) + { + parsed.Id = reader[col_Id] is int pcol_Id ? pcol_Id : default; + } + + result.Add(parsed); + \} while(reader.Read()); + + return result; + } + + internal static IEnumerable ReadUnbuffered(TReader reader) + where TReader : IDataReader + { + if(!reader.Read()) + { + yield break; + } + + ReadSchemaIndexes(reader, out int col_Age, out int col_Name, out int col_Id); + + do + { + UnflatDemo.Person parsed = new UnflatDemo.Person(); + + if(col_Age != -1) + { + parsed.Age = reader[col_Age] is int pcol_Age ? pcol_Age : default; + } + + if(col_Name != -1) + { + parsed.Name = reader[col_Name] is string pcol_Name ? pcol_Name : default; + } + + if(col_Id != -1) + { + parsed.Id = reader[col_Id] is int pcol_Id ? pcol_Id : default; + } + + yield return parsed; + \} while(reader.Read()); + } + + internal static async Task> ReadListAsync(TReader reader, CancellationToken token = default) + where TReader : DbDataReader + { + var result = new List(); + + if(!(await reader.ReadAsync(token).ConfigureAwait(false))) + { + return result; + } + + ReadSchemaIndexes(reader, out int col_Age, out int col_Name, out int col_Id); + + Task reading; + + while(true) + { + UnflatDemo.Person parsed = new UnflatDemo.Person(); + + if(col_Age != -1) + { + parsed.Age = reader[col_Age] is int pcol_Age ? pcol_Age : default; + } + + if(col_Name != -1) + { + parsed.Name = reader[col_Name] is string pcol_Name ? pcol_Name : default; + } + + if(col_Id != -1) + { + parsed.Id = reader[col_Id] is int pcol_Id ? pcol_Id : default; + } + + reading = reader.ReadAsync(token); + + result.Add(parsed); + + if(!(await reading.ConfigureAwait(false))) + { + break; + } + } + + return result; + } + + internal static async ValueTask> ReadListAsyncValue(TReader reader, CancellationToken token = default) + where TReader : DbDataReader + { + var result = new List(); + + if(!(await reader.ReadAsync(token).ConfigureAwait(false))) + { + return result; + } + + ReadSchemaIndexes(reader, out int col_Age, out int col_Name, out int col_Id); + + Task reading; + + while(true) + { + UnflatDemo.Person parsed = new UnflatDemo.Person(); + + if(col_Age != -1) + { + parsed.Age = reader[col_Age] is int pcol_Age ? pcol_Age : default; + } + + if(col_Name != -1) + { + parsed.Name = reader[col_Name] is string pcol_Name ? pcol_Name : default; + } + + if(col_Id != -1) + { + parsed.Id = reader[col_Id] is int pcol_Id ? pcol_Id : default; + } + + reading = reader.ReadAsync(token); + + result.Add(parsed); + + if(!(await reading.ConfigureAwait(false))) + { + break; + } + } + + return result; + } + + internal static async IAsyncEnumerable ReadUnbufferedAsync(TReader reader, [EnumeratorCancellationAttribute] CancellationToken token = default) + where TReader : DbDataReader + { + if(!(await reader.ReadAsync(token).ConfigureAwait(false))) + { + yield break; + } + + ReadSchemaIndexes(reader, out int col_Age, out int col_Name, out int col_Id); + + Task reading; + + while(true) + { + UnflatDemo.Person parsed = new UnflatDemo.Person(); + + if(col_Age != -1) + { + parsed.Age = reader[col_Age] is int pcol_Age ? pcol_Age : default; + } + + if(col_Name != -1) + { + parsed.Name = reader[col_Name] is string pcol_Name ? pcol_Name : default; + } + + if(col_Id != -1) + { + parsed.Id = reader[col_Id] is int pcol_Id ? pcol_Id : default; + } + + reading = reader.ReadAsync(token); + + yield return parsed; + + if(!(await reading.ConfigureAwait(false))) + { + break; + } + } + } + + public static void ReadSchemaIndexes(TReader reader, out int col_Age, out int col_Name, out int col_Id) + where TReader : IDataReader + { + col_Age = -1; + col_Name = -1; + col_Id = -1; + + var fieldCount = reader.FieldCount; + + for(int i = 0; i < fieldCount; i++) + { + ReadSchemaIndex(reader.GetName(i), i, ref col_Age, ref col_Name, ref col_Id); + } + } + + public static void ReadSchemaIndex(string name, int i, ref int col_Age, ref int col_Name, ref int col_Id) + { + switch(name.Length) + { + case 2: + if(col_Id == -1 && string.Equals("Id", name, StringComparison.OrdinalIgnoreCase)) + { + col_Id = i; + } + + break; + + case 3: + if(col_Age == -1 && string.Equals("Age", name, StringComparison.OrdinalIgnoreCase)) + { + col_Age = i; + } + + break; + + case 4: + if(col_Name == -1 && string.Equals("Name", name, StringComparison.OrdinalIgnoreCase)) + { + col_Name = i; + } + + break; + + default: + break; + } + } + } +} +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project Unflat ](/sources/Unflat.zip) + +::: + + +### Share Unflat + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index 2a696226f..8cce69c78 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/index.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/index.md @@ -1,7 +1,7 @@ --- sidebar_position: 30 -title: 229 RSCG list by category -description: 229 RSCG list by category +title: 230 RSCG list by category +description: 230 RSCG list by category slug: /rscg-examples --- @@ -319,7 +319,7 @@ import DocCardList from '@theme/DocCardList'; ## Database
- Expand Database =>examples:6 + Expand Database =>examples:7 @@ -350,6 +350,11 @@ import DocCardList from '@theme/DocCardList'; [Finch.Generators](/docs/Finch.Generators) + + + +[Unflat](/docs/Unflat) +
@@ -1531,6 +1536,8 @@ flowchart LR; Database--> Finch.Generators((Finch.Generators)) + Database--> Unflat((Unflat)) + DependencyInjection--> AutoRegisterInject((AutoRegisterInject)) DependencyInjection--> Injectio((Injectio)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index dcac293bb..eb617367a 100644 --- a/v2/rscg_examples_site/docs/about.md +++ b/v2/rscg_examples_site/docs/about.md @@ -6,7 +6,7 @@ title: About ## Content You will find here code examples -of 229 Roslyn Source Code Generator (RSCG) +of 230 Roslyn Source Code Generator (RSCG) that can be useful for you. That means, you will write more elegant and concise code - even if the generators code is not always nice to look. ## Are those examples ready for production? diff --git a/v2/rscg_examples_site/docs/indexRSCG.md b/v2/rscg_examples_site/docs/indexRSCG.md index ce76dffa8..77aecab54 100644 --- a/v2/rscg_examples_site/docs/indexRSCG.md +++ b/v2/rscg_examples_site/docs/indexRSCG.md @@ -7,9 +7,9 @@ slug: /List-of-RSCG import useBaseUrl from '@docusaurus/useBaseUrl'; -## 229 RSCG with examples in descending chronological order +## 230 RSCG with examples in descending chronological order -This is the list of 229 ( 14 from Microsoft) RSCG with examples +This is the list of 230 ( 14 from Microsoft) RSCG with examples [See by category](/docs/rscg-examples) [See as json](/exports/RSCG.json) [See as Excel](/exports/RSCG.xlsx) @@ -20,6 +20,7 @@ This is the list of 229 ( 14 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|230| [Unflat by pstlnce ](/docs/Unflat)|2025-08-18 => 18 August 2025 | [Database](/docs/Categories/Database) | |229| [Facet by Tim Maes ](/docs/Facet)|2025-08-17 => 17 August 2025 | [Mapper](/docs/Categories/Mapper) | |228| [mvvmgen by Thomas Claudius Huber ](/docs/mvvmgen)|2025-08-16 => 16 August 2025 | [Serializer](/docs/Categories/Serializer) | |227| [UtilityVerse.Copy by pritom purkayasta ](/docs/UtilityVerse.Copy)|2025-08-15 => 15 August 2025 | [Clone](/docs/Categories/Clone) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index 7f5d335ee..6c9f3c650 100644 --- a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js +++ b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js @@ -4,7 +4,7 @@ import styles from './styles.module.css'; const FeatureList = [ { -title: '229 Examples (14 from MSFT)', +title: '230 Examples (14 from MSFT)', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: ( <> diff --git a/v2/rscg_examples_site/static/exports/RSCG.json b/v2/rscg_examples_site/static/exports/RSCG.json index 7fcef4571..fb83f7c28 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -1833,6 +1833,14 @@ "Source": "https://github.com/Tim-Maes/Facet/", "Category": "Mapper", "AddedOn": "2025-08-17T00:00:00" + }, + { + "Name": "Unflat", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat", + "NuGet": "https://www.nuget.org/packages/Unflat/", + "Source": "https://github.com/pstlnce/unflat", + "Category": "Database", + "AddedOn": "2025-08-18T00:00:00" } ] } \ No newline at end of file diff --git a/v2/rscg_examples_site/static/exports/RSCG.xlsx b/v2/rscg_examples_site/static/exports/RSCG.xlsx index 8f3b99f731a7d996b0dc41bab1292b6fd140da3e..e4c5c5e77485b4de8053079107487c09d296dda8 100644 GIT binary patch delta 10505 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 Y%)|QMjFLQ5hzF_0Jj`gXx&Kr7UzgoHYybcN delta 10468 zcmZ8{bx>SQ^d)Y=-5r9vy9R;=2n-My+}$A%26qTBxDyBjx8MvgxVuYmcL)PPmv6Uz zwYB@IUiBY+Z+D$r{rcT|?kP8mHUoW9MMNTmgF{1uTgu@1a!F%60fB>qqlbrs!+9Hh z9l3p6+#SqaTpYN3ogCx8Los@IFe6NU?p9aP|FFnLMZPN6{M0^|S~YH4etuOI^Ys?C zr-`;<;{0JFmg0jqAzOwz5gKL$ISCh$5jeNfR43iSt#m0jS}f@Tk;DSo38W%V$COPB z*=NNfy`IqiE4IfAWW>Sq>g6=QhUBm}rU2XFCP6hRU5p_xedyKi^-y1?NamBEsPIwO z&-;!GC*i>H>}9!S$A7S>SKq|OiOqzuc?)Hiq$r3+D}S@IDQ-R2o+jH)smn9m{|j}* zBbYutqK8*gpLmE>b8Dmer;0xIYsH5%$8wNJ z>_|G3TYGz5-K<82^2UiUrd1ASASfNp>G8QeY(1@OBZ`IQ^`-NjX@tb6rULNAOW(3p ztyAw6?R6vY@5A}_?RrGbhEYdg!`4YNam|MP{li)RNi#)fpv~0-)!4}@4voS;UaGpB zqgSo#{oEPp&skHTQwS(MwI<|l#2uvj(tB!hz_In9Zax2H{q-+2R{9(B%&@BTxBF{< z5*pu^neQ}^`yE7sUzdtJgWNAqbff>2%m1m?i1=L*L0Gn@5B^TSTiFA0IvLy@r8%Wu z(9h@>2h{p&y<0tI?ENq(w+<*##Ev`cUuJEQ#1z7qw5X zJ32Wwiira#D7sR+fPB|+{n?-e4z5g3Cj3BJ@K&MPUp~89vgk3a3KN8BnB2wBsvhTl zZsot64nJ`A4JN>wF&q2PQneBRl%o#*>i|X#GVkZCpNuDXu4CO9*LUWI-3BgeE*{=#b#cT z;BqT{vdV$SB|LEWq92HTuqaZT{uJMvVMRtYa>z5knzw#Fn{Vj!aZ`yr^j}c8i2XFI20VaXIZe!7`(jM&+9D-=BzJU) zn!?&MLA=S=S?6571MGl;aNN^k6H%JS;Y2axKR0c#&}+9}MkxKY%kuET0)0FvICs~EqEkj5+>cy6 zxleZ`K$h;i!qMJaYqk$6!3B?C9pS<0`E;5LIx_pl@V=;0UBKFkUi73Gd(9CA&T|Ny zmUMD7ENdD3hVVgPqF3#>MgV2e_U%c7Qrm*8Tkrf#c}_~@SBo7((Uhk5T*#Bt0=+x$PJW~T z(;~rkIpmMeaG9~{K8l(^8+!n%RIiz?;}K{UMC{N47pGY19^R- z%&lK3zwrG~H9f#M?ye#g0#Qq^JxXC`JLAWk5-~4J1Q&GGo<~+;sAX}q*yXwXn+R*M z=bkYhQfB01A-dVIRA&Af7qrI`@I)9)gQBV0@ay(fMR(cQpS5PKS~V|~dUMNkY%T?* zR25{})|kmFB0Lso7AoQPczGe)@hw0g84I?ZZr%zx^kD|m1weYLB2il7FI%>5LhYml zq*8c0I!Hp<6SJ!x)87?4t*H9b`1ZXNLf6GuoNd1t-lk9?!6(ad=>#Gf$kpX6RJYKX zdA$zMjppS3Zm&9*O8&+EtAA%PM0v)FiV&o9C*m|e`y9`Ywl?8QxB0!MCKZ?;v%X-B zIy^xXWvk7abi2oyWE+Y{t)$MPG8^1<7FiXY#r$*JY8Lwk_O_nLXw#a5lj%nX?jN^) zjA(Xkx3-jc-e&h@hFg&xVv?Mx|1zNYYOn%U|C5d7v~FX@U;u4$ozb|JP#zjRp%4hV z6V-QD@=V!A(9f6D^Z}F9(LB?>fpGJTIk_1&VvyfUvhai;B~ITV2;Dipgz%rS+Vf0~ zC}&S6N26i}wSQ4QU#YNHqO7h_7~!|CYuR$NTEH>s8g+AE^FYk@qzZLn{0N{eWoMUw#}`p*<*yE*f(1-9+LJ=3QyEim=Q=)W*PF zd{_AiFD^Xf9kon>EtTmUGqt(!L3-Nsw(%fLDWV4(e(l25dcYyJFGk&n!f_N+)D67^ z{_iUt`GK3*0UK( zjljqm6I9k`r)5>p!IR!bxq|}|1a`(7x?8R@ne1gU;Wek~kx5>YV@Y>N9hmSNf(!C} z|1@P<4NtC=4h=Wcgm5!GRdh_KFSKLN08v@boT>^Qet;HrD$@?{9kA1~LL2P2U?RN5)#0^v~VPLCbdi%!7`5Smnk5ahgKB@US+GYeq zI+=25G$_F~f{J||>V7o>PmOsqUxVWU*spjaL#=ipx z^0ms)?TGB3^UbXC7>Ze;9FXO+x$19JE0&0$B)LCLkiuusya_qWei3LA2mCfQ^NgYds@Yd@)g8%-)&c% z(+tTHbyou9+u^oS$Mxbh1M;6g!EW@~$bOpB+oWz8Rhz^$#}XbkogufqSicvEeuwJ? z1fhJ>3v%{W!xb%uH~xd8DajxtUN{#&Nljs5^RqQ}Zl&q0u}PH`ga*X;#cX8&q(CT2 zY(2(#q70+?dS@Q!Z(vE5Z3^-Uan=QrunsuYm{R8MFXXpIHMq0^b5I%`5?c!EM|!jh zg}0powyyd0UlWnE)7}v6RS(dgSdnQ)Ts^HCgEi^XB?W|p=YSD-YrU5#Vv{y?NW5HM z!^}BXYtD-rn7s80dL^+_QD|D7QOPMsjykNXr1n||XsOD)Yj&wRXcCl39kLW$l%@m;3)y9>-CXBEfb%4_(nY-`E{6l%ajTGLo z`SV%NQTRD*y0D$fe+#Fh#t1vsq1-@T*)`$8p@Ct78LGMIs{%E}GqtT{!itvKRH@Z} zawUOVQ$mIF(G!52gQ6mnamV9%MN^E=$Geht&FcfU-MXI_nEBi+27wxt5@r1GytKr# z1r4l>HqmZ43zGTM{azxuFG$d1zh}QJ`Ochn#I}au^SF+NkZEs;$Jh)CbBy7nYL*Wi zNl*sdz(a}1N~;z|cRf-U_+{E?W`4e93marA@srVx0N80INNMMn!$D6i%}SspL0Zlb zM>+wRX|{56HlY6x%9(C|s9YZ&pl`wiiB0LYTocZB)a<1oW(&9BCBhP@?>c04sy+#n z4LeO`XKORVA_ROpf|l2a(uxugEMaN2>&3JxXB7+)CQ$hYU+OT=z9X9?C@ZnR!x#6Y zDDX&K4q&#%d@B56bIEU+XV^t(51zph2T6tY!gp5KUM|7Kvo99$otF8$E5>mns{4Go zWI6uX7}t{bwi@yPFg9Q2*-yRHWRyfl9JT5*M-Qf9ex;l1V8JiJn4_M;GNY}i^a1c1 zTtrTd6UWFrS}oEu|A?^_c$wU?$=*7W^0m1`Msi@kgwL;APxCoL?wpMb4O+s&14WN% zHUA)yx!<~X%TeDH-sMV^EU#Nn_c{C7Dc@g2kT;r@Nkq-+6g7mE+IZ!_Lv4GKr7Twx zn}FmqjdM?-`5Z&6fBrhP4OgyfWxLUc`VAuc4g$}dwWo~bx(Gz1+--yIF?A(4_<#3P zpW*qi=S<$GgPXVii4AYyX&L+X;=2`IS^MyInBi7_8JHN48pNuqkfCL7^xqYq{wjq@ z&2ZU!&}G#sAL%}3y**6*dy)G`B!J!KchS0a#nTL6_yV25-}$ z|0M8r7D9~;vdY>kM;mVGf6H~fJ{Z0;5W-I=ssJss?!KK0q@WqNRMNbcS*W<0;Y=zb4cc=u<%6`5)8nZz+{f_#E z3?K?%jJ4{rG255cEfXfNqRl|eX=f4qF2#AF2NU81-7VwuEm3AR^@uBIZZDl=RY!6P zuQdP|ycna({vpq@3fF=KetnnOW6LnM{FmMpQYsSyMdda!SsHXiG6s}}CcvLBJ0ziQ zN0eGsG+k>W*brga7rBa-2l}BvC*h?CW+~FPy@PCVB**O>;jECyH57jpQ&$sGZtUYm zhH&?SIHq)aAMThYU9SKpn~!WWAo;O6c;CCJ4)ANEzeO7Iv_o@#-c!d00gw`RutB&g+eniD`& zrZZvw-sx<$B5Ut}@R~J%iqn2G>aR*ayodh%Jwl?ey-LI?etl|Ux5w^shf7Tu@QRd( zi>Ng#e|S1d&59c#Rf%SYT6c;<4%|z?2VV__5wL+G!1}mmo?XOo6x7^8P@VaUo{V5E z_t5laLkcR-LC7;voW@v*M6sTd1@?%R_OQic=LE3K@LyQCg_Qg$++I;Ly`Z-Dax)3_ z=oMXDl)MqnfR-rt5?1DWz`e%={?rJTWAf)A_8;b1fHUBqyjFF{Z1W;v0Y`&U%LSo@*l(rCyxp{+Zqv}wP+#_zlMA{TM5 z!wdIYkI~zS*Nn`MR6E86CuSBp0%8;}F;j!{fGi+^UB5HJ;1({t({i>5pMkCaU79Y~ znTQlcbx2i0BLW;pM1fJMkT!aB&mhA#1Fj=t)8n9WOVq!HU78V4Dm<54iS6=g6Q4RR zorKVsT~vo}r%Q08^%oe#U((b0zSLi%VpR%TR8nd_Bf%YV4|?JvRaJ`#u*B zeGP)$hm{U3DFwyh2x)mxHM!!ti*M`XeUQL9C@qr;rP}9)S4>)dezSKaJ@&j-@!&g> z+fHgwwscm0!bj885|PTiCd-MD$hECYEG6sPPRy=nR=OchyMvjV&C{Kz^x*WaM19=# zbxjcSb(MmjV!KDDmDcQ`ia}YG>wqEu`c7md2755~0tG1S2~%KoQqa50Ut8^TS}(3! z@^O_@V?;Q-U%_gm=hf3YTB?XB{4DYLG)oyP9i38%dL-9MdhM+L36?YNElh_{d~Y_M ze8k4tZCE)oQ%8b0D&cF7?zdk+dBkO5Ae0;I3+(gX^qk=i&rqv7#I+4ZeT8P1tcNE8Fo+cT& zxKWitjt@^&Q9}mAfWMPcg1F;}pO-e+3U~3M1WN_<%1>8RQ^kTq z#yaA^@+8zN)7H^rlkEoU!ATekljvcksk`(!E9zICFEuVwdF9KC#Rv3OmxJH}Uj1n$*!0YKSR9ioIS#CI28y>88Z zu7Hc6XDEl1|CpuWwL_9=Y)6=PPJAN+uL%^B>P_^Gf(d=@vK8 zqsMY-UI@cz^74nH4`XfnK8LMiT%QYnqWT8?y~s#Md5PmlBM8c~Fcqapx*`oOO<_s< z4t)jcn|MeS)qr6!#d%$y;>~eCw^e1yx%ciUEj+v4E7##2vfJQm*v(arIeuC(A_Jxzb@j)pm!4{HwM}dzjxFl! z{<&g|! zo)Ke_NpYdLgV?G}c};er;IdK?XN51Bsep?p;H)2DvjmzQ9-S*58sL~Mw5eX%8w+;P z&0TCZ`Dx#bo`0r00G89lZQZRbDHwMc#pPG7CXe7S04Tbymd&dPUP4JaT3@A-D#SJ z#;6M2mejrmBT@+JLEJj`*5w@X!60SG42^+N7@5U_sp_v|?rxvovvnbCikVh6IX`7n z+gYl?Sd5Wp(Not%e7h1aP|$EX3ao2KJ9l3u1-64$9vp} zF=J(yQuuH{0ZZD$T+R{%CwN5H{>TC@@Gt<8OcA#eoN+tra@rY6bKGdfP4Xci3(u|% zfZC50u38c3o2{~hfl}wplOw~i{mUBa05$M5>H%U%unj_A$A6_PlW(~R?bw>F+)O+C zwr&Hh;{>%FwuC`=^k)wKDwK!qZ8G&MbeLgsL{dqn;oV;x71q1{RX56(wavl6qQG%; z^$Ff)?r2I!mVS0)vcg11fSQL>YQHNr+MA=a7B6saaS0lpoV`54NwfT_(Ynr+^i9b7 z3V%Bd680RB5;>1PEH56X!h0fy@oP;02AXeSy4aYC8zt14s1e*UPliZ$xE1i$7DV|@{-9}h zxUT3#9J$;+SPMrq3iOSW6okJn)ejJy-{ROZ7~0HQakV*ATHTWEZhCyHW2Hz=vsF^L z_w%MUr7;!@+oifoa4DPUg~Db2Xl?YyKCZ&Z4?h}p&-4i@%fiX`kliH`u?#7;+`PGs zGGL$A-@yzM)6JXqy=)5*2?rMbIj_d1#VQG4NL?B=SJL9o_IA6=AKIWvfD~^qaQDG< zZ>P|nAPNw9wnOxf%D?PdEpFf+*5d24#GHwAW5aVtllNeV$Nc8AB4u8}mC+;hGOlw3 zmQdJk*xs2tQ|=w4{-Dt6bQhP+SVEPtl9Lj%nwYyGM`3VfNZjmQMlCpl(y92P%Io54IgY>^$1|K`2~2Mg0aDOx}tsC1aNi3Cn<^9)?W1 z_~-s1|9%NiT^xq7U${LjIB9i>e7;vZXIfSgy&_`bP?=C)9%t%D{?y*>{u;SZi7=0G zajYmgzUh%&|0AE+ab%<#!ibT-j~s9+Kppv&$N9dq_GH)zgcnUYiM6mI(9@F|FGdEQkk-{C|!sw+=L0^n*} zIon|vwy)0H?w7j7Ngcx>y_he*mw!T^nJTF;ja_Z0$Wh0%Aj=+@fl*Yd_kgpf zZSO)ZJ6fE$zD#*wksy&j^7XsecYKnH$IzCoi=OJqK>CK2pV~~UdK$|OBrhY*?d9MZ zdR9w}{?H;F`m;y}sE9qE(ef=}#Ad@A-5c7U?9y5)8auBHJ5BB4FOf?l{&*?7D|Qrt z;)nN(a=us^esi24!SE?fKADyBB}%;@*P&QRc6*ikbopJ7mDJ;N$GuDIQyQ_`lX@E1 zgncQW^fg2~iPK-mRl2&+HckwFYrov?B6^o~Z&qF1uOKuC|5jNSHPnLY3unZ|SA1`ujKTU4~ZV8P-L!t zKJ@a!xu`j`JbT?~)4E2+Sj{78a?)39WROfW91m+k7cffVc2D<6q{HzjAL7_M8|@ep zZqBTu==)pPnOhv&9jwPF14=5nVQ1dnuR3Pa1& z=Yw~ZSHM=x3%?Sc@x-hIUkGbYlTm0bHvqy-MoK*l)_lf!`>OfK_3 zm+nL977829`SkKPOoDmPP0aW;%DcM>lNsFHm)lCYt^-is7mx8dcX)qgiXsZF68TS*HYv z<%WJVr0<{rJ4dpoR(>6?ThlI zCS_XLV~>pMT=sRA<~Wt{zrKFrBc?M)B`2X^L=PZ$&G3kf6m9wk?S!oO(s&!k6?E+~ zXkjUR$*pQhPq&>_Gx7p^rPOJ;z^Zuy6TZIQ~4#9lC4iI{Gjv|Tc!I9PNk-GDjfHCl1 z5=lGuW6?9MSVGYc32oz3=cS6+4J%?-`y-lsxVbOPAc0*?kC$TO+`v3@^l=rlb zW;+Et=`)KiFixL`H1;TdM!muIk~DmDdUMbQS7Hx{3h>^t-B$}we$Nh{2IhEA58@*l zrYjC2<;W(%nNTj&^-X71~6o3H5AgoEsfxOm8@>Kg!v{>u_rn$c@_$50V- z7pp}a7rJ9{dw4SoyV^e`Ws?u_AS!$!3fq%PnSn14X@;IAMYBOTIOoy{NbBeR?T4o? z&V#_S6Il&EzPN+f%xce}c*OnVu)v6|_zuiD>q^A=BrCY}2@KDkpF7tbQ5GM|ijm*E zZA2Aq$d|W@R^Mt{IwGc=r+H}xx!tb<)pKVfwfO`O8@O|lrfw26s&@4t>nw}x;0FK0 zzQebz9xG5pQ2?Q%^y7+hj9I}ldo1t|=t0d_Lb$6kE(tb@c9kqMb&HR*->q0&LJ89L z1cN>E!4C1VqU5@dOPw{&Dl4|Drqf7oIWo5%%h3}1S5ywMc#+YNSzK+TP=d^T2!-+# zy$7E#^x!b=g_Tf~(;7q@wKyV|c~G?u@kajviFhxNwafkqQQGmgi*kn6lap9U!`*HH zyaHG*H@1_H=zJ+@`r9|+pR40FwvB#C_R#04r4*F^8q*D) zfNs-IGRytu76rZYI%!>a(_rXu%G+>WO3bWTnZ%90VW+5=_d08ABS?zaiR>|_-{wb1 ztq3_8gp&|N&1E`ODjeY@SR{u&jHfKg<4hiVpUt;x(o@M0@*T#0xhLqqX`_=9J`Kc* zE6p|!FF0xvh@Y}!$IkpdU)2ty-#`yQRT1pk_+2182RbVpiBSKHeG`F8m3vxK=of0y z8FCZ*`#Qu1j@{Getg%N{WFNgq7G}tiK+pKoK>F|5jYz&ppCdMW=gJ;F_LWy{jL9PK zO6MtGjs;tjAvFwBULheug@f!)9*7O!;fJP$fqXYOaxYe5=~?S;x(LL6;wPya8clJb zerp%yfKY;YYu9S;$q+RCNW!yfMRy77VDlN=q56{9I2K3MRg_a?6&T)Ux=>3Y)uF$b zzfgA~+TOJXqGf-#>Z#|kR%DF9d?Ci(dI;Bn(bm#$l|Yoy?npF>HQriw4eu!L=D#U3 zR!Q;KEep^>OK8F3jK4DXQM+s`COoJp=PpJHcp@l~s8}@oO78_fHQua7@1M7O|7#G| zRv*cKU3`WAAE6lB|JKAM7cw_Aq_b1N3tNctiint73Yzio3ksN7TF}#SOG$8RTREC} z+POG;*xI>zNd1rR|IyRMGfUX7fR8xdgP``k{|V>%4?Blg?UX;P1HG3U{~}8$X~+?* zE*&pOeZlcBhV)2~{tTw}UjBHP{`V@lvpPR}-7l|CykFpJX#oc#n)`rH(Fsw`l9XWW zsxwT$Zi2#&R386d9}_a7hwle9>jHz)9#nTf^KUtV2SPB?-=fEPu1r?(S9$QNpb`-y zgy-Jy2|YyYfkAL|oGDkJ_qUn}L@Vlhez`h2DOGrj7p>@G@8a*29}{P#*yfj^J(l zBJbktY31zMfWw6ckM=(jLof@sAi`1x*o0g3{}9BL|Gn?t7W%)B p75JH(9Q{9={}WwW9wPWAun-UHe=C~tP{I#^19_NHZn*w)`Cpc6SA_ro From 03186c3e0a017cde0f27474ad38e845e19928fcc Mon Sep 17 00:00:00 2001 From: Andrei Ignat Date: Tue, 16 Sep 2025 21:52:27 +0300 Subject: [PATCH 2/2] unflat2 --- v2/book/examples/Unflat.html | 64 ++++++++++++++++++ v2/book/list.html | 6 +- v2/book/pandocHTML.yaml | 1 + .../static/sources/Unflat.zip | Bin 0 -> 1743 bytes 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 v2/book/examples/Unflat.html create mode 100644 v2/rscg_examples_site/static/sources/Unflat.zip diff --git a/v2/book/examples/Unflat.html b/v2/book/examples/Unflat.html new file mode 100644 index 000000000..e46557201 --- /dev/null +++ b/v2/book/examples/Unflat.html @@ -0,0 +1,64 @@ + +

RSCG nr 230 : Unflat

+ +

Info

+Nuget : https://www.nuget.org/packages/Unflat/ + +

You can find more details at : https://github.com/pstlnce/unflat

+ +

Author :pstlnce

+ +

Source: https://github.com/pstlnce/unflat

+ +

About

+ +DataReader to Object Model + +

+ How to use +

+

+ Add reference to the Unflat in the csproj +

+ + +

This was for me the starting code

+ +
+ I have coded the file Program.cs +
+ +
+ +
+ I have coded the file Person.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is Unflat.UnflatMarkerAttribute.g.cs +
+ + +
+ The file generated is UnflatDemo.PersonParser.g.cs +
+ + +

+ You can download the code and this page as pdf from + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/Unflat + +

+ + +

+ You can see the whole list at + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG + +

+ diff --git a/v2/book/list.html b/v2/book/list.html index e53b409fd..8d8218fb1 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 229 RSCG with examples => +This is the list of 230 RSCG with examples =>

@@ -942,6 +942,10 @@

+ + + +
229 Facet
230Unflat
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index aebb6f5db..86909edc7 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -243,6 +243,7 @@ input-files: - examples/UtilityVerse.Copy.html - examples/mvvmgen.html - examples/Facet.html +- examples/Unflat.html # or you may use input-file: with a single value # defaults: diff --git a/v2/rscg_examples_site/static/sources/Unflat.zip b/v2/rscg_examples_site/static/sources/Unflat.zip new file mode 100644 index 0000000000000000000000000000000000000000..aabd185159a4692b51993ff379240cadb5f3bc8b GIT binary patch literal 1743 zcmWIWW@Zs#U|`^2ShL0;`U=yRlzog0442p#7`T9(?Xq?0}Q(YF5h@@idWa!xXp-{e{tacGp+NV=vQpiKM>WMYW{tm@pHLz zJfA;))AOEQGpRG?NNdsQ&qh8|0t4M*G?XV!VHIB~^r2<0M&pSz#e#@w;l7ugB~D*T z%)TtOEhV#2ry=yeh(OCkznnFT_r?19|6DWY?}4KSObhyNbeydHr zmq%PS?>dR!N z2c7?9a@SDzY*}n<@vpY^g0~i{nX%PAieA4;=V#`YEy~{Mof7SxIo<3cz`9W058ivi7&#P8?0!bGobD)7QTVh-?%@4T?!74!m=DWI^e(?` z^n3cE=uaw675TO&HaM40jY>bqmNxyILvDTg+SNBdY=3&|UvTN;;`+1SewHo1vGVXW z%ksrLPCs1Vf9O?x`|-qco0>M~=0CLTzxH)%hlBys^Q0&FvK!u=xTGEckL8oVST+@_ zT-gSU-FH9?ihD>byQJpk>j$J373b&aB^Oukuda_v%F8NrOe$LClo1!@m(=NNx;SV$QOkv`ALCgS%Eq(s}`7OsvAcxRM@ye#n{kY(NcZmjtE7Ctt%|-`4=%{ zu}r#kW{(i-d6Cwv)-P9tvRjh`0=pNk*s(;zSU>h4{|lXvsa)FvEN!pfX`1Afz2=zp zvgJv}@*a$W3un}RncO`Osq@F~^y%j93&v5}c`t}AvQymj$RhV7^K z-_PIintJ&3DXYM5x7PkOlU#II_S>>eOtM?wPCFEIgDZF=Yx|-rZ?E0TXAF&6u+_lO z$~=NCLpE;T8fW$3h>VjDIhQ6~ll=7m2aCzhUg<~kj)iaMW>&ty>F}X>@1ta@I@#{Ij?~8$%z2@la}8I< z)HFVsDU{{%kX!%a*W$veYnE3-^qZe7V-AcjR94}9zwZ3}jmh_gs;6j|xa`|+Z^|G3 z_VS_?I}Jpxmz}bzlE1y>Uc&OI^{ZMoMnz8YeRY+kS5)oetc_dxSg$`;H1@5qV!js9 z5b{6mqvFpO+dr5pOk1XSzqcewXKF%tNhbdWKE9J3`Bo3sFKMiCS9p3i;Y!Y;$2ZM< zcgJ4po@bAUpB=#XQB|y7YXyv-6eb1+8PxbeBr#wV6%^%XwNCQ&14dKp^|e>5BgD9G zsHAp2iO^cHcGH583rb=+cT$3U{tDj|cHAMw-FHN^VAhH$Vh2C%{rTlt@6+?&`OV6| zNgAn?|5RIe-KhB5ZKlOHD+F1)KRMQ4P;XhvQS~Y(^phJ~vfifNh{L)f4-TX_1WjJ4 z)!w4#yO1TQi2s~-wvbg%+eJ%NbJ1y{W{%yvce1i2yOI{xbMn2Ge|l?98n66*rta@0?m8{e%zkq&d`P<6CVikg1Ww(#<#Tjw7>WDz4&?~!h6rAT~oO3i11i6PVjH~ zBoiy@^q*lH