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 +4 -4
- data/README.md +43 -14
- data/app/controllers/concerns/dbviewer/connection_management.rb +88 -0
- data/app/controllers/concerns/dbviewer/data_export.rb +32 -0
- data/app/controllers/concerns/dbviewer/database_information.rb +62 -0
- data/app/controllers/concerns/dbviewer/database_operations.rb +8 -503
- data/app/controllers/concerns/dbviewer/datatable_support.rb +47 -0
- data/app/controllers/concerns/dbviewer/query_operations.rb +28 -0
- data/app/controllers/concerns/dbviewer/relationship_management.rb +173 -0
- data/app/controllers/concerns/dbviewer/table_operations.rb +56 -0
- data/app/controllers/dbviewer/api/entity_relationship_diagrams_controller.rb +1 -1
- data/app/controllers/dbviewer/tables_controller.rb +7 -2
- data/app/helpers/dbviewer/application_helper.rb +9 -541
- data/app/helpers/dbviewer/database_helper.rb +59 -0
- data/app/helpers/dbviewer/filter_helper.rb +137 -0
- data/app/helpers/dbviewer/formatting_helper.rb +30 -0
- data/app/helpers/dbviewer/navigation_helper.rb +35 -0
- data/app/helpers/dbviewer/pagination_helper.rb +72 -0
- data/app/helpers/dbviewer/sorting_helper.rb +47 -0
- data/app/helpers/dbviewer/table_rendering_helper.rb +145 -0
- data/app/helpers/dbviewer/ui_helper.rb +41 -0
- data/lib/dbviewer/database/manager.rb +2 -3
- data/lib/dbviewer/datatable/query_operations.rb +35 -20
- data/lib/dbviewer/query/executor.rb +0 -35
- data/lib/dbviewer/version.rb +1 -1
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e0daf87e04dd3b546db4e71db2a20bb4ea9d9295e2d1c5017bc6300d7dd92c7
|
4
|
+
data.tar.gz: 93e23481c151d00baaf8a700117085bc9cae463a919c03cdb37e03e19936f884
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
%%
|
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
|
-
|
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
|