@@ -125,6 +125,30 @@ def _get_history_store(self: QueryMixinHost) -> Any:
125125 return store
126126 return self .services .history_store
127127
128+ def _get_unsaved_history_store (self : QueryMixinHost ) -> Any :
129+ store = getattr (self , "_unsaved_history_store" , None )
130+ if store is None :
131+ from sqlit .domains .query .store .memory import InMemoryHistoryStore
132+
133+ store = InMemoryHistoryStore ()
134+ self ._unsaved_history_store = store
135+ return store
136+
137+ def _should_save_query_history (self : QueryMixinHost , config : Any ) -> bool :
138+ """Return True if the connection is saved and history should be persisted."""
139+ name = getattr (config , "name" , "" )
140+ if not name :
141+ return False
142+ connections = getattr (self , "connections" , None ) or []
143+ return any (getattr (conn , "name" , None ) == name for conn in connections )
144+
145+ def _save_query_history (self : QueryMixinHost , config : Any , query : str ) -> None :
146+ """Save query history only for saved connections."""
147+ if self ._should_save_query_history (config ):
148+ self ._get_history_store ().save_query (config .name , query )
149+ return
150+ self ._get_unsaved_history_store ().save_query (config .name , query )
151+
128152 def _get_query_service (self : QueryMixinHost , provider : Any ) -> QueryService :
129153 if self ._query_service is None or (
130154 self ._query_service_db_type is not None
@@ -262,8 +286,6 @@ async def _run_query_async(self: QueryMixinHost, query: str, keep_insert_mode: b
262286
263287 # Use TransactionExecutor for transaction-aware query execution
264288 executor = self ._get_transaction_executor (config , provider )
265- service = self ._get_query_service (provider )
266-
267289 # Check if this is a multi-statement query
268290 statements = split_statements (query )
269291 is_multi_statement = len (statements ) > 1
@@ -305,7 +327,7 @@ async def _run_query_async(self: QueryMixinHost, query: str, keep_insert_mode: b
305327 return
306328
307329 try :
308- await asyncio .to_thread (service . _save_to_history , config . name , query )
330+ await asyncio .to_thread (self . _save_query_history , config , query )
309331 except Exception :
310332 pass
311333 result = outcome .result
@@ -336,7 +358,7 @@ async def _run_query_async(self: QueryMixinHost, query: str, keep_insert_mode: b
336358 elapsed_ms = (time .perf_counter () - start_time ) * 1000
337359
338360 try :
339- await asyncio .to_thread (service . _save_to_history , config . name , query )
361+ await asyncio .to_thread (self . _save_query_history , config , query )
340362 except Exception :
341363 pass
342364 self ._display_multi_statement_results (multi_result , elapsed_ms )
@@ -350,7 +372,7 @@ async def _run_query_async(self: QueryMixinHost, query: str, keep_insert_mode: b
350372 elapsed_ms = (time .perf_counter () - start_time ) * 1000
351373
352374 try :
353- await asyncio .to_thread (service . _save_to_history , config . name , query )
375+ await asyncio .to_thread (self . _save_query_history , config , query )
354376 except Exception :
355377 pass
356378
@@ -401,8 +423,6 @@ async def _run_query_atomic_async(self: QueryMixinHost, query: str) -> None:
401423
402424 # Create a dedicated executor for atomic execution
403425 executor = TransactionExecutor (config = config , provider = provider )
404- service = self ._get_query_service (provider )
405-
406426 try :
407427 start_time = time .perf_counter ()
408428 max_rows = self .services .runtime .max_rows or MAX_FETCH_ROWS
@@ -414,7 +434,7 @@ async def _run_query_atomic_async(self: QueryMixinHost, query: str) -> None:
414434 elapsed_ms = (time .perf_counter () - start_time ) * 1000
415435
416436 try :
417- await asyncio .to_thread (service . _save_to_history , config . name , query )
437+ await asyncio .to_thread (self . _save_query_history , config , query )
418438 except Exception :
419439 pass
420440
@@ -551,9 +571,11 @@ def action_show_history(self: QueryMixinHost) -> None:
551571
552572 from ..screens import QueryHistoryScreen
553573
554- history_store = self ._get_history_store ()
555574 starred_store = self .services .starred_store
556- history = history_store .load_for_connection (self .current_config .name )
575+ if self ._should_save_query_history (self .current_config ):
576+ history = self ._get_history_store ().load_for_connection (self .current_config .name )
577+ else :
578+ history = self ._get_unsaved_history_store ().load_for_connection (self .current_config .name )
557579 starred = starred_store .load_for_connection (self .current_config .name )
558580 self .push_screen (
559581 QueryHistoryScreen (history , self .current_config .name , starred ),
@@ -587,16 +609,28 @@ def _show_telescope(self: QueryMixinHost, *, auto_open_filter: bool) -> None:
587609 """Open telescope with optional filter preset."""
588610 from ..screens import QueryHistoryScreen
589611
612+ connection_map = self ._get_telescope_connection_map ()
613+ available_connections = set (connection_map .keys ())
614+
590615 history_store = self ._get_history_store ()
591616 if hasattr (history_store , "load_all" ):
592617 history = history_store .load_all ()
593618 else :
594619 history = []
595- for config in self . _get_telescope_connection_map () .values ():
620+ for config in connection_map .values ():
596621 history .extend (history_store .load_for_connection (config .name ))
597622 history .sort (key = lambda entry : entry .timestamp , reverse = True )
598623
599- connection_map = self ._get_telescope_connection_map ()
624+ unsaved_store = getattr (self , "_unsaved_history_store" , None )
625+ if unsaved_store is not None and hasattr (unsaved_store , "load_all" ):
626+ history .extend (unsaved_store .load_all ())
627+
628+ if available_connections :
629+ history = [
630+ entry for entry in history
631+ if getattr (entry , "connection_name" , None ) in available_connections
632+ ]
633+ history .sort (key = lambda entry : entry .timestamp , reverse = True )
600634 connection_labels = {
601635 name : self ._format_telescope_connection_label (config )
602636 for name , config in connection_map .items ()
0 commit comments