@@ -65,33 +65,78 @@ public static string EscapeString(string str)
6565 }
6666
6767 /// <summary>
68- /// Replaces the last comma with semicolon in StringBuilder
68+ /// Replaces the last comma with a custom suffix in StringBuilder.
69+ /// Walks backward until it finds the last non-comment line.
6970 /// </summary>
70- /// <param name="str"></param>
71- /// <returns></returns>
72- public static void ReplaceLastCommaWithSemicolon ( this StringBuilder str )
71+ public static void ReplaceLastComma ( this StringBuilder str , string replacement )
7372 {
74- bool isComment = false ;
75- int lastCommaPos = - 1 ;
76- for ( var i = str . Length - 1 ; i > 0 ; i -- )
73+ for ( var lineEnd = str . Length - 1 ; lineEnd >= 0 ; )
7774 {
78- if ( i >= 3 && str [ i - 3 ] == ',' && str [ i - 2 ] == ' ' && str [ i - 1 ] == '-' && str [ i ] == '-' )
75+ while ( lineEnd >= 0 && ( str [ lineEnd ] == '\r ' || str [ lineEnd ] == '\n ' ) )
76+ -- lineEnd ;
77+
78+ if ( lineEnd < 0 )
79+ return ;
80+
81+ var lineStart = lineEnd ;
82+ while ( lineStart > 0 && str [ lineStart - 1 ] != '\r ' && str [ lineStart - 1 ] != '\n ' )
83+ -- lineStart ;
84+
85+ var contentStart = lineStart ;
86+ while ( contentStart <= lineEnd && char . IsWhiteSpace ( str [ contentStart ] ) )
87+ ++ contentStart ;
88+
89+ if ( contentStart > lineEnd )
7990 {
80- str [ i - 3 ] = ';' ;
81- isComment = true ;
82- break ;
91+ lineEnd = lineStart - 1 ;
92+ continue ;
93+ }
94+
95+ if ( contentStart + 1 <= lineEnd && str [ contentStart ] == '-' && str [ contentStart + 1 ] == '-' )
96+ {
97+ lineEnd = lineStart - 1 ;
98+ continue ;
99+ }
100+
101+ var commentStart = - 1 ;
102+ for ( var i = contentStart ; i < lineEnd ; ++ i )
103+ {
104+ if ( str [ i ] == '-' && str [ i + 1 ] == '-' )
105+ {
106+ commentStart = i ;
107+ break ;
108+ }
83109 }
84110
85- if ( lastCommaPos == - 1 && str [ i ] == ',' )
86- lastCommaPos = i ;
111+ var contentEnd = commentStart == - 1 ? lineEnd : commentStart - 1 ;
112+ while ( contentEnd >= contentStart && char . IsWhiteSpace ( str [ contentEnd ] ) )
113+ -- contentEnd ;
114+
115+ for ( var i = contentEnd ; i >= contentStart ; -- i )
116+ {
117+ if ( str [ i ] == ';' )
118+ return ;
119+
120+ if ( str [ i ] == ',' )
121+ {
122+ str . Remove ( i , 1 ) ;
123+ str . Insert ( i , replacement ) ;
124+ return ;
125+ }
126+ }
87127
88- // only interact with last line, skip trailing newline
89- if ( ( str [ i ] == '\n ' || str [ i ] == '\r ' ) && i < str . Length - 3 )
90- break ;
128+ lineEnd = lineStart - 1 ;
91129 }
130+ }
92131
93- if ( ! isComment && lastCommaPos != - 1 )
94- str [ lastCommaPos ] = ';' ;
132+ /// <summary>
133+ /// Replaces the last comma with semicolon in StringBuilder
134+ /// </summary>
135+ /// <param name="str"></param>
136+ /// <returns></returns>
137+ public static void ReplaceLastCommaWithSemicolon ( this StringBuilder str )
138+ {
139+ str . ReplaceLastComma ( ";" ) ;
95140 }
96141
97142 /// <summary>
@@ -208,14 +253,15 @@ public static bool IsHotfixTable<T>() where T : IDataModel
208253 /// <param name="storeList"><see cref="DataBag{T}"/> with items form sniff.</param>
209254 /// <param name="dbList"><see cref="DataBag{T}"/> with items from database.</param>
210255 /// <param name="storeType">Are we dealing with Spells, Quests, Units, ...?</param>
211- public static string Compare < T > ( IEnumerable < Tuple < T , TimeSpan ? > > storeList , RowList < T > dbList , StoreNameType storeType )
256+ public static string Compare < T > ( IEnumerable < Tuple < T , TimeSpan ? > > storeList , RowList < T > dbList , StoreNameType storeType , bool useOnDuplicateKeyUpdateForInserts = false )
212257 where T : IDataModel , new ( )
213258 {
214259 var primaryKey = GetFirstPrimaryKey < T > ( ) ;
215260 return Compare ( storeList , dbList ,
216261 t => storeType != StoreNameType . None
217262 ? StoreGetters . GetName ( storeType , Convert . ToInt32 ( primaryKey . GetValue ( t ) ) , false )
218- : "" ) ;
263+ : "" ,
264+ useOnDuplicateKeyUpdateForInserts ) ;
219265 }
220266
221267 /// <summary>
@@ -229,7 +275,7 @@ public static string Compare<T>(IEnumerable<Tuple<T, TimeSpan?>> storeList, RowL
229275 /// <param name="dbList">Dictionary retrieved from DB</param>
230276 /// <param name="commentSetter"></param>
231277 /// <returns>A string containing full SQL queries</returns>
232- public static string Compare < T > ( IEnumerable < Tuple < T , TimeSpan ? > > storeList , RowList < T > dbList , Func < T , string > commentSetter )
278+ public static string Compare < T > ( IEnumerable < Tuple < T , TimeSpan ? > > storeList , RowList < T > dbList , Func < T , string > commentSetter , bool useOnDuplicateKeyUpdateForInserts = false )
233279 where T : IDataModel , new ( )
234280 {
235281 if ( ! IsTableVisible < T > ( ) )
@@ -334,7 +380,7 @@ public static string Compare<T>(IEnumerable<Tuple<T, TimeSpan?>> storeList, RowL
334380 }
335381 }
336382
337- return new SQLInsert < T > ( rowsIns ) . Build ( ) + Environment . NewLine +
383+ return new SQLInsert < T > ( rowsIns , withDelete : ! useOnDuplicateKeyUpdateForInserts , onDuplicateKeyUpdate : useOnDuplicateKeyUpdateForInserts ) . Build ( ) + Environment . NewLine +
338384 new SQLUpdate < T > ( rowsUpd ) . Build ( ) ;
339385 }
340386
0 commit comments