@@ -10,13 +10,16 @@ import 'package:postgres/postgres.dart' as pg;
1010import 'package:querya_desktop/core/database/postgres_service.dart' ;
1111import 'package:querya_desktop/core/database/postgres_sql.dart' ;
1212import 'package:querya_desktop/core/database/result_row_string_convert.dart' ;
13+ import 'package:querya_desktop/core/database/sql_table_target_extractor.dart' ;
14+ import 'package:querya_desktop/core/database/table_mutation_engine.dart' ;
1315import 'package:querya_desktop/core/layout/vertical_split_pane.dart' ;
1416import 'package:querya_desktop/core/storage/app_settings.dart' ;
1517import 'package:querya_desktop/core/storage/local_db.dart' ;
1618import 'package:querya_desktop/features/postgresql/postgres_object_kind.dart' ;
1719import 'package:querya_desktop/features/postgresql/postgres_table_utils.dart' ;
1820import 'package:querya_desktop/features/settings/preferences_dialog.dart' ;
1921import 'package:querya_desktop/features/settings/sql_statement_timeout_dropdown.dart' ;
22+ import 'package:querya_desktop/features/main_screen/data_grid_staging_buffer.dart' ;
2023import 'package:querya_desktop/features/main_screen/query_editor_tab.dart' ;
2124import 'package:querya_desktop/features/main_screen/results_tab.dart' ;
2225import 'package:querya_desktop/features/main_screen/sql_editor_chrome.dart' ;
@@ -80,6 +83,9 @@ class _PostgresSqlWorkspaceState extends material.State<PostgresSqlWorkspace> {
8083 List <List <String >> _rows = [];
8184 int ? _affectedRows;
8285 String ? _statusLine;
86+ DataGridStagingBuffer ? _stagingBuffer;
87+ String ? _lastExecutedSql;
88+ bool _savingChanges = false ;
8389
8490 /// PostgreSQL default: each statement is its own transaction unless you use
8591 /// `BEGIN` / `BEGIN` +implicit when autocommit is off.
@@ -367,6 +373,10 @@ class _PostgresSqlWorkspaceState extends material.State<PostgresSqlWorkspace> {
367373 _columns = cols;
368374 _rows = outRows;
369375 _affectedRows = result.affectedRows;
376+ _lastExecutedSql = userSql;
377+ _stagingBuffer = cols.isNotEmpty
378+ ? DataGridStagingBuffer (columns: cols, rows: outRows)
379+ : null ;
370380 if (cols.isEmpty && outRows.isEmpty) {
371381 _statusLine =
372382 'Command completed. Rows affected: ${result .affectedRows }.' ;
@@ -416,6 +426,61 @@ class _PostgresSqlWorkspaceState extends material.State<PostgresSqlWorkspace> {
416426 }
417427 }
418428
429+ Future <void > _applyStagedChanges () async {
430+ if (_stagingBuffer == null || ! _stagingBuffer! .isDirty || _savingChanges) return ;
431+ final target = _lastExecutedSql != null ? SqlTableTargetExtractor .extract (_lastExecutedSql! ) : null ;
432+ final tableName = target? .tableName ?? 'table' ;
433+ final schemaName = target? .schema;
434+
435+ setState (() => _savingChanges = true );
436+ try {
437+ final plan = _stagingBuffer! .generateMutationPlan (
438+ dialect: SqlDialect .postgres,
439+ tableName: tableName,
440+ schema: schemaName,
441+ );
442+ if (plan.isEmpty) {
443+ setState (() => _savingChanges = false );
444+ return ;
445+ }
446+
447+ await _ensureLease ();
448+ final conn = _lease? .connection;
449+ if (conn == null || ! conn.isConnected) {
450+ throw StateError ('Could not connect to PostgreSQL.' );
451+ }
452+
453+ final txSql = plan.toTransactionSql ();
454+ final to = _statementTimeout ();
455+ await conn.execute (txSql, timeout: to);
456+
457+ if (! mounted) return ;
458+ setState (() {
459+ _rows = _stagingBuffer! .effectiveRows;
460+ _stagingBuffer = DataGridStagingBuffer (columns: _columns, rows: _rows);
461+ _savingChanges = false ;
462+ });
463+ await _refreshTxStatus ();
464+ } catch (e) {
465+ if (mounted) {
466+ setState (() => _savingChanges = false );
467+ await showAppDialog <void >(
468+ context: context,
469+ builder: (ctx) => material.AlertDialog (
470+ title: const material.Text ('Save Changes Failed' ),
471+ content: material.Text (e.toString ()),
472+ actions: [
473+ material.TextButton (
474+ onPressed: () => material.Navigator .of (ctx).pop (),
475+ child: const material.Text ('OK' ),
476+ ),
477+ ],
478+ ),
479+ );
480+ }
481+ }
482+ }
483+
419484 Future <void > _openSqlFile () async {
420485 try {
421486 final file = await openFile (
@@ -597,6 +662,9 @@ class _PostgresSqlWorkspaceState extends material.State<PostgresSqlWorkspace> {
597662 isLoading: _running,
598663 affectedRows: _affectedRows,
599664 statusLine: _statusLine,
665+ stagingBuffer: _stagingBuffer,
666+ onApplyChanges: widget.isReadOnly ? null : _applyStagedChanges,
667+ isSaving: _savingChanges,
600668 ),
601669 ),
602670 ],
0 commit comments