@@ -125,6 +125,7 @@ final class DataChangeManager: ObservableObject {
125125 deletedRowIndices. removeAll ( )
126126 insertedRowIndices. removeAll ( )
127127 modifiedCells. removeAll ( )
128+ insertedRowData. removeAll ( ) // Clear lazy storage
128129 undoStack. removeAll ( ) // Clear undo stack too
129130 hasChanges = false
130131 reloadVersion += 1 // Trigger table reload
@@ -147,6 +148,7 @@ final class DataChangeManager: ObservableObject {
147148 deletedRowIndices. removeAll ( )
148149 insertedRowIndices. removeAll ( )
149150 modifiedCells. removeAll ( )
151+ insertedRowData. removeAll ( ) // Clear lazy storage
150152
151153 // Now update @Published properties - triggers ONE view update
152154 changes. removeAll ( )
@@ -197,7 +199,16 @@ final class DataChangeManager: ObservableObject {
197199 if let insertIndex = changes. firstIndex ( where: {
198200 $0. rowIndex == rowIndex && $0. type == . insert
199201 } ) {
200- // Update or add cell change in the INSERT record
202+ // OPTIMIZATION: Update the stored values directly first
203+ if var storedValues = insertedRowData [ rowIndex] {
204+ if columnIndex < storedValues. count {
205+ storedValues [ columnIndex] = newValue
206+ insertedRowData [ rowIndex] = storedValues
207+ }
208+ }
209+
210+ // Also update/create CellChange for this specific column
211+ // (Lazy build - only for edited columns, not all columns)
201212 if let cellIndex = changes [ insertIndex] . cellChanges. firstIndex ( where: {
202213 $0. columnIndex == columnIndex
203214 } ) {
@@ -210,7 +221,7 @@ final class DataChangeManager: ObservableObject {
210221 newValue: newValue
211222 )
212223 } else {
213- // Add new cell to INSERT
224+ // Add new cell to INSERT (lazy - only for this edited column)
214225 changes [ insertIndex] . cellChanges. append ( CellChange (
215226 rowIndex: rowIndex,
216227 columnIndex: columnIndex,
@@ -319,15 +330,16 @@ final class DataChangeManager: ObservableObject {
319330 }
320331
321332 func recordRowInsertion( rowIndex: Int , values: [ String ? ] ) {
322- let cellChanges = values. enumerated ( ) . map { index, value in
323- CellChange (
324- rowIndex: rowIndex, columnIndex: index, columnName: columns [ safe: index] ?? " " ,
325- oldValue: nil , newValue: value)
326- }
327- let rowChange = RowChange ( rowIndex: rowIndex, type: . insert, cellChanges: cellChanges)
333+ // OPTIMIZATION: Store row data directly without creating CellChange objects
334+ // This eliminates expensive enumerated().map() for every column
335+ // CellChanges will be built lazily only when needed (SQL generation or cell edits)
336+ insertedRowData [ rowIndex] = values
337+
338+ // Lightweight RowChange marker with empty cellChanges array
339+ let rowChange = RowChange ( rowIndex: rowIndex, type: . insert, cellChanges: [ ] )
328340 changes. append ( rowChange)
329- insertedRowIndices. insert ( rowIndex) // Add to cache
330- pushUndo ( . rowInsertion( rowIndex: rowIndex) ) // Push undo action
341+ insertedRowIndices. insert ( rowIndex)
342+ pushUndo ( . rowInsertion( rowIndex: rowIndex) )
331343 hasChanges = true
332344 }
333345
@@ -356,6 +368,7 @@ final class DataChangeManager: ObservableObject {
356368 // Remove the INSERT change from the changes array
357369 changes. removeAll { $0. rowIndex == rowIndex && $0. type == . insert }
358370 insertedRowIndices. remove ( rowIndex)
371+ insertedRowData. removeValue ( forKey: rowIndex) // Clear lazy storage
359372
360373 // Shift down indices for rows after the removed row
361374 var shiftedInsertedIndices = Set < Int > ( )
@@ -410,6 +423,7 @@ final class DataChangeManager: ObservableObject {
410423 for rowIndex in validRows {
411424 changes. removeAll { $0. rowIndex == rowIndex && $0. type == . insert }
412425 insertedRowIndices. remove ( rowIndex)
426+ insertedRowData. removeValue ( forKey: rowIndex) // Clear lazy storage
413427 }
414428
415429 // Push undo action so user can undo this deletion
@@ -753,6 +767,52 @@ final class DataChangeManager: ObservableObject {
753767 }
754768
755769 private func generateInsertSQL( for change: RowChange ) -> String ? {
770+ // OPTIMIZATION: Get values from lazy storage instead of cellChanges
771+ if let values = insertedRowData [ change. rowIndex] {
772+ return generateInsertSQLFromStoredData ( rowIndex: change. rowIndex, values: values)
773+ }
774+
775+ // Fallback: use cellChanges if stored data not available (backward compatibility)
776+ return generateInsertSQLFromCellChanges ( for: change)
777+ }
778+
779+ /// Generate INSERT SQL from lazy-stored row data (new optimized path)
780+ private func generateInsertSQLFromStoredData( rowIndex: Int , values: [ String ? ] ) -> String ? {
781+ var nonDefaultColumns : [ String ] = [ ]
782+ var nonDefaultValues : [ String ] = [ ]
783+
784+ for (index, value) in values. enumerated ( ) {
785+ // Skip DEFAULT columns - let DB handle them
786+ if value == " __DEFAULT__ " { continue }
787+
788+ guard index < columns. count else { continue }
789+ let columnName = columns [ index]
790+
791+ nonDefaultColumns. append ( databaseType. quoteIdentifier ( columnName) )
792+
793+ if let val = value {
794+ // Check if it's a SQL function expression
795+ if isSQLFunctionExpression ( val) {
796+ nonDefaultValues. append ( val. trimmingCharacters ( in: . whitespaces) . uppercased ( ) )
797+ } else {
798+ nonDefaultValues. append ( " ' \( escapeSQLString ( val) ) ' " )
799+ }
800+ } else {
801+ nonDefaultValues. append ( " NULL " )
802+ }
803+ }
804+
805+ // If all columns are DEFAULT, don't generate INSERT
806+ guard !nonDefaultColumns. isEmpty else { return nil }
807+
808+ let columnList = nonDefaultColumns. joined ( separator: " , " )
809+ let valueList = nonDefaultValues. joined ( separator: " , " )
810+
811+ return " INSERT INTO \( databaseType. quoteIdentifier ( tableName) ) ( \( columnList) ) VALUES ( \( valueList) ) "
812+ }
813+
814+ /// Generate INSERT SQL from cellChanges (fallback for backward compatibility)
815+ private func generateInsertSQLFromCellChanges( for change: RowChange ) -> String ? {
756816 guard !change. cellChanges. isEmpty else { return nil }
757817
758818 // Filter out DEFAULT columns - let DB handle them
@@ -837,6 +897,7 @@ final class DataChangeManager: ObservableObject {
837897 deletedRowIndices. removeAll ( ) // Clear cache
838898 insertedRowIndices. removeAll ( ) // Clear cache
839899 modifiedCells. removeAll ( ) // Clear cache
900+ insertedRowData. removeAll ( ) // Clear lazy storage
840901 hasChanges = false
841902 reloadVersion += 1 // Trigger table reload
842903 }
@@ -850,6 +911,7 @@ final class DataChangeManager: ObservableObject {
850911 state. deletedRowIndices = deletedRowIndices
851912 state. insertedRowIndices = insertedRowIndices
852913 state. modifiedCells = modifiedCells
914+ state. insertedRowData = insertedRowData // Save lazy storage
853915 state. primaryKeyColumn = primaryKeyColumn
854916 state. columns = columns
855917 return state
@@ -862,6 +924,7 @@ final class DataChangeManager: ObservableObject {
862924 self . deletedRowIndices = state. deletedRowIndices
863925 self . insertedRowIndices = state. insertedRowIndices
864926 self . modifiedCells = state. modifiedCells
927+ self . insertedRowData = state. insertedRowData // Restore lazy storage
865928 self . primaryKeyColumn = state. primaryKeyColumn
866929 self . columns = state. columns
867930 self . hasChanges = !state. changes. isEmpty
0 commit comments