sqlshell 0.2.3__py3-none-any.whl → 0.3.1__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.

Potentially problematic release.


This version of sqlshell might be problematic. Click here for more details.

@@ -1,9 +1,10 @@
1
1
  import sys
2
2
  import itertools
3
3
  import pandas as pd
4
- from typing import List, Dict, Tuple, Set
4
+ from typing import List, Dict, Tuple, Set, Callable
5
5
  from PyQt6.QtWidgets import (
6
- QApplication, QWidget, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem, QHeaderView, QTabWidget, QMainWindow
6
+ QApplication, QWidget, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem, QHeaderView, QTabWidget, QMainWindow,
7
+ QPushButton, QHBoxLayout, QMessageBox
7
8
  )
8
9
  from PyQt6.QtCore import Qt
9
10
 
@@ -217,7 +218,8 @@ def profile_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None, mi
217
218
  return foreign_keys, inclusion_dependencies, integrity_results
218
219
 
219
220
 
220
- def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None, min_match_ratio: float = 0.95):
221
+ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None, min_match_ratio: float = 0.95,
222
+ on_generate_join: Callable = None, parent=None):
221
223
  """
222
224
  Create a visual representation of foreign key relationships between DataFrames.
223
225
 
@@ -225,6 +227,9 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
225
227
  - dfs: List of pandas DataFrames to analyze
226
228
  - df_names: Optional list of names for the DataFrames. If None, names will be generated.
227
229
  - min_match_ratio: Minimum ratio of matching values to consider a foreign key
230
+ - on_generate_join: Callback function that will be called when the Generate JOIN button is clicked.
231
+ It receives a JOIN query string as its argument.
232
+ - parent: Parent widget for the QMainWindow. Typically the main application window.
228
233
 
229
234
  Returns:
230
235
  - QMainWindow: The visualization window
@@ -239,7 +244,7 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
239
244
  )
240
245
 
241
246
  # Create main window
242
- window = QMainWindow()
247
+ window = QMainWindow(parent)
243
248
  window.setWindowTitle("Foreign Key Analysis")
244
249
  window.resize(900, 700)
245
250
 
@@ -268,6 +273,13 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
268
273
  # Create tabs
269
274
  tabs = QTabWidget()
270
275
 
276
+ # Define the "Add to editor" function to handle JOIN queries
277
+ def handle_join_query(query):
278
+ if on_generate_join:
279
+ on_generate_join(query)
280
+ QMessageBox.information(window, "JOIN Query Generated",
281
+ f"The following query has been added to the editor:\n\n{query}")
282
+
271
283
  # Tab for Foreign Keys
272
284
  fk_tab = QWidget()
273
285
  fk_layout = QVBoxLayout()
@@ -276,12 +288,16 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
276
288
  fk_header.setStyleSheet("font-weight: bold;")
277
289
  fk_layout.addWidget(fk_header)
278
290
 
279
- fk_table = QTableWidget(len(foreign_keys), 5)
291
+ fk_table = QTableWidget(len(foreign_keys), 6) # Added column for Generate JOIN button
280
292
  fk_table.setHorizontalHeaderLabels([
281
- "Referenced Table", "Referenced Column", "Referencing Table", "Referencing Column", "Match Ratio"
293
+ "Referenced Table", "Referenced Column", "Referencing Table", "Referencing Column", "Match Ratio", "Action"
282
294
  ])
283
295
  fk_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
284
296
 
297
+ # Set minimum width for the Action column
298
+ fk_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Interactive)
299
+ fk_table.setColumnWidth(5, 140) # Set a fixed width for action column
300
+
285
301
  for row, (pk_table, pk_col, fk_table_name, fk_col, match_ratio) in enumerate(foreign_keys):
286
302
  fk_table.setItem(row, 0, QTableWidgetItem(pk_table))
287
303
  fk_table.setItem(row, 1, QTableWidgetItem(pk_col))
@@ -298,6 +314,27 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
298
314
  ratio_item.setForeground(Qt.GlobalColor.darkYellow)
299
315
  fk_table.setItem(row, 4, ratio_item)
300
316
 
317
+ # Add Generate JOIN hyperlink - optimized for better visibility
318
+ if on_generate_join is not None:
319
+ button_widget = QWidget()
320
+ button_layout = QHBoxLayout(button_widget)
321
+ button_layout.setContentsMargins(0, 0, 0, 0) # Minimal margins
322
+ button_layout.setSpacing(0) # No spacing
323
+
324
+ # Create a styled hyperlink label
325
+ join_link = QLabel("<a href='#' style='color: #3498DB; font-weight: bold;'>Generate JOIN</a>")
326
+ join_link.setTextFormat(Qt.TextFormat.RichText)
327
+ join_link.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
328
+ join_link.setCursor(Qt.CursorShape.PointingHandCursor)
329
+ join_link.setAlignment(Qt.AlignmentFlag.AlignCenter) # Center the text
330
+ join_query = f"SELECT * FROM {fk_table_name} JOIN {pk_table} ON {fk_table_name}.{fk_col} = {pk_table}.{pk_col}"
331
+
332
+ # Connect linkActivated signal to handle the JOIN query
333
+ join_link.linkActivated.connect(lambda link, q=join_query: handle_join_query(q))
334
+
335
+ button_layout.addWidget(join_link)
336
+ fk_table.setCellWidget(row, 5, button_widget)
337
+
301
338
  fk_layout.addWidget(fk_table)
302
339
  fk_tab.setLayout(fk_layout)
303
340
  tabs.addTab(fk_tab, "Foreign Keys")
@@ -310,12 +347,16 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
310
347
  id_header.setStyleSheet("font-weight: bold;")
311
348
  id_layout.addWidget(id_header)
312
349
 
313
- id_table = QTableWidget(len(inclusion_dependencies), 5)
350
+ id_table = QTableWidget(len(inclusion_dependencies), 6) # Added column for Generate JOIN button
314
351
  id_table.setHorizontalHeaderLabels([
315
- "Referenced Table", "Referenced Column", "Referencing Table", "Referencing Column", "Match Ratio"
352
+ "Referenced Table", "Referenced Column", "Referencing Table", "Referencing Column", "Match Ratio", "Action"
316
353
  ])
317
354
  id_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
318
355
 
356
+ # Set minimum width for the Action column
357
+ id_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Interactive)
358
+ id_table.setColumnWidth(5, 140) # Set a fixed width for action column
359
+
319
360
  for row, (table1, col1, table2, col2, match_ratio) in enumerate(inclusion_dependencies):
320
361
  id_table.setItem(row, 0, QTableWidgetItem(table1))
321
362
  id_table.setItem(row, 1, QTableWidgetItem(col1))
@@ -332,6 +373,27 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
332
373
  ratio_item.setForeground(Qt.GlobalColor.darkYellow)
333
374
  id_table.setItem(row, 4, ratio_item)
334
375
 
376
+ # Add Generate JOIN hyperlink - optimized for better visibility
377
+ if on_generate_join is not None:
378
+ button_widget = QWidget()
379
+ button_layout = QHBoxLayout(button_widget)
380
+ button_layout.setContentsMargins(0, 0, 0, 0) # Minimal margins
381
+ button_layout.setSpacing(0) # No spacing
382
+
383
+ # Create a styled hyperlink label
384
+ join_link = QLabel("<a href='#' style='color: #3498DB; font-weight: bold;'>Generate JOIN</a>")
385
+ join_link.setTextFormat(Qt.TextFormat.RichText)
386
+ join_link.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
387
+ join_link.setCursor(Qt.CursorShape.PointingHandCursor)
388
+ join_link.setAlignment(Qt.AlignmentFlag.AlignCenter) # Center the text
389
+ join_query = f"SELECT * FROM {table2} JOIN {table1} ON {table2}.{col2} = {table1}.{col1}"
390
+
391
+ # Connect linkActivated signal to handle the JOIN query
392
+ join_link.linkActivated.connect(lambda link, q=join_query: handle_join_query(q))
393
+
394
+ button_layout.addWidget(join_link)
395
+ id_table.setCellWidget(row, 5, button_widget)
396
+
335
397
  id_layout.addWidget(id_table)
336
398
  id_tab.setLayout(id_layout)
337
399
  tabs.addTab(id_tab, "Inclusion Dependencies")
@@ -352,12 +414,16 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
352
414
  ri_layout.addWidget(ri_description)
353
415
 
354
416
  # Create table for referential integrity
355
- ri_table = QTableWidget(len(integrity_results), 5)
417
+ ri_table = QTableWidget(len(integrity_results), 6) # Added column for Generate JOIN button
356
418
  ri_table.setHorizontalHeaderLabels([
357
- "Relationship", "Violations", "Total FK Values", "Violation %", "Example Violations"
419
+ "Relationship", "Violations", "Total FK Values", "Violation %", "Example Violations", "Action"
358
420
  ])
359
421
  ri_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
360
422
 
423
+ # Set minimum width for the Action column
424
+ ri_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Interactive)
425
+ ri_table.setColumnWidth(5, 140) # Set a fixed width for action column
426
+
361
427
  row = 0
362
428
  for key, stats in integrity_results.items():
363
429
  pk_table, pk_col, fk_table, fk_col = key
@@ -383,6 +449,27 @@ def visualize_foreign_keys(dfs: List[pd.DataFrame], df_names: List[str] = None,
383
449
  examples += f" (and {stats['violation_count'] - len(stats['violations'])} more)"
384
450
  ri_table.setItem(row, 4, QTableWidgetItem(examples))
385
451
 
452
+ # Add Generate JOIN hyperlink - optimized for better visibility
453
+ if on_generate_join is not None:
454
+ button_widget = QWidget()
455
+ button_layout = QHBoxLayout(button_widget)
456
+ button_layout.setContentsMargins(0, 0, 0, 0) # Minimal margins
457
+ button_layout.setSpacing(0) # No spacing
458
+
459
+ # Create a styled hyperlink label
460
+ join_link = QLabel("<a href='#' style='color: #3498DB; font-weight: bold;'>Generate JOIN</a>")
461
+ join_link.setTextFormat(Qt.TextFormat.RichText)
462
+ join_link.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
463
+ join_link.setCursor(Qt.CursorShape.PointingHandCursor)
464
+ join_link.setAlignment(Qt.AlignmentFlag.AlignCenter) # Center the text
465
+ join_query = f"SELECT * FROM {fk_table} LEFT JOIN {pk_table} ON {fk_table}.{fk_col} = {pk_table}.{pk_col}"
466
+
467
+ # Connect linkActivated signal to handle the JOIN query
468
+ join_link.linkActivated.connect(lambda link, q=join_query: handle_join_query(q))
469
+
470
+ button_layout.addWidget(join_link)
471
+ ri_table.setCellWidget(row, 5, button_widget)
472
+
386
473
  row += 1
387
474
 
388
475
  ri_layout.addWidget(ri_table)
@@ -442,12 +529,17 @@ def test_profile_foreign_keys():
442
529
  # Add some non-existent customer IDs
443
530
  orders_df.loc[95:99, "customer_id"] = [25, 26, 27, 28, 29]
444
531
 
532
+ # Define a callback function to handle JOIN generation
533
+ def handle_join_query(query):
534
+ print(f"Generated JOIN query: {query}")
535
+ # In a real application, this would insert the query into the query editor
536
+
445
537
  # Create and show visualization
446
538
  dfs = [customers_df, products_df, orders_df, order_details_df]
447
539
  df_names = ["Customers", "Products", "Orders", "OrderDetails"]
448
540
 
449
541
  app = QApplication(sys.argv)
450
- window = visualize_foreign_keys(dfs, df_names, min_match_ratio=0.9)
542
+ window = visualize_foreign_keys(dfs, df_names, min_match_ratio=0.9, on_generate_join=handle_join_query)
451
543
  sys.exit(app.exec())
452
544
 
453
545
  # Only run the test function when script is executed directly