diff --git a/lib/features/main_screen/main_screen_workspace_state.dart b/lib/features/main_screen/main_screen_workspace_state.dart index f34bc65..f3c3532 100644 --- a/lib/features/main_screen/main_screen_workspace_state.dart +++ b/lib/features/main_screen/main_screen_workspace_state.dart @@ -176,40 +176,52 @@ class MainScreenWorkspaceState { MainScreenWorkspaceState restoreLastSelectedObject() { final conn = activeConnection; if (conn == null) return this; - if (lastSelectedPostgresObject != null) { - final obj = lastSelectedPostgresObject!; - return selectPostgresObject( - conn, - obj.database, - obj.schema, - obj.name, - obj.kind, - ); - } - if (lastSelectedMysqlObject != null) { - final obj = lastSelectedMysqlObject!; - return selectMysqlObject( - conn, - obj.database, - obj.name, - obj.kind, - ); - } - if (lastSelectedSqliteObject != null) { - final obj = lastSelectedSqliteObject!; - return selectSqliteObject( - conn, - obj.name, - obj.kind, - ); - } - if (lastSelectedExtensionObject != null) { - final obj = lastSelectedExtensionObject!; - return selectExtensionObject( - conn, - obj.database, - obj.name, - ); + final type = conn.type.toLowerCase(); + switch (type) { + case 'postgres': + case 'postgresql': + if (lastSelectedPostgresObject != null) { + final obj = lastSelectedPostgresObject!; + return selectPostgresObject( + conn, + obj.database, + obj.schema, + obj.name, + obj.kind, + ); + } + break; + case 'mysql': + if (lastSelectedMysqlObject != null) { + final obj = lastSelectedMysqlObject!; + return selectMysqlObject( + conn, + obj.database, + obj.name, + obj.kind, + ); + } + break; + case 'sqlite': + if (lastSelectedSqliteObject != null) { + final obj = lastSelectedSqliteObject!; + return selectSqliteObject( + conn, + obj.name, + obj.kind, + ); + } + break; + default: + if (lastSelectedExtensionObject != null) { + final obj = lastSelectedExtensionObject!; + return selectExtensionObject( + conn, + obj.database, + obj.name, + ); + } + break; } return this; } @@ -240,9 +252,9 @@ class MainScreenWorkspaceState { selectedSqliteObject: null, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, lastSelectedPostgresObject: pg, - lastSelectedMysqlObject: lastSelectedMysqlObject, - lastSelectedSqliteObject: lastSelectedSqliteObject, - lastSelectedExtensionObject: lastSelectedExtensionObject, + lastSelectedMysqlObject: null, + lastSelectedSqliteObject: null, + lastSelectedExtensionObject: null, isReadOnly: isReadOnly, ); } @@ -270,10 +282,10 @@ class MainScreenWorkspaceState { mysqlSqlTabRequestToken: mysqlSqlTabRequestToken, selectedSqliteObject: null, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, - lastSelectedPostgresObject: lastSelectedPostgresObject, + lastSelectedPostgresObject: null, lastSelectedMysqlObject: my, - lastSelectedSqliteObject: lastSelectedSqliteObject, - lastSelectedExtensionObject: lastSelectedExtensionObject, + lastSelectedSqliteObject: null, + lastSelectedExtensionObject: null, isReadOnly: isReadOnly, ); } @@ -299,10 +311,10 @@ class MainScreenWorkspaceState { mysqlSqlTabRequestToken: mysqlSqlTabRequestToken, selectedSqliteObject: sq, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, - lastSelectedPostgresObject: lastSelectedPostgresObject, - lastSelectedMysqlObject: lastSelectedMysqlObject, + lastSelectedPostgresObject: null, + lastSelectedMysqlObject: null, lastSelectedSqliteObject: sq, - lastSelectedExtensionObject: lastSelectedExtensionObject, + lastSelectedExtensionObject: null, isReadOnly: isReadOnly, ); } @@ -329,9 +341,9 @@ class MainScreenWorkspaceState { selectedSqliteObject: null, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, selectedExtensionObject: ext, - lastSelectedPostgresObject: lastSelectedPostgresObject, - lastSelectedMysqlObject: lastSelectedMysqlObject, - lastSelectedSqliteObject: lastSelectedSqliteObject, + lastSelectedPostgresObject: null, + lastSelectedMysqlObject: null, + lastSelectedSqliteObject: null, lastSelectedExtensionObject: ext, isReadOnly: isReadOnly, ); @@ -350,10 +362,10 @@ class MainScreenWorkspaceState { mysqlSqlTabRequestToken: mysqlSqlTabRequestToken, selectedSqliteObject: null, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, - lastSelectedPostgresObject: lastSelectedPostgresObject, - lastSelectedMysqlObject: lastSelectedMysqlObject, - lastSelectedSqliteObject: lastSelectedSqliteObject, - lastSelectedExtensionObject: lastSelectedExtensionObject, + lastSelectedPostgresObject: null, + lastSelectedMysqlObject: null, + lastSelectedSqliteObject: null, + lastSelectedExtensionObject: null, isReadOnly: isReadOnly, ); } @@ -372,10 +384,10 @@ class MainScreenWorkspaceState { mysqlSqlTabRequestToken: mysqlSqlTabRequestToken, selectedSqliteObject: null, sqliteSqlTabRequestToken: sqliteSqlTabRequestToken, - lastSelectedPostgresObject: lastSelectedPostgresObject, - lastSelectedMysqlObject: lastSelectedMysqlObject, - lastSelectedSqliteObject: lastSelectedSqliteObject, - lastSelectedExtensionObject: lastSelectedExtensionObject, + lastSelectedPostgresObject: null, + lastSelectedMysqlObject: null, + lastSelectedSqliteObject: null, + lastSelectedExtensionObject: null, isReadOnly: isReadOnly, ); } diff --git a/test/features/main_screen/main_screen_workspace_state_test.dart b/test/features/main_screen/main_screen_workspace_state_test.dart index dd33190..f780b58 100644 --- a/test/features/main_screen/main_screen_workspace_state_test.dart +++ b/test/features/main_screen/main_screen_workspace_state_test.dart @@ -1,5 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:querya_desktop/core/storage/local_db.dart'; +import 'package:querya_desktop/features/connections/connections_panel.dart' + show SqliteObjectKind; import 'package:querya_desktop/features/main_screen/main_screen_workspace_state.dart'; import 'package:querya_desktop/features/mysql/mysql_object_kind.dart'; import 'package:querya_desktop/features/postgresql/postgres_object_kind.dart'; @@ -22,6 +24,21 @@ void main() { createdAt: createdAt, id: 11, ); + final sqliteConn = ConnectionRow( + type: 'sqlite', + name: 'lite', + databaseName: '/tmp/test.db', + createdAt: createdAt, + id: 12, + ); + final clickhouseConn = ConnectionRow( + type: 'clickhouse', + name: 'ch', + host: '127.0.0.1', + port: 8123, + createdAt: createdAt, + id: 13, + ); group('MainScreenWorkspaceState', () { test('empty has no selection', () { @@ -214,5 +231,103 @@ void main() { final diffConn = reselectedSame.selectConnection(mysqlConn); expect(diffConn.lastSelectedPostgresObject, isNull); }); + + test('restoreLastSelectedObject is connection-type-aware', () { + // 1. MySQL connection + final mysqlState = MainScreenWorkspaceState.empty + .selectMysqlObject(mysqlConn, 'app_db', 'users', MysqlObjectKind.table) + .unselectActiveObject(); + expect(mysqlState.selectedMysqlObject, isNull); + expect(mysqlState.lastSelectedMysqlObject?.name, 'users'); + final restoredMy = mysqlState.restoreLastSelectedObject(); + expect(restoredMy.selectedMysqlObject?.name, 'users'); + expect(restoredMy.selectedPostgresObject, isNull); + + // 2. SQLite connection + final sqliteState = MainScreenWorkspaceState.empty + .selectSqliteObject(sqliteConn, 'settings', SqliteObjectKind.table) + .unselectActiveObject(); + expect(sqliteState.selectedSqliteObject, isNull); + expect(sqliteState.lastSelectedSqliteObject?.name, 'settings'); + final restoredSq = sqliteState.restoreLastSelectedObject(); + expect(restoredSq.selectedSqliteObject?.name, 'settings'); + + // 3. Extension (ClickHouse) connection + final extState = MainScreenWorkspaceState.empty + .selectExtensionObject(clickhouseConn, 'analytics', 'hits') + .unselectActiveObject(); + expect(extState.selectedExtensionObject, isNull); + expect(extState.lastSelectedExtensionObject?.name, 'hits'); + final restoredExt = extState.restoreLastSelectedObject(); + expect(restoredExt.selectedExtensionObject?.name, 'hits'); + }); + + test('restoreLastSelectedObject ignores cached references from other drivers', () { + // Craft a state where active connection is MySQL but lastSelectedPostgresObject is non-null + const mismatchedState = MainScreenWorkspaceState( + activeConnection: ConnectionRow( + type: 'mysql', + name: 'my_db', + createdAt: '2025-01-01', + id: 50, + ), + lastSelectedPostgresObject: ( + database: 'pg_db', + schema: 'public', + name: 'pg_table', + kind: PostgresObjectKind.table, + ), + ); + + final restored = mismatchedState.restoreLastSelectedObject(); + // Must NOT invoke selectPostgresObject with a MySQL connection + expect(restored.selectedPostgresObject, isNull); + expect(restored.selectedMysqlObject, isNull); + }); + + test('select*Object clears cached object references of other drivers', () { + final statePg = MainScreenWorkspaceState.empty.selectPostgresObject( + pgConn, + 'db', + 'public', + 't1', + PostgresObjectKind.table, + ); + expect(statePg.lastSelectedPostgresObject?.name, 't1'); + expect(statePg.lastSelectedMysqlObject, isNull); + expect(statePg.lastSelectedSqliteObject, isNull); + expect(statePg.lastSelectedExtensionObject, isNull); + + final stateMy = statePg.selectMysqlObject( + mysqlConn, + 'db', + 't2', + MysqlObjectKind.table, + ); + expect(stateMy.lastSelectedPostgresObject, isNull); + expect(stateMy.lastSelectedMysqlObject?.name, 't2'); + expect(stateMy.lastSelectedSqliteObject, isNull); + expect(stateMy.lastSelectedExtensionObject, isNull); + + final stateSq = stateMy.selectSqliteObject( + sqliteConn, + 't3', + SqliteObjectKind.table, + ); + expect(stateSq.lastSelectedPostgresObject, isNull); + expect(stateSq.lastSelectedMysqlObject, isNull); + expect(stateSq.lastSelectedSqliteObject?.name, 't3'); + expect(stateSq.lastSelectedExtensionObject, isNull); + + final stateExt = stateSq.selectExtensionObject( + clickhouseConn, + 'db', + 't4', + ); + expect(stateExt.lastSelectedPostgresObject, isNull); + expect(stateExt.lastSelectedMysqlObject, isNull); + expect(stateExt.lastSelectedSqliteObject, isNull); + expect(stateExt.lastSelectedExtensionObject?.name, 't4'); + }); }); }