88using System . Linq ;
99using System . Threading ;
1010using System . Threading . Tasks ;
11+ using Entities ;
1112using static Entities . Plugins . TranslationManagement . Smartling . SmartlingFileData ;
1213
1314namespace Entities . Plugins . TranslationManagement . Smartling
@@ -54,7 +55,7 @@ protected override async Task ProcessExport(CancellationToken ct, List<string> c
5455 {
5556 string packageId = Guid . NewGuid ( ) . ToString ( ) ;
5657
57- dtmData = _fileProcessor . ProcessExportData < SmartlingAppData > ( ExportLookbackInDays , ExportMaxTablesPerFile , MaxRowsPerFile , ct , db ) ;
58+ dtmData = _fileProcessor . ProcessExportData < SmartlingAppData > ( ExportLookbackInDays , ExportMaxTablesPerFile , MaxRowsPerTable , ct , db ) ;
5859
5960 if ( dtmData . FileData != null && dtmData . FileData . Tables . Count > 0 )
6061 {
@@ -112,60 +113,44 @@ public async Task BuildPackageAsync(SmartlingAppData appData, string packageId,
112113 }
113114 }
114115
115- public Dictionary < string , SmartlingExportFile > BuildDtmFileDataCollection ( SmartlingFileData dtmCultureData , int exportMaxTablesPerFile , int maxRowsPerFile )
116+ public static Dictionary < string , SmartlingExportFile > BuildDtmFileDataCollection ( SmartlingFileData dtmCultureData , int exportMaxTablesPerFile , int maxRowsPerTable )
116117 {
117- //A dictionary to hold all sub files per file
118- Dictionary < string , SmartlingExportFile > subFiles = new Dictionary < string , SmartlingExportFile > ( ) ;
119-
120- //A dictionary to hold all sub data per file
121- Dictionary < string , SmartlingFileData > subData = new Dictionary < string , SmartlingFileData > ( ) ;
118+ if ( dtmCultureData != null && dtmCultureData . Tables != null && dtmCultureData . Tables . Any ( ) )
119+ {
120+ //A dictionary to hold all sub files per file
121+ Dictionary < string , SmartlingExportFile > subFiles = new Dictionary < string , SmartlingExportFile > ( ) ;
122122
123- //first we need to divide the data based on the exportMaxTablesPerFile value and then the maxRowsPerFile value
124- IEnumerable < IEnumerable < Table > > chunkTables = dtmCultureData ? . Tables ? . AsEnumerable ( ) . ToChunks ( exportMaxTablesPerFile )
125- . Select ( rows => rows . ToList ( ) ) ;
123+ //A dictionary to hold all row chunks per table file
124+ Dictionary < string , List < HashSet < Row > > > tabelRowChunks = new Dictionary < string , List < HashSet < Row > > > ( ) ;
126125
127- int tableListCount = 0 ;
128- if ( ( bool ) chunkTables ? . Any ( ) )
129- {
130- foreach ( IEnumerable < Table > tableList in chunkTables )
126+ int tableCount = 0 ;
127+ foreach ( Table table in dtmCultureData . Tables )
131128 {
132- SmartlingFileData subFile = new SmartlingFileData ( ) ;
133- subFile . smartling = dtmCultureData . smartling ;
134- subFile . GlobalizationMetaData = dtmCultureData . GlobalizationMetaData ;
135- subFile . Tables = new List < Table > ( ) ;
136- foreach ( Table table in tableList )
137- {
138- IEnumerable < IEnumerable < Row > > chunkRows = table . Rows ? . AsEnumerable ( ) . ToChunks ( maxRowsPerFile )
139- . Select ( rows => rows . ToHashSet ( ) ) ;
129+ //Get rows based on the max number of rows we're allowed per table
130+ List < HashSet < Row > > chunkRows = SplitRowList < Row > ( table . Rows , maxRowsPerTable ) ;
140131
141- if ( chunkRows != null )
132+ if ( chunkRows != null )
133+ {
134+ foreach ( IEnumerable < Row > chunk in chunkRows )
142135 {
143- //create a new file for each chunk of rows
144- foreach ( IEnumerable < Row > chunk in chunkRows )
145- {
136+ List < HashSet < Row > > rows = new List < HashSet < Row > > ( ) { chunk as HashSet < Row > } ;
146137
147- Table subTable = new Table ( )
148- {
149- PrimaryKeyName = table . PrimaryKeyName ,
150- BaseTable = table . BaseTable ,
151- FullBaseTableName = table . FullBaseTableName ,
152- LocalizedTable = table . LocalizedTable ,
153- FullLocalizedTableName = table . FullLocalizedTableName ,
154- TableSchema = table . TableSchema ,
155- SystemColumns = table . SystemColumns ,
156- SourceLanguageColumns = table . SourceLanguageColumns ,
157- TranslatedLanguageColumns = table . TranslatedLanguageColumns ,
158-
159- Rows = chunk as HashSet < Row > ,
160- } ;
161- subFile . Tables . Add ( subTable ) ;
138+ if ( ! tabelRowChunks . TryGetValue ( table . FullBaseTableName , out List < HashSet < Row > > _ ) )
139+ {
140+ tabelRowChunks . Add ( table . FullBaseTableName , rows ) ;
141+ }
142+ else
143+ {
144+ tabelRowChunks [ table . FullBaseTableName ] . AddRange ( rows ) ;
162145 }
163146 }
164147 }
165- subData . Add ( subFile . GlobalizationMetaData . PackageId + "_" + dtmCultureData . GlobalizationMetaData . Locale + "_" + tableListCount . ToString ( ) , subFile ) ;
166- tableListCount ++ ;
148+ tableCount ++ ;
167149 }
168150
151+ //split data into sub data objects
152+ Dictionary < string , SmartlingFileData > subData = GetSubData ( dtmCultureData , tabelRowChunks ) ;
153+
169154 //now we need to create ExportFile objects for each sub data object
170155 if ( subData ? . Count > 0 )
171156 {
@@ -175,27 +160,30 @@ public Dictionary<string, SmartlingExportFile> BuildDtmFileDataCollection(Smartl
175160 subFiles . Add ( fileCollection . Key , AddFile ( fileCollection . Key , fileCollection . Value , dtmCultureData . GlobalizationMetaData ) ) ;
176161 }
177162 }
163+
164+ return subFiles ;
178165 }
179166
180- return subFiles ;
167+ return new Dictionary < string , SmartlingExportFile > ( ) ;
181168 }
182169
183- public virtual void AddDtmPackage ( ref Dictionary < string , SmartlingExportFile > dtmPackage , SmartlingFileData fileData , string packageId )
170+ public virtual void AddDtmPackage ( ref Dictionary < string , SmartlingExportFile > exportPackage , SmartlingFileData fileData , string packageId )
184171 {
185172 try
186173 {
187- Dictionary < string , SmartlingExportFile > subFiles = BuildDtmFileDataCollection ( fileData , ExportMaxTablesPerFile , MaxRowsPerFile ) ;
174+ Dictionary < string , SmartlingExportFile > subFiles = BuildDtmFileDataCollection ( fileData , ExportMaxTablesPerFile , MaxRowsPerTable ) ;
188175
189176 if ( subFiles ? . Count > 0 )
190177 {
191178 foreach ( KeyValuePair < string , SmartlingExportFile > subFile in subFiles )
192179 {
193- dtmPackage . Add ( subFile . Key , subFile . Value ) ;
180+ exportPackage . Add ( subFile . Key , subFile . Value ) ;
194181 }
195182 }
196183 else
197184 {
198- dtmPackage . Add ( packageId , new SmartlingExportFile ( fileData , fileData . GlobalizationMetaData ) ) ;
185+ fileData . GlobalizationMetaData . LastFile = true ;
186+ exportPackage . Add ( packageId , new SmartlingExportFile ( fileData , fileData . GlobalizationMetaData ) ) ;
199187 }
200188 }
201189 catch ( Exception ex )
@@ -212,5 +200,68 @@ public static SmartlingExportFile AddFile(string fileName, SmartlingFileData job
212200 exportFile . FileName = fileName + ".json" ;
213201 return exportFile ;
214202 }
203+
204+ private static Dictionary < string , SmartlingFileData > GetSubData ( SmartlingFileData dtmCultureData , Dictionary < string , List < HashSet < Row > > > tabelRowChunks )
205+ {
206+ // Find the entry with the largest number of HashSet<Row> in its value list
207+ var maxEntry = tabelRowChunks
208+ . OrderByDescending ( kvp => kvp . Value ? . Count ?? 0 )
209+ . FirstOrDefault ( ) ;
210+
211+ //we need to know how many files we will need to create for each table
212+ int totalFilesNeeded = maxEntry . Value ? . Count ?? 0 ;
213+
214+ Dictionary < string , SmartlingFileData > subData = new Dictionary < string , SmartlingFileData > ( ) ;
215+
216+ int fileCount = 0 ;
217+
218+ while ( fileCount < totalFilesNeeded )
219+ {
220+ SmartlingFileData subDataFile = new SmartlingFileData ( ) ;
221+ subDataFile . Tables = new List < Table > ( ) ;
222+ subDataFile . smartling = dtmCultureData . smartling ;
223+ subDataFile . GlobalizationMetaData = dtmCultureData . GlobalizationMetaData ;
224+ string fileName = $ "{ dtmCultureData . GlobalizationMetaData . PackageId } _{ fileCount } ";
225+
226+ foreach ( Table table in dtmCultureData . Tables )
227+ {
228+ var rowSet = tabelRowChunks . FirstOrDefault ( l => l . Key == table . FullBaseTableName ) . Value [ fileCount ] ;
229+ if ( rowSet != null && rowSet . Count > fileCount )
230+ {
231+ // Create a new table object for each chunk
232+ Table newTable = new Table ( )
233+ {
234+ Rows = rowSet ,
235+ FullBaseTableName = table . FullBaseTableName ,
236+ LocalizedTable = table . LocalizedTable ,
237+ PrimaryKeyName = table . PrimaryKeyName ,
238+ SystemColumns = table . SystemColumns ,
239+ SourceLanguageColumns = table . SourceLanguageColumns ,
240+ TranslatedLanguageColumns = table . TranslatedLanguageColumns
241+ } ;
242+ subDataFile . Tables . Add ( newTable ) ;
243+ }
244+ }
245+ subData . Add ( fileName , subDataFile ) ;
246+ fileCount ++ ;
247+ }
248+
249+ return subData ;
250+ }
251+
252+ private static List < HashSet < T > > SplitRowList < T > ( HashSet < T > list , int chunkSize )
253+ {
254+ var chunks = new List < HashSet < T > > ( ) ;
255+ if ( list == null || chunkSize <= 0 )
256+ return chunks ;
257+
258+ var array = list . ToArray ( ) ;
259+ for ( int i = 0 ; i < array . Length ; i += chunkSize )
260+ {
261+ var chunk = array . Skip ( i ) . Take ( chunkSize ) ;
262+ chunks . Add ( new HashSet < T > ( chunk ) ) ;
263+ }
264+ return chunks ;
265+ }
215266 }
216267}
0 commit comments