dbviewer 0.6.3 → 0.6.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b378480a03f4c61f60ee8e6b918b81bfabb09fcb3f7256010d6ee7d59795feb3
4
- data.tar.gz: 0ed1b725b27aa7c1290f767ce900ee8d5be1e2dd54df5edcaecef71f8945658f
3
+ metadata.gz: 8e0daf87e04dd3b546db4e71db2a20bb4ea9d9295e2d1c5017bc6300d7dd92c7
4
+ data.tar.gz: 93e23481c151d00baaf8a700117085bc9cae463a919c03cdb37e03e19936f884
5
5
  SHA512:
6
- metadata.gz: d7e70b3cb0c7ad44b8d5dee1fc476d85738a3169b1aaccac9e9aea242f0e1cf2801836341f4c391f9dd7d184985606376ca09366dada9944cd8058111a407105
7
- data.tar.gz: 9914b89d8c4678cf949edad75d713d74cdc9aa9ece9f67cabe967afd42d411730d8d34839ee9c006393ec0f35bc2a3cfe88d8195b49caaec99d6aab09f5c9d03
6
+ metadata.gz: b14ff2e88b86b05963da90401a3c4fca3b53c8550b1b04638a04eb0245fc31cd712e050ae16262c48809709f7a7ed3bc0d385c357d20af474f1c28a5bc48d50d
7
+ data.tar.gz: f018111ae3f4be3fc78555dc563e1e1353c88479d128933688b7a0b3063c266425fd49a19072ac43cc6828e66c43b5a560ae78c8367f4f605d2167acff5b9cc0
data/README.md CHANGED
@@ -373,7 +373,6 @@ graph TB
373
373
  subgraph "DBViewer Engine"
374
374
  Engine[Engine<br/>Rails::Engine]
375
375
  Config[Configuration<br/>Settings & Defaults]
376
- Validator::Sql[Validator::Sql<br/>Query Validation]
377
376
  end
378
377
 
379
378
  subgraph "Controllers Layer"
@@ -382,6 +381,11 @@ graph TB
382
381
  LogsController[LogsController<br/>Query Logs]
383
382
  ERDController[ERDController<br/>Entity Relationships]
384
383
  APIController[API Controllers<br/>JSON Endpoints]
384
+ ConnectionsController[ConnectionsController<br/>Database Connections]
385
+ end
386
+
387
+ subgraph "Controller Concerns"
388
+ DatabaseOperations[DatabaseOperations<br/>Shared Database Logic]
385
389
  end
386
390
 
387
391
  subgraph "Database Namespace"
@@ -396,11 +400,13 @@ graph TB
396
400
  QueryLogger[Logger<br/>Query Logging]
397
401
  QueryAnalyzer[Analyzer<br/>Performance Analysis]
398
402
  QueryParser[Parser<br/>SQL Parsing]
403
+ NotificationSubscriber[NotificationSubscriber<br/>Query Notifications]
399
404
  end
400
405
 
401
406
  subgraph "Datatable Namespace"
402
- QueryOperations[QueryOperations<br/>Table Queries]
407
+ QueryOperations[QueryOperations<br/>Table Queries & Filtering]
403
408
  QueryParams[QueryParams<br/>Parameter Handling]
409
+ ColumnFiltering[apply_single_column_filter<br/>Individual Filter Logic]
404
410
  end
405
411
 
406
412
  subgraph "Storage Namespace"
@@ -409,48 +415,71 @@ graph TB
409
415
  FileStorage[FileStorage<br/>File Storage]
410
416
  end
411
417
 
418
+ subgraph "Validation Namespace"
419
+ ValidatorSql[Validator::Sql<br/>Query Validation]
420
+ end
421
+
412
422
  %% Configuration Dependencies (Decoupled)
413
423
  Config -.->|"Dependency Injection"| Manager
414
424
  Manager -->|"cache_expiry"| CacheManager
415
425
  Manager -->|"config object"| QueryExecutor
416
426
 
417
- %% Main Dependencies
427
+ %% Engine Initialization
418
428
  Engine --> HomeController
419
429
  Engine --> TablesController
420
430
  Engine --> LogsController
421
431
  Engine --> ERDController
432
+ Engine --> ConnectionsController
433
+ Engine -.->|"setup()"| QueryLogger
434
+ Engine -.->|"subscribe"| NotificationSubscriber
422
435
 
436
+ %% Controller Dependencies
437
+ TablesController --> DatabaseOperations
438
+ HomeController --> DatabaseOperations
439
+ ConnectionsController --> DatabaseOperations
440
+ APIController --> DatabaseOperations
441
+ LogsController -.->|"Get List"| QueryLogger
442
+
443
+ DatabaseOperations --> Manager
444
+ DatabaseOperations --> QueryOperations
445
+
446
+ %% Manager Dependencies
423
447
  Manager --> CacheManager
424
448
  Manager --> MetadataManager
425
449
  Manager --> DynamicModelFactory
426
450
  Manager --> QueryOperations
427
451
 
452
+ %% Cache Dependencies
428
453
  CacheManager --> DynamicModelFactory
429
454
  CacheManager --> MetadataManager
430
455
 
456
+ %% QueryOperations Dependencies (Refactored)
431
457
  QueryOperations --> DynamicModelFactory
432
- QueryOperations --> QueryExecutor
433
458
  QueryOperations --> MetadataManager
459
+ QueryOperations --> QueryAnalyzer
460
+ QueryOperations --> ColumnFiltering
434
461
 
462
+ %% Storage Dependencies
435
463
  QueryLogger --> StorageBase
436
464
  StorageBase --> InMemoryStorage
437
465
  StorageBase --> FileStorage
438
466
 
439
- TablesController --> Manager
440
- HomeController --> Manager
441
- LogsController --> QueryLogger
442
- APIController --> Manager
443
- APIController --> QueryLogger
444
-
445
- %% Decoupled Configuration Flow
446
- Engine -.->|"setup()"| QueryLogger
467
+ %% Configuration Flow
447
468
  Config -.->|"logging settings"| QueryLogger
469
+ Config -.->|"database connections"| Manager
470
+
471
+ %% Validation
472
+ ValidatorSql --> QueryExecutor
448
473
 
474
+ %% Styling
449
475
  class CacheManager,QueryLogger decoupled
450
- class HomeController,TablesController,LogsController,ERDController,APIController controller
476
+ class HomeController,TablesController,LogsController,ERDController,APIController,ConnectionsController controller
477
+ class DatabaseOperations concern
451
478
  class Manager,MetadataManager,DynamicModelFactory database
452
- class QueryExecutor,QueryAnalyzer,QueryParser query
479
+ class QueryExecutor,QueryAnalyzer,QueryParser,NotificationSubscriber query
453
480
  class StorageBase,InMemoryStorage,FileStorage storage
481
+ class ColumnFiltering filtering
482
+ class ValidatorSql validation
454
483
  ```
455
484
 
456
485
  ## 🤌🏻 Contributing
@@ -0,0 +1,88 @@
1
+ module Dbviewer
2
+ module ConnectionManagement
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :current_connection_key, :available_connections if respond_to?(:helper_method)
7
+ end
8
+
9
+ # Get the current active connection key
10
+ def current_connection_key
11
+ key = session[:dbviewer_connection] || Dbviewer.configuration.current_connection
12
+ return key.to_sym if key && Dbviewer.configuration.database_connections.key?(key.to_sym)
13
+
14
+ first_key = Dbviewer.configuration.database_connections.keys.first
15
+ if first_key
16
+ session[:dbviewer_connection] = first_key
17
+ return first_key
18
+ end
19
+
20
+ :default
21
+ end
22
+
23
+ # Set the current connection to use
24
+ def switch_connection(connection_key)
25
+ connection_key = connection_key.to_sym if connection_key.respond_to?(:to_sym)
26
+
27
+ if connection_key && Dbviewer.configuration.database_connections.key?(connection_key)
28
+ session[:dbviewer_connection] = connection_key
29
+ # Clear the database manager to force it to be recreated with the new connection
30
+ @database_manager = nil
31
+ return true
32
+ else
33
+ # If the connection key doesn't exist, reset to default connection
34
+ if Dbviewer.configuration.database_connections.key?(Dbviewer.configuration.current_connection)
35
+ session[:dbviewer_connection] = Dbviewer.configuration.current_connection
36
+ @database_manager = nil
37
+ return true
38
+ else
39
+ # If even the default connection isn't valid, try the first available connection
40
+ first_key = Dbviewer.configuration.database_connections.keys.first
41
+ if first_key
42
+ session[:dbviewer_connection] = first_key
43
+ @database_manager = nil
44
+ return true
45
+ end
46
+ end
47
+ end
48
+
49
+ false # Return false if we couldn't set a valid connection
50
+ end
51
+
52
+ # Get list of available connections
53
+ def available_connections
54
+ connections = Dbviewer.configuration.database_connections.map do |key, config|
55
+ # Try to determine the adapter name if it's not already stored
56
+ adapter_name = nil
57
+ if config[:adapter_name].present?
58
+ adapter_name = config[:adapter_name]
59
+ elsif config[:connection].present?
60
+ begin
61
+ adapter_name = config[:connection].connection.adapter_name
62
+ rescue => e
63
+ Rails.logger.error("Error getting adapter name: #{e.message}")
64
+ end
65
+ end
66
+
67
+ {
68
+ key: key,
69
+ name: config[:name] || key.to_s.humanize,
70
+ adapter_name: adapter_name,
71
+ current: key.to_sym == current_connection_key.to_sym
72
+ }
73
+ end
74
+
75
+ # Ensure at least one connection is marked as current
76
+ unless connections.any? { |c| c[:current] }
77
+ # If no connection is current, mark the first one as current
78
+ if connections.any?
79
+ connections.first[:current] = true
80
+ # Also update the session
81
+ session[:dbviewer_connection] = connections.first[:key]
82
+ end
83
+ end
84
+
85
+ connections
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,32 @@
1
+ require "csv"
2
+
3
+ module Dbviewer
4
+ module DataExport
5
+ extend ActiveSupport::Concern
6
+
7
+ # Export table data to CSV
8
+ def export_table_to_csv(table_name, query_params = nil, include_headers = true)
9
+ records = database_manager.table_query_operations.table_records(table_name, query_params)
10
+
11
+ csv_data = CSV.generate do |csv|
12
+ # Add headers if requested
13
+ csv << records.columns if include_headers
14
+
15
+ # Add rows
16
+ records.rows.each do |row|
17
+ csv << row.map { |cell| format_csv_value(cell) }
18
+ end
19
+ end
20
+
21
+ csv_data
22
+ end
23
+
24
+ private
25
+
26
+ # Format cell values for CSV export to handle nil values and special characters
27
+ def format_csv_value(value)
28
+ return "" if value.nil?
29
+ value.to_s
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,62 @@
1
+ module Dbviewer
2
+ module DatabaseInformation
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :get_database_name, :get_adapter_name if respond_to?(:helper_method)
7
+ end
8
+
9
+ # Get the name of the current database
10
+ def get_database_name
11
+ # First check if this connection has a name in the configuration
12
+ current_conn_config = Dbviewer.configuration.database_connections[current_connection_key]
13
+ return current_conn_config[:name] if current_conn_config && current_conn_config[:name].present?
14
+
15
+ adapter = database_manager.connection.adapter_name.downcase
16
+
17
+ case adapter
18
+ when /mysql/
19
+ query = "SELECT DATABASE() as db_name"
20
+ result = database_manager.execute_query(query).first
21
+ result ? result["db_name"] : "Database"
22
+ when /postgres/
23
+ query = "SELECT current_database() as db_name"
24
+ result = database_manager.execute_query(query).first
25
+ result ? result["db_name"] : "Database"
26
+ when /sqlite/
27
+ # For SQLite, extract the database name from the connection_config
28
+ database_path = database_manager.connection.pool.spec.config[:database] || ""
29
+ File.basename(database_path, ".*") || "SQLite Database"
30
+ else
31
+ "Database" # Default fallback
32
+ end
33
+ end
34
+
35
+ # Get the name of the current database adapter
36
+ def get_adapter_name
37
+ adapter_name = database_manager.connection.adapter_name.downcase
38
+ adapter_mappings = {
39
+ /mysql/i => "MySQL",
40
+ /postgres/i => "PostgreSQL",
41
+ /sqlite/i => "SQLite",
42
+ /oracle/i => "Oracle",
43
+ /sqlserver|mssql/i => "SQL Server"
44
+ }
45
+ adapter_mappings.find { |pattern, _| adapter_name =~ pattern }&.last || adapter_name.titleize
46
+ rescue
47
+ "Unknown"
48
+ end
49
+
50
+ # Gather database analytics information
51
+ def fetch_database_analytics
52
+ tables = fetch_tables(include_record_counts: true)
53
+
54
+ {
55
+ total_tables: tables.size,
56
+ total_records: tables.sum { |t| t[:record_count] },
57
+ largest_tables: tables.sort_by { |t| -t[:record_count] }.first(10),
58
+ empty_tables: tables.select { |t| t[:record_count] == 0 }
59
+ }
60
+ end
61
+ end
62
+ end