dbviewer 0.3.6 → 0.3.15
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 +137 -0
- data/app/controllers/dbviewer/tables_controller.rb +34 -0
- data/app/views/dbviewer/home/index.html.erb +37 -16
- data/app/views/dbviewer/tables/mini_erd.html.erb +517 -0
- data/app/views/dbviewer/tables/show.html.erb +566 -21
- data/app/views/layouts/dbviewer/application.html.erb +19 -0
- data/config/routes.rb +1 -0
- data/lib/dbviewer/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65e50cbafa3a2fc1372ce4150c0de4d54001345af9e7d487b048ba3d59929fd2
|
4
|
+
data.tar.gz: 3e84c14c32a912f5c447dc2d4525231f83cd2bd272f99a3b4e19261b692ee2c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d12f7e3bc158c902256ce416e7770d95436deefcb12f7a54673200d06706d57e5368a8ddd2d6ed374c5c64ebe753c82619fa505864b5f002cf805e6d3d11146
|
7
|
+
data.tar.gz: 645d438dd54e867e6f58c2d0e2f1cdc09c49652b97cfd93ce39758440dea8f58e14910a5718d677513762195a5346a225c11fa289597ef6a7b28e4cf75541e2a
|
@@ -65,6 +65,19 @@ module Dbviewer
|
|
65
65
|
empty_tables: tables.select { |t| t[:record_count] == 0 }
|
66
66
|
}
|
67
67
|
|
68
|
+
# Calculate total foreign key relationships
|
69
|
+
begin
|
70
|
+
total_relationships = 0
|
71
|
+
tables.each do |table|
|
72
|
+
metadata = fetch_table_metadata(table[:name])
|
73
|
+
total_relationships += metadata[:foreign_keys].size if metadata && metadata[:foreign_keys]
|
74
|
+
end
|
75
|
+
analytics[:total_relationships] = total_relationships
|
76
|
+
rescue => e
|
77
|
+
Rails.logger.error("Error calculating relationship count: #{e.message}")
|
78
|
+
analytics[:total_relationships] = 0
|
79
|
+
end
|
80
|
+
|
68
81
|
# Calculate schema size if possible
|
69
82
|
begin
|
70
83
|
analytics[:schema_size] = calculate_schema_size
|
@@ -207,6 +220,130 @@ module Dbviewer
|
|
207
220
|
relationships
|
208
221
|
end
|
209
222
|
|
223
|
+
# Get mini ERD data for a specific table and its relationships
|
224
|
+
def fetch_mini_erd_for_table(table_name)
|
225
|
+
related_tables = []
|
226
|
+
relationships = []
|
227
|
+
|
228
|
+
# Validate the table exists
|
229
|
+
unless database_manager.tables.include?(table_name)
|
230
|
+
Rails.logger.error("[DBViewer] Table not found for mini ERD: #{table_name}")
|
231
|
+
return {
|
232
|
+
tables: [],
|
233
|
+
relationships: [],
|
234
|
+
error: "Table '#{table_name}' not found in the database"
|
235
|
+
}
|
236
|
+
end
|
237
|
+
|
238
|
+
# Add current table
|
239
|
+
related_tables << { name: table_name }
|
240
|
+
|
241
|
+
Rails.logger.info("[DBViewer] Generating mini ERD for table: #{table_name}")
|
242
|
+
|
243
|
+
# Get foreign keys from this table to others (outgoing relationships)
|
244
|
+
begin
|
245
|
+
metadata = fetch_table_metadata(table_name)
|
246
|
+
Rails.logger.debug("[DBViewer] Table metadata: #{metadata.inspect}")
|
247
|
+
|
248
|
+
if metadata && metadata[:foreign_keys].present?
|
249
|
+
metadata[:foreign_keys].each do |fk|
|
250
|
+
# Ensure all required fields are present
|
251
|
+
next unless fk[:to_table].present? && fk[:column].present?
|
252
|
+
|
253
|
+
# Sanitize table and column names for display
|
254
|
+
from_table = table_name.to_s
|
255
|
+
to_table = fk[:to_table].to_s
|
256
|
+
from_column = fk[:column].to_s
|
257
|
+
to_column = fk[:primary_key].to_s.presence || "id"
|
258
|
+
relationship_name = fk[:name].to_s.presence || "#{from_table}_to_#{to_table}"
|
259
|
+
|
260
|
+
relationship = {
|
261
|
+
from_table: from_table,
|
262
|
+
to_table: to_table,
|
263
|
+
from_column: from_column,
|
264
|
+
to_column: to_column,
|
265
|
+
name: relationship_name,
|
266
|
+
direction: "outgoing"
|
267
|
+
}
|
268
|
+
|
269
|
+
relationships << relationship
|
270
|
+
Rails.logger.debug("[DBViewer] Added outgoing relationship: #{relationship.inspect}")
|
271
|
+
|
272
|
+
# Add the related table if not already included
|
273
|
+
unless related_tables.any? { |t| t[:name] == to_table }
|
274
|
+
related_tables << { name: to_table }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
rescue => e
|
279
|
+
Rails.logger.error("[DBViewer] Error fetching outgoing relationships for #{table_name}: #{e.message}")
|
280
|
+
Rails.logger.error(e.backtrace.join("\n"))
|
281
|
+
end
|
282
|
+
|
283
|
+
# Get foreign keys from other tables to this one (incoming relationships)
|
284
|
+
begin
|
285
|
+
database_manager.tables.each do |other_table_name|
|
286
|
+
next if other_table_name == table_name # Skip self
|
287
|
+
|
288
|
+
begin
|
289
|
+
other_metadata = fetch_table_metadata(other_table_name)
|
290
|
+
if other_metadata && other_metadata[:foreign_keys].present?
|
291
|
+
other_metadata[:foreign_keys].each do |fk|
|
292
|
+
if fk[:to_table] == table_name
|
293
|
+
# Ensure all required fields are present
|
294
|
+
next unless fk[:column].present?
|
295
|
+
|
296
|
+
# Sanitize table and column names for display
|
297
|
+
from_table = other_table_name.to_s
|
298
|
+
to_table = table_name.to_s
|
299
|
+
from_column = fk[:column].to_s
|
300
|
+
to_column = fk[:primary_key].to_s.presence || "id"
|
301
|
+
relationship_name = fk[:name].to_s.presence || "#{from_table}_to_#{to_table}"
|
302
|
+
|
303
|
+
relationship = {
|
304
|
+
from_table: from_table,
|
305
|
+
to_table: to_table,
|
306
|
+
from_column: from_column,
|
307
|
+
to_column: to_column,
|
308
|
+
name: relationship_name,
|
309
|
+
direction: "incoming"
|
310
|
+
}
|
311
|
+
|
312
|
+
relationships << relationship
|
313
|
+
Rails.logger.debug("[DBViewer] Added incoming relationship: #{relationship.inspect}")
|
314
|
+
|
315
|
+
# Add the related table if not already included
|
316
|
+
unless related_tables.any? { |t| t[:name] == from_table }
|
317
|
+
related_tables << { name: from_table }
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
rescue => e
|
323
|
+
Rails.logger.error("[DBViewer] Error processing relationships for table #{other_table_name}: #{e.message}")
|
324
|
+
# Continue to the next table
|
325
|
+
end
|
326
|
+
end
|
327
|
+
rescue => e
|
328
|
+
Rails.logger.error("[DBViewer] Error fetching incoming relationships for #{table_name}: #{e.message}")
|
329
|
+
Rails.logger.error(e.backtrace.join("\n"))
|
330
|
+
end
|
331
|
+
|
332
|
+
# If no relationships were found, make sure to still include at least the current table
|
333
|
+
if relationships.empty?
|
334
|
+
Rails.logger.info("[DBViewer] No relationships found for table: #{table_name}")
|
335
|
+
end
|
336
|
+
|
337
|
+
result = {
|
338
|
+
tables: related_tables,
|
339
|
+
relationships: relationships,
|
340
|
+
timestamp: Time.now.to_i
|
341
|
+
}
|
342
|
+
|
343
|
+
Rails.logger.info("[DBViewer] Mini ERD data generated: #{related_tables.length} tables, #{relationships.length} relationships")
|
344
|
+
result
|
345
|
+
end
|
346
|
+
|
210
347
|
# Prepare the SQL query - either from params or default
|
211
348
|
def prepare_query
|
212
349
|
quoted_table = safe_quote_table_name(@table_name)
|
@@ -27,6 +27,12 @@ module Dbviewer
|
|
27
27
|
@total_pages = calculate_total_pages(@total_count, @per_page)
|
28
28
|
@records = fetch_table_records(@table_name)
|
29
29
|
|
30
|
+
# Ensure @records is never nil to prevent template errors
|
31
|
+
if @records.nil?
|
32
|
+
column_names = fetch_table_columns(@table_name).map { |c| c[:name] }
|
33
|
+
@records = ActiveRecord::Result.new(column_names, [])
|
34
|
+
end
|
35
|
+
|
30
36
|
# Fetch timestamp visualization data if the table has a created_at column
|
31
37
|
if has_timestamp_column?(@table_name)
|
32
38
|
@time_grouping = params[:time_group] || "daily"
|
@@ -46,6 +52,34 @@ module Dbviewer
|
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
55
|
+
def mini_erd
|
56
|
+
@table_name = params[:id]
|
57
|
+
|
58
|
+
begin
|
59
|
+
@erd_data = fetch_mini_erd_for_table(@table_name)
|
60
|
+
|
61
|
+
if @erd_data[:error].present?
|
62
|
+
Rails.logger.error("Mini ERD error: #{@erd_data[:error]}")
|
63
|
+
end
|
64
|
+
|
65
|
+
respond_to do |format|
|
66
|
+
format.json { render json: @erd_data }
|
67
|
+
format.html { render layout: false }
|
68
|
+
end
|
69
|
+
rescue => e
|
70
|
+
Rails.logger.error("Error generating Mini ERD: #{e.message}")
|
71
|
+
Rails.logger.error(e.backtrace.join("\n"))
|
72
|
+
|
73
|
+
@error_message = e.message
|
74
|
+
@erd_data = { tables: [], relationships: [], error: @error_message }
|
75
|
+
|
76
|
+
respond_to do |format|
|
77
|
+
format.json { render json: { error: @error_message }, status: :internal_server_error }
|
78
|
+
format.html { render layout: false }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
49
83
|
def query
|
50
84
|
@table_name = params[:id]
|
51
85
|
@read_only_mode = true # Flag to indicate we're in read-only mode
|
@@ -15,37 +15,58 @@
|
|
15
15
|
|
16
16
|
<div class="row g-3 mb-4">
|
17
17
|
<div class="col-md-3">
|
18
|
-
<div class="card h-100
|
19
|
-
<div class="card-body">
|
20
|
-
<
|
21
|
-
|
18
|
+
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
19
|
+
<div class="card-body d-flex align-items-center">
|
20
|
+
<div class="metric-icon me-3">
|
21
|
+
<i class="bi bi-table fs-4"></i>
|
22
|
+
</div>
|
23
|
+
<div class="text-start">
|
24
|
+
<h5 class="mb-1">Tables</h5>
|
25
|
+
<h2 class="mb-0"><%= @analytics[:total_tables] %></h2>
|
26
|
+
</div>
|
22
27
|
</div>
|
23
28
|
</div>
|
24
29
|
</div>
|
25
30
|
|
26
31
|
<div class="col-md-3">
|
27
|
-
<div class="card h-100
|
28
|
-
<div class="card-body">
|
29
|
-
<
|
30
|
-
|
32
|
+
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
33
|
+
<div class="card-body d-flex align-items-center">
|
34
|
+
<div class="metric-icon me-3">
|
35
|
+
<i class="bi bi-database fs-4"></i>
|
36
|
+
</div>
|
37
|
+
<div class="text-start">
|
38
|
+
<h5 class="mb-1">Records</h5>
|
39
|
+
<h2 class="mb-0"><%= number_with_delimiter(@analytics[:total_records]) %></h2>
|
40
|
+
</div>
|
31
41
|
</div>
|
32
42
|
</div>
|
33
43
|
</div>
|
34
44
|
|
35
45
|
<div class="col-md-3">
|
36
|
-
<div class="card h-100
|
37
|
-
<div class="card-body">
|
38
|
-
<
|
39
|
-
|
46
|
+
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
47
|
+
<div class="card-body d-flex align-items-center">
|
48
|
+
<div class="metric-icon me-3">
|
49
|
+
<i class="bi bi-link-45deg fs-4"></i>
|
50
|
+
</div>
|
51
|
+
<div class="text-start">
|
52
|
+
<h5 class="mb-1">Relationships</h5>
|
53
|
+
<h2 class="mb-0"><%= @analytics[:total_relationships] %></h2>
|
54
|
+
<small class="text-muted d-block">Foreign Key Connections</small>
|
55
|
+
</div>
|
40
56
|
</div>
|
41
57
|
</div>
|
42
58
|
</div>
|
43
59
|
|
44
60
|
<div class="col-md-3">
|
45
|
-
<div class="card h-100
|
46
|
-
<div class="card-body">
|
47
|
-
<
|
48
|
-
|
61
|
+
<div class="card h-100 border-0 shadow-sm <%= stat_card_bg_class %>">
|
62
|
+
<div class="card-body d-flex align-items-center">
|
63
|
+
<div class="metric-icon me-3">
|
64
|
+
<i class="bi bi-hdd fs-4"></i>
|
65
|
+
</div>
|
66
|
+
<div class="text-start">
|
67
|
+
<h5 class="mb-1">Database Size</h5>
|
68
|
+
<h2 class="mb-0"><%= number_to_human_size(@analytics[:schema_size]) %></h2>
|
69
|
+
</div>
|
49
70
|
</div>
|
50
71
|
</div>
|
51
72
|
</div>
|