vector-inspector 0.3.6__py3-none-any.whl → 0.3.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,177 @@
1
+ """Controller for managing connection lifecycle and threading."""
2
+
3
+ from typing import Dict, Optional
4
+ from PySide6.QtCore import QObject, Signal, QThread
5
+ from PySide6.QtWidgets import QMessageBox, QWidget
6
+
7
+ from vector_inspector.core.connection_manager import ConnectionManager, ConnectionState
8
+ from vector_inspector.core.connections.base_connection import VectorDBConnection
9
+ from vector_inspector.core.provider_factory import ProviderFactory
10
+ from vector_inspector.services.profile_service import ProfileService
11
+ from vector_inspector.ui.components.loading_dialog import LoadingDialog
12
+
13
+
14
+ class ConnectionThread(QThread):
15
+ """Background thread for connecting to database."""
16
+
17
+ finished = Signal(bool, list, str) # success, collections, error_message
18
+
19
+ def __init__(self, connection: VectorDBConnection):
20
+ super().__init__()
21
+ self.connection = connection
22
+
23
+ def run(self):
24
+ """Connect to database and get collections."""
25
+ try:
26
+ success = self.connection.connect()
27
+ if success:
28
+ collections = self.connection.list_collections()
29
+ self.finished.emit(True, collections, "")
30
+ else:
31
+ self.finished.emit(False, [], "Connection failed")
32
+ except Exception as e:
33
+ self.finished.emit(False, [], str(e))
34
+
35
+
36
+ class ConnectionController(QObject):
37
+ """Controller for managing connection operations and lifecycle.
38
+
39
+ This handles:
40
+ - Creating connections from profiles
41
+ - Starting connection threads
42
+ - Handling connection results
43
+ - Managing loading dialogs
44
+ - Emitting signals for UI updates
45
+ """
46
+
47
+ connection_completed = Signal(
48
+ str, bool, list, str
49
+ ) # connection_id, success, collections, error
50
+
51
+ def __init__(
52
+ self,
53
+ connection_manager: ConnectionManager,
54
+ profile_service: ProfileService,
55
+ parent: Optional[QWidget] = None,
56
+ ):
57
+ super().__init__(parent)
58
+ self.connection_manager = connection_manager
59
+ self.profile_service = profile_service
60
+ self.parent_widget = parent
61
+
62
+ # State
63
+ self._connection_threads: Dict[str, ConnectionThread] = {}
64
+ self.loading_dialog = LoadingDialog("Loading...", parent)
65
+
66
+ def connect_to_profile(self, profile_id: str) -> bool:
67
+ """Connect to a profile.
68
+
69
+ Args:
70
+ profile_id: ID of the profile to connect to
71
+
72
+ Returns:
73
+ True if connection initiated successfully, False otherwise
74
+ """
75
+ profile_data = self.profile_service.get_profile_with_credentials(profile_id)
76
+ if not profile_data:
77
+ QMessageBox.warning(self.parent_widget, "Error", "Profile not found.")
78
+ return False
79
+
80
+ # Check connection limit
81
+ if self.connection_manager.get_connection_count() >= ConnectionManager.MAX_CONNECTIONS:
82
+ QMessageBox.warning(
83
+ self.parent_widget,
84
+ "Connection Limit",
85
+ f"Maximum number of connections ({ConnectionManager.MAX_CONNECTIONS}) reached. "
86
+ "Please close a connection first.",
87
+ )
88
+ return False
89
+
90
+ # Create connection
91
+ provider = profile_data["provider"]
92
+ config = profile_data["config"]
93
+ credentials = profile_data.get("credentials", {})
94
+
95
+ try:
96
+ # Create connection object using factory
97
+ connection = ProviderFactory.create(provider, config, credentials)
98
+
99
+ # Register with connection manager, using profile_id as connection_id for persistence
100
+ connection_id = self.connection_manager.create_connection(
101
+ name=profile_data["name"],
102
+ provider=provider,
103
+ connection=connection,
104
+ config=config,
105
+ connection_id=profile_data["id"],
106
+ )
107
+
108
+ # Update state to connecting
109
+ self.connection_manager.update_connection_state(
110
+ connection_id, ConnectionState.CONNECTING
111
+ )
112
+
113
+ # Connect in background thread
114
+ thread = ConnectionThread(connection)
115
+ thread.finished.connect(
116
+ lambda success, collections, error: self._on_connection_finished(
117
+ connection_id, success, collections, error
118
+ )
119
+ )
120
+ self._connection_threads[connection_id] = thread
121
+ thread.start()
122
+
123
+ # Show loading dialog
124
+ self.loading_dialog.show_loading(f"Connecting to {profile_data['name']}...")
125
+ return True
126
+
127
+ except Exception as e:
128
+ QMessageBox.critical(
129
+ self.parent_widget, "Connection Error", f"Failed to create connection: {e}"
130
+ )
131
+ return False
132
+
133
+ def _on_connection_finished(
134
+ self, connection_id: str, success: bool, collections: list, error: str
135
+ ):
136
+ """Handle connection thread completion."""
137
+ self.loading_dialog.hide_loading()
138
+
139
+ # Clean up thread
140
+ thread = self._connection_threads.pop(connection_id, None)
141
+ if thread:
142
+ thread.wait() # Wait for thread to fully finish
143
+ thread.deleteLater()
144
+
145
+ if success:
146
+ # Update state to connected
147
+ self.connection_manager.update_connection_state(
148
+ connection_id, ConnectionState.CONNECTED
149
+ )
150
+
151
+ # Mark connection as opened first (will show in UI)
152
+ self.connection_manager.mark_connection_opened(connection_id)
153
+
154
+ # Then update collections (UI item now exists to receive them)
155
+ self.connection_manager.update_collections(connection_id, collections)
156
+ else:
157
+ # Update state to error
158
+ self.connection_manager.update_connection_state(
159
+ connection_id, ConnectionState.ERROR, error
160
+ )
161
+
162
+ QMessageBox.warning(
163
+ self.parent_widget, "Connection Failed", f"Failed to connect: {error}"
164
+ )
165
+
166
+ # Remove the failed connection
167
+ self.connection_manager.close_connection(connection_id)
168
+
169
+ # Emit signal for UI updates
170
+ self.connection_completed.emit(connection_id, success, collections, error)
171
+
172
+ def cleanup(self):
173
+ """Clean up connection threads on shutdown."""
174
+ for thread in list(self._connection_threads.values()):
175
+ if thread.isRunning():
176
+ thread.quit()
177
+ thread.wait(1000) # Wait up to 1 second