dbviewer 0.3.1 → 0.3.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/app/controllers/concerns/dbviewer/database_operations.rb +3 -5
- data/app/controllers/dbviewer/entity_relationship_diagrams_controller.rb +1 -3
- data/app/controllers/dbviewer/home_controller.rb +6 -3
- data/app/controllers/dbviewer/logs_controller.rb +8 -4
- data/app/controllers/dbviewer/tables_controller.rb +1 -1
- data/app/views/dbviewer/home/index.html.erb +2 -44
- data/app/views/dbviewer/tables/index.html.erb +3 -3
- data/lib/dbviewer/cache_manager.rb +78 -0
- data/lib/dbviewer/configuration.rb +0 -28
- data/lib/dbviewer/database_manager.rb +80 -301
- data/lib/dbviewer/dynamic_model_factory.rb +60 -0
- data/lib/dbviewer/engine.rb +5 -3
- data/lib/dbviewer/error_handler.rb +18 -0
- data/lib/dbviewer/logger.rb +26 -53
- data/lib/dbviewer/query_collection.rb +0 -4
- data/lib/dbviewer/query_executor.rb +91 -0
- data/lib/dbviewer/table_metadata_manager.rb +104 -0
- data/lib/dbviewer/version.rb +1 -1
- data/lib/dbviewer.rb +10 -15
- metadata +7 -4
- data/app/controllers/dbviewer/databases_controller.rb +0 -0
- data/lib/dbviewer/initializer.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e6fcb0f5760c3daa24b0bbcd6f7f39d308890386eb7bae0e99b59c5027c0853
|
4
|
+
data.tar.gz: 486266a6f7d882f28b2411860466cb271b7e5d32ca65a25f04bf27601a6fb4c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 362be7d7fed295db73faad72e0b339d7b1f824d945e7c141c2cb43305d9d31c109526c05fe612135c6cfafc74e618621125a03bab3127ac52ec57a58bfcabbf0
|
7
|
+
data.tar.gz: 0a7289d157e0911d0e5e932c7ebbd964536ade2b125d4de7308fb518516793a6162f690a6d7c0dbc3cb88087754a3b2593265c5c6fa48c9980bb6ca0375cf91c
|
@@ -41,8 +41,8 @@ module Dbviewer
|
|
41
41
|
def fetch_tables_with_stats(include_record_counts = false)
|
42
42
|
database_manager.tables.map do |table_name|
|
43
43
|
table_stats = {
|
44
|
-
name: table_name
|
45
|
-
columns_count: database_manager.column_count(table_name)
|
44
|
+
name: table_name
|
45
|
+
# columns_count: database_manager.column_count(table_name)
|
46
46
|
}
|
47
47
|
|
48
48
|
# Only fetch record counts if explicitly requested
|
@@ -61,9 +61,7 @@ module Dbviewer
|
|
61
61
|
analytics = {
|
62
62
|
total_tables: tables.size,
|
63
63
|
total_records: tables.sum { |t| t[:record_count] },
|
64
|
-
|
65
|
-
largest_tables: tables.sort_by { |t| -t[:record_count] }.first(5),
|
66
|
-
widest_tables: tables.sort_by { |t| -t[:columns_count] }.first(5),
|
64
|
+
largest_tables: tables.sort_by { |t| -t[:record_count] }.first(10),
|
67
65
|
empty_tables: tables.select { |t| t[:record_count] == 0 }
|
68
66
|
}
|
69
67
|
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Dbviewer
|
2
2
|
class EntityRelationshipDiagramsController < ApplicationController
|
3
3
|
def index
|
4
|
-
@tables = fetch_tables_with_stats
|
5
|
-
|
6
4
|
if @tables.present?
|
7
5
|
@table_relationships = fetch_table_relationships
|
8
6
|
else
|
@@ -11,7 +9,7 @@ module Dbviewer
|
|
11
9
|
end
|
12
10
|
|
13
11
|
respond_to do |format|
|
14
|
-
format.html
|
12
|
+
format.html
|
15
13
|
format.json do
|
16
14
|
render json: {
|
17
15
|
tables: @tables,
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module Dbviewer
|
2
2
|
class HomeController < ApplicationController
|
3
|
-
skip_before_action :set_tables
|
4
|
-
|
5
3
|
def index
|
6
|
-
@tables = fetch_tables_with_stats(include_record_counts: true)
|
7
4
|
@analytics = fetch_database_analytics
|
8
5
|
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def set_tables
|
10
|
+
@tables = fetch_tables_with_stats(include_record_counts: true)
|
11
|
+
end
|
9
12
|
end
|
10
13
|
end
|
@@ -3,7 +3,7 @@ module Dbviewer
|
|
3
3
|
before_action :set_filters, only: [ :index ]
|
4
4
|
|
5
5
|
def index
|
6
|
-
@queries =
|
6
|
+
@queries = dbviewer_logger.recent_queries(
|
7
7
|
limit: @limit,
|
8
8
|
table_filter: @table_filter,
|
9
9
|
request_id: @request_id,
|
@@ -11,16 +11,16 @@ module Dbviewer
|
|
11
11
|
)
|
12
12
|
|
13
13
|
if @request_id.present? || @table_filter.present? || @min_duration.present?
|
14
|
-
@stats =
|
14
|
+
@stats = dbviewer_logger.stats_for_queries(@queries)
|
15
15
|
@filtered_stats = true
|
16
16
|
else
|
17
|
-
@stats =
|
17
|
+
@stats = dbviewer_logger.stats
|
18
18
|
@filtered_stats = false
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def destroy_all
|
23
|
-
|
23
|
+
dbviewer_logger.clear
|
24
24
|
flash[:success] = "Query logs cleared successfully"
|
25
25
|
|
26
26
|
redirect_to logs_path
|
@@ -35,5 +35,9 @@ module Dbviewer
|
|
35
35
|
@limit = (params[:limit] || 100).to_i
|
36
36
|
@limit = 1000 if @limit > 1000
|
37
37
|
end
|
38
|
+
|
39
|
+
def dbviewer_logger
|
40
|
+
@dbviewer_logger ||= Dbviewer::Logger.instance
|
41
|
+
end
|
38
42
|
end
|
39
43
|
end
|
@@ -65,7 +65,6 @@
|
|
65
65
|
<tr>
|
66
66
|
<th>Table Name</th>
|
67
67
|
<th class="text-end">Records</th>
|
68
|
-
<th class="text-end">Columns</th>
|
69
68
|
</tr>
|
70
69
|
</thead>
|
71
70
|
<tbody>
|
@@ -77,7 +76,6 @@
|
|
77
76
|
</a>
|
78
77
|
</td>
|
79
78
|
<td class="text-end"><%= number_with_delimiter(table[:record_count]) %></td>
|
80
|
-
<td class="text-end"><%= table[:columns_count] %></td>
|
81
79
|
</tr>
|
82
80
|
<% end %>
|
83
81
|
</tbody>
|
@@ -92,47 +90,7 @@
|
|
92
90
|
</div>
|
93
91
|
</div>
|
94
92
|
|
95
|
-
<div class="col-
|
96
|
-
<div class="card h-100 shadow-sm">
|
97
|
-
<div class="card-header">
|
98
|
-
<h5 class="card-title mb-0">Tables with Most Columns</h5>
|
99
|
-
</div>
|
100
|
-
<div class="card-body">
|
101
|
-
<% if @analytics[:widest_tables].any? %>
|
102
|
-
<div class="table-responsive">
|
103
|
-
<table class="table table-sm table-hover">
|
104
|
-
<thead>
|
105
|
-
<tr>
|
106
|
-
<th>Table Name</th>
|
107
|
-
<th class="text-end">Columns</th>
|
108
|
-
<th class="text-end">Records</th>
|
109
|
-
</tr>
|
110
|
-
</thead>
|
111
|
-
<tbody>
|
112
|
-
<% @analytics[:widest_tables].each do |table| %>
|
113
|
-
<tr>
|
114
|
-
<td>
|
115
|
-
<a href="<%= dbviewer.table_path(table[:name]) %>">
|
116
|
-
<%= table[:name] %>
|
117
|
-
</a>
|
118
|
-
</td>
|
119
|
-
<td class="text-end"><%= table[:columns_count] %></td>
|
120
|
-
<td class="text-end"><%= number_with_delimiter(table[:record_count]) %></td>
|
121
|
-
</tr>
|
122
|
-
<% end %>
|
123
|
-
</tbody>
|
124
|
-
</table>
|
125
|
-
</div>
|
126
|
-
<% else %>
|
127
|
-
<div class="text-center my-4 empty-data-message">
|
128
|
-
<p>No table data available</p>
|
129
|
-
</div>
|
130
|
-
<% end %>
|
131
|
-
</div>
|
132
|
-
</div>
|
133
|
-
</div>
|
134
|
-
|
135
|
-
<div class="col-12 mb-4">
|
93
|
+
<div class="col-6 mb-4">
|
136
94
|
<div class="card shadow-sm">
|
137
95
|
<div class="card-header d-flex justify-content-between align-items-center">
|
138
96
|
<h5 class="card-title mb-0">Recent SQL Queries</h5>
|
@@ -141,7 +99,7 @@
|
|
141
99
|
<div class="card-body p-0">
|
142
100
|
<% begin %>
|
143
101
|
<% require_dependency "dbviewer/logger" %>
|
144
|
-
<% queries = Dbviewer::Logger.instance.recent_queries(limit:
|
102
|
+
<% queries = Dbviewer::Logger.instance.recent_queries(limit: 10) %>
|
145
103
|
|
146
104
|
<% if queries.any? %>
|
147
105
|
<div class="table-responsive">
|
@@ -36,7 +36,7 @@
|
|
36
36
|
<thead>
|
37
37
|
<tr>
|
38
38
|
<th>Table Name</th>
|
39
|
-
<th class="text-
|
39
|
+
<th class="text-end">Records</th>
|
40
40
|
<th>Actions</th>
|
41
41
|
</tr>
|
42
42
|
</thead>
|
@@ -46,8 +46,8 @@
|
|
46
46
|
<td class="fw-medium">
|
47
47
|
<%= link_to table[:name], table_path(table[:name]), class: "text-decoration-none" %>
|
48
48
|
</td>
|
49
|
-
<td class="text-
|
50
|
-
<span class="badge bg-secondary-subtle"><%= table[:
|
49
|
+
<td class="text-end">
|
50
|
+
<span class="badge bg-secondary-subtle"><%= table[:record_count] %></span>
|
51
51
|
</td>
|
52
52
|
<td>
|
53
53
|
<%= link_to raw('<i class="bi bi-eye"></i>'), table_path(table[:name]), class: "btn btn-sm btn-outline-primary", title: "View" %>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Dbviewer
|
2
|
+
# CacheManager handles caching concerns for the DatabaseManager
|
3
|
+
# It provides an abstraction layer for managing caches efficiently
|
4
|
+
class CacheManager
|
5
|
+
# Initialize the cache manager
|
6
|
+
# @param config [Dbviewer::Configuration] Configuration object
|
7
|
+
def initialize(config = nil)
|
8
|
+
@config = config || Dbviewer.configuration
|
9
|
+
@dynamic_models = {}
|
10
|
+
@table_columns_cache = {}
|
11
|
+
@table_metadata_cache = {}
|
12
|
+
@cache_last_reset = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get a model from cache or return nil
|
16
|
+
# @param table_name [String] Name of the table
|
17
|
+
# @return [Class, nil] The cached model or nil if not found
|
18
|
+
def get_model(table_name)
|
19
|
+
@dynamic_models[table_name]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Store a model in the cache
|
23
|
+
# @param table_name [String] Name of the table
|
24
|
+
# @param model [Class] ActiveRecord model class
|
25
|
+
def store_model(table_name, model)
|
26
|
+
@dynamic_models[table_name] = model
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get column information from cache
|
30
|
+
# @param table_name [String] Name of the table
|
31
|
+
# @return [Array<Hash>, nil] The cached column information or nil if not found
|
32
|
+
def get_columns(table_name)
|
33
|
+
@table_columns_cache[table_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Store column information in cache
|
37
|
+
# @param table_name [String] Name of the table
|
38
|
+
# @param columns [Array<Hash>] Column information
|
39
|
+
def store_columns(table_name, columns)
|
40
|
+
@table_columns_cache[table_name] = columns
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get table metadata from cache
|
44
|
+
# @param table_name [String] Name of the table
|
45
|
+
# @return [Hash, nil] The cached metadata or nil if not found
|
46
|
+
def get_metadata(table_name)
|
47
|
+
@table_metadata_cache[table_name]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Store table metadata in cache
|
51
|
+
# @param table_name [String] Name of the table
|
52
|
+
# @param metadata [Hash] Table metadata
|
53
|
+
def store_metadata(table_name, metadata)
|
54
|
+
@table_metadata_cache[table_name] = metadata
|
55
|
+
end
|
56
|
+
|
57
|
+
# Reset caches if they've been around too long
|
58
|
+
def reset_if_needed
|
59
|
+
cache_expiry = @config.cache_expiry || 300
|
60
|
+
|
61
|
+
if Time.now - @cache_last_reset > cache_expiry
|
62
|
+
@table_columns_cache = {}
|
63
|
+
@table_metadata_cache = {}
|
64
|
+
@cache_last_reset = Time.now
|
65
|
+
Rails.logger.debug("[DBViewer] Cache reset due to expiry after #{cache_expiry} seconds")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clear all caches - useful when schema changes are detected
|
70
|
+
def clear_all
|
71
|
+
@dynamic_models = {}
|
72
|
+
@table_columns_cache = {}
|
73
|
+
@table_metadata_cache = {}
|
74
|
+
@cache_last_reset = Time.now
|
75
|
+
Rails.logger.debug("[DBViewer] All caches cleared")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -48,32 +48,4 @@ module Dbviewer
|
|
48
48
|
@admin_credentials = nil
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
52
|
-
# Class accessor for configuration
|
53
|
-
class << self
|
54
|
-
attr_accessor :configuration
|
55
|
-
end
|
56
|
-
|
57
|
-
# Configure the engine with a block
|
58
|
-
#
|
59
|
-
# @example
|
60
|
-
# Dbviewer.configure do |config|
|
61
|
-
# config.per_page_options = [10, 25, 50]
|
62
|
-
# config.default_per_page = 25
|
63
|
-
# end
|
64
|
-
def self.configure
|
65
|
-
self.configuration ||= Configuration.new
|
66
|
-
yield(configuration) if block_given?
|
67
|
-
end
|
68
|
-
|
69
|
-
# Reset configuration to defaults
|
70
|
-
def self.reset_configuration
|
71
|
-
self.configuration = Configuration.new
|
72
|
-
end
|
73
|
-
|
74
|
-
# Get the current configuration
|
75
|
-
# Creates a default configuration if none exists
|
76
|
-
def self.configuration
|
77
|
-
@configuration ||= Configuration.new
|
78
|
-
end
|
79
51
|
end
|