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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 151a189372c94a737108969cd768ab9dbc4e16a2abc608f07026d1a6b7ee65a5
4
- data.tar.gz: a5fa3a4f4aa8e1acd606f60c2264412a261beec6b6889675ef941d05d1e593cb
3
+ metadata.gz: 65e50cbafa3a2fc1372ce4150c0de4d54001345af9e7d487b048ba3d59929fd2
4
+ data.tar.gz: 3e84c14c32a912f5c447dc2d4525231f83cd2bd272f99a3b4e19261b692ee2c3
5
5
  SHA512:
6
- metadata.gz: e8345197920cf8c6a006d3faecd9a0b9f2a6ef4c972226707203ba43b121e05c3a02195eec4d38a699231ae488741802a9dff5c7317ddc576f4e27381ad897e7
7
- data.tar.gz: b9a8ff1804963de25e85f9a288c198ee4aaa23cf25253ff99f0ce84f3e470e2e35a47c304ff24b2cbd962d9c913fb69b08f11d6bbd2d213af52113ce4d048e18
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 text-center border-0 <%= stat_card_bg_class %>">
19
- <div class="card-body">
20
- <h5 class="mb-1">Tables</h5>
21
- <h2 class="mb-0"><%= @analytics[:total_tables] %></h2>
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 text-center border-0 <%= stat_card_bg_class %>">
28
- <div class="card-body">
29
- <h5 class="mb-1">Records</h5>
30
- <h2 class="mb-0"><%= number_with_delimiter(@analytics[:total_records]) %></h2>
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 text-center border-0 <%= stat_card_bg_class %>">
37
- <div class="card-body">
38
- <h5 class="mb-1">Columns</h5>
39
- <h2 class="mb-0"><%= @analytics[:total_columns] %></h2>
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 text-center border-0 <%= stat_card_bg_class %>">
46
- <div class="card-body">
47
- <h5 class="mb-1">Database Size</h5>
48
- <h2 class="mb-0"><%= number_to_human_size(@analytics[:schema_size]) %></h2>
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>