dbviewer 0.5.2 → 0.5.3
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 +92 -0
- data/app/controllers/concerns/dbviewer/database_operations.rb +11 -19
- data/app/controllers/dbviewer/api/entity_relationship_diagrams_controller.rb +84 -0
- data/app/controllers/dbviewer/api/queries_controller.rb +1 -1
- data/app/controllers/dbviewer/entity_relationship_diagrams_controller.rb +5 -6
- data/app/controllers/dbviewer/logs_controller.rb +1 -1
- data/app/controllers/dbviewer/tables_controller.rb +2 -8
- data/app/helpers/dbviewer/application_helper.rb +1 -1
- data/app/views/dbviewer/entity_relationship_diagrams/index.html.erb +217 -100
- data/app/views/dbviewer/tables/show.html.erb +278 -404
- data/config/routes.rb +7 -0
- data/lib/dbviewer/database/cache_manager.rb +78 -0
- data/lib/dbviewer/database/dynamic_model_factory.rb +62 -0
- data/lib/dbviewer/database/manager.rb +204 -0
- data/lib/dbviewer/database/metadata_manager.rb +129 -0
- data/lib/dbviewer/datatable/query_operations.rb +330 -0
- data/lib/dbviewer/datatable/query_params.rb +41 -0
- data/lib/dbviewer/engine.rb +1 -1
- data/lib/dbviewer/query/analyzer.rb +250 -0
- data/lib/dbviewer/query/collection.rb +39 -0
- data/lib/dbviewer/query/executor.rb +93 -0
- data/lib/dbviewer/query/logger.rb +108 -0
- data/lib/dbviewer/query/parser.rb +56 -0
- data/lib/dbviewer/storage/file_storage.rb +0 -3
- data/lib/dbviewer/version.rb +1 -1
- data/lib/dbviewer.rb +24 -7
- metadata +14 -14
- data/lib/dbviewer/cache_manager.rb +0 -78
- data/lib/dbviewer/database_manager.rb +0 -249
- data/lib/dbviewer/dynamic_model_factory.rb +0 -60
- data/lib/dbviewer/error_handler.rb +0 -18
- data/lib/dbviewer/logger.rb +0 -77
- data/lib/dbviewer/query_analyzer.rb +0 -239
- data/lib/dbviewer/query_collection.rb +0 -37
- data/lib/dbviewer/query_executor.rb +0 -91
- data/lib/dbviewer/query_parser.rb +0 -53
- data/lib/dbviewer/table_metadata_manager.rb +0 -136
- data/lib/dbviewer/table_query_operations.rb +0 -621
- data/lib/dbviewer/table_query_params.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f8d59c15a88c9b63e2765f80b554c2b2a0a33f82fdb094e1ed6f86fdf8dde20
|
4
|
+
data.tar.gz: d2bbe1fd8acae50c791ab4c32a061c78abbee095001e1647e32b4af4e6918753
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcdf464a23ec52c45d85645ea0dcc9f57fe59c69b8452a68de7f000606d31d3e29c8b81ca237a228debc6884b57e8fb7a40500c1f02af550b3c5515456009ae5
|
7
|
+
data.tar.gz: 768b6cb0f7d67c0ecda6301c6a94471ad16a89f37c6164c8e4f976222f1e1f95720b17477e43811f4d9574c79c71e1f6e582471d0acf408b815aeba17b58c961
|
data/README.md
CHANGED
@@ -333,6 +333,98 @@ gem build dbviewer.gemspec
|
|
333
333
|
2. Visit `http://localhost:3000/dbviewer` to test your changes
|
334
334
|
3. The dummy app includes sample data across multiple tables to test various DBViewer features
|
335
335
|
|
336
|
+
### Architecture Diagram
|
337
|
+
```mermaid
|
338
|
+
graph TB
|
339
|
+
subgraph "DBViewer Engine"
|
340
|
+
Engine[Engine<br/>Rails::Engine]
|
341
|
+
Config[Configuration<br/>Settings & Defaults]
|
342
|
+
SqlValidator[SqlValidator<br/>Query Validation]
|
343
|
+
end
|
344
|
+
|
345
|
+
subgraph "Controllers Layer"
|
346
|
+
HomeController[HomeController<br/>Dashboard & Overview]
|
347
|
+
TablesController[TablesController<br/>Table Operations]
|
348
|
+
LogsController[LogsController<br/>Query Logs]
|
349
|
+
ERDController[ERDController<br/>Entity Relationships]
|
350
|
+
APIController[API Controllers<br/>JSON Endpoints]
|
351
|
+
end
|
352
|
+
|
353
|
+
subgraph "Database Namespace"
|
354
|
+
Manager[Manager<br/>Database Operations]
|
355
|
+
CacheManager[CacheManager<br/>Caching Layer]
|
356
|
+
MetadataManager[MetadataManager<br/>Schema Information]
|
357
|
+
DynamicModelFactory[DynamicModelFactory<br/>ActiveRecord Models]
|
358
|
+
end
|
359
|
+
|
360
|
+
subgraph "Query Namespace"
|
361
|
+
QueryExecutor[Executor<br/>SQL Execution]
|
362
|
+
QueryLogger[Logger<br/>Query Logging]
|
363
|
+
QueryAnalyzer[Analyzer<br/>Performance Analysis]
|
364
|
+
QueryParser[Parser<br/>SQL Parsing]
|
365
|
+
end
|
366
|
+
|
367
|
+
subgraph "Datatable Namespace"
|
368
|
+
QueryOperations[QueryOperations<br/>Table Queries]
|
369
|
+
QueryParams[QueryParams<br/>Parameter Handling]
|
370
|
+
end
|
371
|
+
|
372
|
+
subgraph "Storage Namespace"
|
373
|
+
StorageBase[Base<br/>Storage Interface]
|
374
|
+
InMemoryStorage[InMemoryStorage<br/>Memory Storage]
|
375
|
+
FileStorage[FileStorage<br/>File Storage]
|
376
|
+
end
|
377
|
+
|
378
|
+
%% Configuration Dependencies (Decoupled)
|
379
|
+
Config -.->|"Dependency Injection"| Manager
|
380
|
+
Manager -->|"cache_expiry"| CacheManager
|
381
|
+
Manager -->|"config object"| QueryExecutor
|
382
|
+
|
383
|
+
%% Main Dependencies
|
384
|
+
Engine --> HomeController
|
385
|
+
Engine --> TablesController
|
386
|
+
Engine --> LogsController
|
387
|
+
Engine --> ERDController
|
388
|
+
|
389
|
+
Manager --> CacheManager
|
390
|
+
Manager --> MetadataManager
|
391
|
+
Manager --> DynamicModelFactory
|
392
|
+
Manager --> QueryOperations
|
393
|
+
|
394
|
+
CacheManager --> DynamicModelFactory
|
395
|
+
CacheManager --> MetadataManager
|
396
|
+
|
397
|
+
QueryOperations --> DynamicModelFactory
|
398
|
+
QueryOperations --> QueryExecutor
|
399
|
+
QueryOperations --> MetadataManager
|
400
|
+
|
401
|
+
QueryLogger --> StorageBase
|
402
|
+
StorageBase --> InMemoryStorage
|
403
|
+
StorageBase --> FileStorage
|
404
|
+
|
405
|
+
TablesController --> Manager
|
406
|
+
HomeController --> Manager
|
407
|
+
LogsController --> QueryLogger
|
408
|
+
APIController --> Manager
|
409
|
+
APIController --> QueryLogger
|
410
|
+
|
411
|
+
%% Decoupled Configuration Flow
|
412
|
+
Engine -.->|"setup()"| QueryLogger
|
413
|
+
Config -.->|"logging settings"| QueryLogger
|
414
|
+
|
415
|
+
classDef decoupled fill:#e1f5fe,stroke:#01579b,stroke-width:2px
|
416
|
+
classDef controller fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
|
417
|
+
classDef database fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
|
418
|
+
classDef query fill:#fff3e0,stroke:#e65100,stroke-width:2px
|
419
|
+
classDef storage fill:#fce4ec,stroke:#880e4f,stroke-width:2px
|
420
|
+
|
421
|
+
class CacheManager,QueryLogger decoupled
|
422
|
+
class HomeController,TablesController,LogsController,ERDController,APIController controller
|
423
|
+
class Manager,MetadataManager,DynamicModelFactory database
|
424
|
+
class QueryExecutor,QueryAnalyzer,QueryParser query
|
425
|
+
class StorageBase,InMemoryStorage,FileStorage storage
|
426
|
+
```
|
427
|
+
|
336
428
|
## 🤌🏻 Contributing
|
337
429
|
|
338
430
|
Bug reports and pull requests are welcome.
|
@@ -10,7 +10,7 @@ module Dbviewer
|
|
10
10
|
|
11
11
|
# Initialize the database manager
|
12
12
|
def database_manager
|
13
|
-
@database_manager ||= ::Dbviewer::
|
13
|
+
@database_manager ||= ::Dbviewer::Database::Manager.new
|
14
14
|
end
|
15
15
|
|
16
16
|
# Initialize the table query operations manager
|
@@ -46,23 +46,15 @@ module Dbviewer
|
|
46
46
|
|
47
47
|
# Get the name of the current database adapter
|
48
48
|
def get_adapter_name
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
"
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
"SQLite"
|
59
|
-
when /oracle/
|
60
|
-
"Oracle"
|
61
|
-
when /sqlserver/, /mssql/
|
62
|
-
"SQL Server"
|
63
|
-
else
|
64
|
-
adapter.titleize # Fallback to titleized version
|
65
|
-
end
|
49
|
+
adapter_name = database_manager.connection.adapter_name.downcase
|
50
|
+
adapter_mappings = {
|
51
|
+
/mysql/i => "MySQL",
|
52
|
+
/postgres/i => "PostgreSQL",
|
53
|
+
/sqlite/i => "SQLite",
|
54
|
+
/oracle/i => "Oracle",
|
55
|
+
/sqlserver|mssql/i => "SQL Server"
|
56
|
+
}
|
57
|
+
adapter_mappings.find { |pattern, _| adapter_name =~ pattern }&.last || adapter_name.titleize
|
66
58
|
rescue => e
|
67
59
|
Rails.logger.error("Error retrieving adapter name: #{e.message}")
|
68
60
|
"Unknown"
|
@@ -328,7 +320,7 @@ module Dbviewer
|
|
328
320
|
|
329
321
|
# Export table data to CSV
|
330
322
|
def export_table_to_csv(table_name, query_params = nil, include_headers = true)
|
331
|
-
records = database_manager.
|
323
|
+
records = database_manager.table_query_operations.table_records(table_name, query_params)
|
332
324
|
|
333
325
|
csv_data = CSV.generate do |csv|
|
334
326
|
# Add headers if requested
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Dbviewer
|
2
|
+
module Api
|
3
|
+
class EntityRelationshipDiagramsController < BaseController
|
4
|
+
before_action :set_tables
|
5
|
+
|
6
|
+
def relationships
|
7
|
+
# Fetch all relationships asynchronously
|
8
|
+
begin
|
9
|
+
@table_relationships = fetch_table_relationships
|
10
|
+
render_success({
|
11
|
+
relationships: @table_relationships,
|
12
|
+
status: "success"
|
13
|
+
})
|
14
|
+
rescue => e
|
15
|
+
Rails.logger.error("[DBViewer] Error fetching relationships: #{e.message}")
|
16
|
+
render json: {
|
17
|
+
relationships: [],
|
18
|
+
status: "error",
|
19
|
+
error: e.message
|
20
|
+
}, status: :internal_server_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def table_relationships
|
25
|
+
# Fetch relationships for specific tables
|
26
|
+
table_names = params[:tables]&.split(",") || []
|
27
|
+
|
28
|
+
if table_names.blank?
|
29
|
+
render json: {
|
30
|
+
relationships: [],
|
31
|
+
status: "error",
|
32
|
+
error: "No tables specified"
|
33
|
+
}, status: :bad_request
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
relationships = []
|
39
|
+
|
40
|
+
table_names.each do |table_name|
|
41
|
+
next unless @tables.any? { |t| t[:name] == table_name }
|
42
|
+
|
43
|
+
begin
|
44
|
+
metadata = fetch_table_metadata(table_name)
|
45
|
+
if metadata && metadata[:foreign_keys].present?
|
46
|
+
metadata[:foreign_keys].each do |fk|
|
47
|
+
relationships << {
|
48
|
+
from_table: table_name,
|
49
|
+
to_table: fk[:to_table],
|
50
|
+
from_column: fk[:column],
|
51
|
+
to_column: fk[:primary_key],
|
52
|
+
name: fk[:name]
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
Rails.logger.error("[DBViewer] Error fetching relationships for #{table_name}: #{e.message}")
|
58
|
+
# Continue with other tables even if one fails
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
render_success({
|
63
|
+
relationships: relationships,
|
64
|
+
status: "success",
|
65
|
+
processed_tables: table_names
|
66
|
+
})
|
67
|
+
rescue => e
|
68
|
+
Rails.logger.error("[DBViewer] Error in table_relationships: #{e.message}")
|
69
|
+
render json: {
|
70
|
+
relationships: [],
|
71
|
+
status: "error",
|
72
|
+
error: e.message
|
73
|
+
}, status: :internal_server_error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def set_tables
|
80
|
+
@tables = fetch_tables
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -13,7 +13,7 @@ module Dbviewer
|
|
13
13
|
def fetch_recent_queries
|
14
14
|
return [] unless query_logging_enabled?
|
15
15
|
|
16
|
-
Dbviewer::Logger.instance.recent_queries(limit: queries_limit)
|
16
|
+
Dbviewer::Query::Logger.instance.recent_queries(limit: queries_limit)
|
17
17
|
end
|
18
18
|
|
19
19
|
def query_logging_enabled?
|
@@ -1,19 +1,18 @@
|
|
1
1
|
module Dbviewer
|
2
2
|
class EntityRelationshipDiagramsController < ApplicationController
|
3
3
|
def index
|
4
|
-
if
|
5
|
-
|
6
|
-
else
|
7
|
-
@table_relationships = []
|
4
|
+
# Only show warning if no tables exist, but don't fetch relationships on initial load
|
5
|
+
if @tables.blank?
|
8
6
|
flash.now[:warning] = "No tables found in database to generate ERD."
|
9
7
|
end
|
10
8
|
|
11
9
|
respond_to do |format|
|
12
|
-
format.html
|
10
|
+
format.html # Just render the HTML without relationships
|
13
11
|
format.json do
|
12
|
+
# For JSON requests, return just tables initially
|
14
13
|
render json: {
|
15
14
|
tables: @tables,
|
16
|
-
relationships:
|
15
|
+
relationships: []
|
17
16
|
}
|
18
17
|
end
|
19
18
|
end
|
@@ -11,7 +11,7 @@ module Dbviewer
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def show
|
14
|
-
query_params = Dbviewer::
|
14
|
+
query_params = Dbviewer::Datatable::QueryParams.new(
|
15
15
|
page: @current_page,
|
16
16
|
per_page: @per_page,
|
17
17
|
order_by: @order_by,
|
@@ -29,12 +29,6 @@ module Dbviewer
|
|
29
29
|
@records = ActiveRecord::Result.new(column_names, [])
|
30
30
|
end
|
31
31
|
|
32
|
-
# Fetch timestamp visualization data if the table has a created_at column
|
33
|
-
if has_timestamp_column?(@table_name)
|
34
|
-
@time_grouping = params[:time_group] || "daily"
|
35
|
-
@timestamp_data = fetch_timestamp_data(@table_name, @time_grouping)
|
36
|
-
end
|
37
|
-
|
38
32
|
respond_to do |format|
|
39
33
|
format.html # Default HTML response
|
40
34
|
format.json do
|
@@ -76,7 +70,7 @@ module Dbviewer
|
|
76
70
|
end
|
77
71
|
|
78
72
|
include_headers = params[:include_headers] != "0"
|
79
|
-
query_params = Dbviewer::
|
73
|
+
query_params = Dbviewer::Datatable::QueryParams.new(
|
80
74
|
page: @current_page,
|
81
75
|
per_page: (params[:limit] || 10000).to_i,
|
82
76
|
order_by: @order_by,
|