@@ -32,7 +32,7 @@ internal CsvPlugin(IGuidProvider guidProvider, IReflectionGuard reflectionGuard)
3232 Name = "Csv" ,
3333 CompanyName = "FlowSynx" ,
3434 Description = Resources . PluginDescription ,
35- Version = new PluginVersion ( 1 , 1 , 0 ) ,
35+ Version = new PluginVersion ( 1 , 1 , 1 ) ,
3636 Category = PluginCategory . Data ,
3737 Authors = new List < string > { "FlowSynx" } ,
3838 Copyright = "© FlowSynx. All rights reserved." ,
@@ -49,6 +49,7 @@ internal CsvPlugin(IGuidProvider guidProvider, IReflectionGuard reflectionGuard)
4949
5050 private Dictionary < string , ICsvOperationHandler > OperationMap => new ( StringComparer . OrdinalIgnoreCase )
5151 {
52+ [ "read" ] = new ReadOperationHandler ( ) ,
5253 [ "filter" ] = new FilterOperationHandler ( ) ,
5354 [ "map" ] = new MapOperationHandler ( )
5455 } ;
@@ -84,7 +85,7 @@ public Task Initialize(IPluginLogger logger)
8485 }
8586
8687 var context = ParseDataToContext ( inputParameter . Data ) ;
87- var csv = context . Content ?? throw new ArgumentException ( "Input CSV is required." ) ;
88+ var csv = ReadDataFromPluginContext ( context , inputParameter ) ;
8889
8990 using var reader = new StringReader ( csv ) ;
9091 using var csvReader = new CsvReader ( reader , new CsvConfiguration ( CultureInfo . InvariantCulture )
@@ -132,6 +133,57 @@ private PluginContext ParseDataToContext(object? data)
132133 } ;
133134 }
134135
136+ private string ReadDataFromPluginContext ( PluginContext pluginContext , InputParameter inputParameter )
137+ {
138+ if ( pluginContext . Content is not null )
139+ return pluginContext . Content ;
140+ else if ( pluginContext . StructuredData is not null )
141+ return StructuredDataToCsv ( pluginContext . StructuredData , inputParameter . Delimiter ) ;
142+ else
143+ throw new InvalidDataException ( string . Format ( Resources . TheEnteredDataIsInvalid , pluginContext . Id ) ) ;
144+ }
145+
146+ private string StructuredDataToCsv ( List < Dictionary < string , object > > ? data , string ? delimiter = "," )
147+ {
148+ if ( data == null || data . Count == 0 )
149+ return string . Empty ;
150+
151+ using var writer = new StringWriter ( ) ;
152+ var config = new CsvConfiguration ( CultureInfo . InvariantCulture )
153+ {
154+ Delimiter = delimiter ?? "," ,
155+ HasHeaderRecord = true ,
156+ TrimOptions = TrimOptions . Trim ,
157+ DetectColumnCountChanges = true ,
158+ BadDataFound = null
159+ } ;
160+
161+ using var csv = new CsvWriter ( writer , config ) ;
162+
163+ // Get all unique headers
164+ var headers = data . SelectMany ( d => d . Keys ) . Distinct ( ) . ToList ( ) ;
165+
166+ // Write headers
167+ foreach ( var header in headers )
168+ {
169+ csv . WriteField ( header ) ;
170+ }
171+ csv . NextRecord ( ) ;
172+
173+ // Write rows
174+ foreach ( var row in data )
175+ {
176+ foreach ( var header in headers )
177+ {
178+ row . TryGetValue ( header , out var value ) ;
179+ csv . WriteField ( value ) ;
180+ }
181+ csv . NextRecord ( ) ;
182+ }
183+
184+ return writer . ToString ( ) ;
185+ }
186+
135187 private async Task < string > ToCsvStringAsync ( IEnumerable < ExpandoObject > records , InputParameter inputParameter )
136188 {
137189 using var writer = new StringWriter ( ) ;
0 commit comments