rails_db_inspector 0.3.0 → 0.5.0

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: 5a2301258a71ef2726b47b18829dab86405d253cd0b093c262d00d986e8cef26
4
- data.tar.gz: d343bba0f9d5235aeb9ad7c2747ffb21f284114142387bf0e3394cb5374220d0
3
+ metadata.gz: 563499f106cd48b6fb921b627408e92cf17388416ab8980485e18e4060c2c1e6
4
+ data.tar.gz: 357910264b9a52d1e9c944e5ff53c8be679ec20ebc7bb4cebf5109866396d48b
5
5
  SHA512:
6
- metadata.gz: 0cd3029c26cce165f89f5834878968688240380c37461f8b0b988fc5ebe5566bfb9cdd2ab1fe3f38f3856fb90580b72627d7f2ceb4607e5fbd31d2f8118cac44
7
- data.tar.gz: a04e479dd6955d4d4d309f79f2911c321c06c753e53272bc2e64c99d0ad93707ed7f57b9918f68071b7d2898492551663c365f3fdb2eae3758f9bf7b5e1c2b76
6
+ metadata.gz: accc48fc04b30608198e8b02238a6bdc49de9b75936b60521a5002edfeef2c3bd98b9beb8e6afc63b2f9e9815838bde4dc4055f0addf27c814855c9178d30298
7
+ data.tar.gz: 25e5c3919cbbdf126c4f4ff6186b7abe10fb97fb8ade2a28c589de7249a2d7edc1370848ab9c29316906a69e7ade51827b03c6b0a20a595f43b0ddf8f362aa07
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A mountable Rails engine that gives you a built-in dashboard for **SQL query monitoring**, **N+1 detection**, **EXPLAIN / EXPLAIN ANALYZE plans**, and **interactive schema visualization** — no external services required.
4
4
 
5
- Supports **PostgreSQL** and **MySQL**.
5
+ Supports **PostgreSQL**, **MySQL**, and **SQLite**.
6
6
 
7
7
  ![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.1-red)
8
8
  ![Rails](https://img.shields.io/badge/rails-%3E%3D%207.1-red)
@@ -18,7 +18,7 @@ Supports **PostgreSQL** and **MySQL**.
18
18
  - **Real-time SQL Query Capture** — every query your app executes is logged with SQL text, duration, bind parameters, and timestamps
19
19
  - **N+1 Query Detection** — automatically identifies repeated query patterns and highlights the worst offenders
20
20
  - **Query Grouping** — queries are grouped by controller action using Rails marginal annotations
21
- - **EXPLAIN Plans** — run `EXPLAIN` on any captured query to see the execution plan (PostgreSQL JSON format, MySQL tabular)
21
+ - **EXPLAIN Plans** — run `EXPLAIN` on any captured query to see the execution plan (PostgreSQL JSON format, MySQL tabular, SQLite QUERY PLAN)
22
22
  - **EXPLAIN ANALYZE** — optionally run `EXPLAIN ANALYZE` to get real execution statistics, buffer usage, and timing (opt-in, SELECT only)
23
23
  - **Plan Analysis** — rich visual rendering of PostgreSQL plans including cost breakdown, row estimate accuracy, index usage analysis, performance hotspots, buffer statistics, and actionable recommendations
24
24
  - **Interactive Schema / ERD Visualization** — drag-and-drop entity relationship diagram with pan, zoom, search, column expansion, heat-map by row count, missing index warnings, polymorphic detection, and SVG export
@@ -185,9 +185,9 @@ The widget is automatically injected via Rack middleware and only appears in `de
185
185
  |------------|---------|-----------------|--------------|
186
186
  | PostgreSQL | ✅ | ✅ | ✅ |
187
187
  | MySQL | ✅ | ✅ | ✅ |
188
- | SQLite | | | ✅ |
188
+ | SQLite | | | ✅ |
189
189
 
190
- EXPLAIN uses `FORMAT JSON` for PostgreSQL and standard `EXPLAIN` for MySQL.
190
+ EXPLAIN uses `FORMAT JSON` for PostgreSQL, standard `EXPLAIN` for MySQL, and `EXPLAIN QUERY PLAN` for SQLite.
191
191
 
192
192
  ---
193
193
 
@@ -98,6 +98,15 @@
98
98
  #heat-legend { position: absolute; bottom: 48px; left: 12px; display: flex; align-items: center; gap: 4px; font-size: 10px; color: #9ca3af; z-index: 50; background: rgba(255,255,255,0.9); padding: 4px 8px; border-radius: 6px; border: 1px solid #e5e7eb; }
99
99
  #heat-legend .heat-swatch { width: 12px; height: 10px; border-radius: 2px; }
100
100
 
101
+ /* Loading overlay */
102
+ #schema-loading { position: absolute; inset: 0; background: rgba(248,250,252,0.92); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 200; transition: opacity 0.4s ease; }
103
+ #schema-loading.fade-out { opacity: 0; pointer-events: none; }
104
+ #schema-loading .spinner { width: 36px; height: 36px; border: 3px solid #e5e7eb; border-top-color: #3b82f6; border-radius: 50%; animation: spin 0.8s linear infinite; }
105
+ @keyframes spin { to { transform: rotate(360deg); } }
106
+ #schema-loading .load-label { margin-top: 14px; font-size: 13px; font-weight: 500; color: #6b7280; }
107
+ #schema-loading .load-timer { margin-top: 4px; font-size: 22px; font-weight: 700; font-family: ui-monospace, monospace; color: #374151; letter-spacing: 0.02em; }
108
+ #schema-loading .load-sub { margin-top: 6px; font-size: 11px; color: #9ca3af; }
109
+
101
110
  </style>
102
111
  <% end %>
103
112
 
@@ -117,6 +126,14 @@
117
126
  <svg id="schema-svg"></svg>
118
127
  <div id="schema-canvas"></div>
119
128
 
129
+ <!-- Loading Overlay -->
130
+ <div id="schema-loading">
131
+ <div class="spinner"></div>
132
+ <div class="load-label">Laying out schema&hellip;</div>
133
+ <div class="load-timer" id="load-timer">0.0s</div>
134
+ <div class="load-sub" id="load-table-count"></div>
135
+ </div>
136
+
120
137
  <!-- Detail Panel -->
121
138
  <div id="detail-panel">
122
139
  <div class="detail-header">
@@ -491,9 +508,36 @@
491
508
  return { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y };
492
509
  }
493
510
 
511
+ // Loading overlay / timer
512
+ var loadingOverlay = document.getElementById('schema-loading');
513
+ var loadTimerEl = document.getElementById('load-timer');
514
+ var loadTableCountEl = document.getElementById('load-table-count');
515
+ var loadStart = performance.now();
516
+ var loadingDone = false;
517
+
518
+ loadTableCountEl.textContent = tableNames.length + ' tables \u00B7 ' + relationships.length + ' relationships';
519
+
520
+ function updateLoadTimer() {
521
+ if (loadingDone) return;
522
+ var elapsed = ((performance.now() - loadStart) / 1000).toFixed(1);
523
+ loadTimerEl.textContent = elapsed + 's';
524
+ requestAnimationFrame(updateLoadTimer);
525
+ }
526
+ requestAnimationFrame(updateLoadTimer);
527
+
528
+ function hideLoading() {
529
+ if (loadingDone) return;
530
+ loadingDone = true;
531
+ var elapsed = ((performance.now() - loadStart) / 1000).toFixed(1);
532
+ loadTimerEl.textContent = elapsed + 's';
533
+ loadingOverlay.classList.add('fade-out');
534
+ setTimeout(function() { loadingOverlay.style.display = 'none'; }, 500);
535
+ }
536
+
494
537
  // Animation loop
495
538
  function tick() {
496
539
  simulate();
540
+ if (!loadingDone && simAlpha < 0.01) hideLoading();
497
541
  requestAnimationFrame(tick);
498
542
  }
499
543
  tick();
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsDbInspector
4
+ class Explain
5
+ class Sqlite
6
+ def initialize(connection)
7
+ @connection = connection
8
+ end
9
+
10
+ def explain(sql, analyze: false)
11
+ # Strip any existing EXPLAIN prefix to prevent doubling
12
+ clean_sql = sql.sub(/\A\s*EXPLAIN\s*(QUERY\s+PLAN)?\s*/i, "")
13
+
14
+ statement =
15
+ if analyze
16
+ RailsDbInspector::Explain.select_only!(clean_sql)
17
+ "EXPLAIN QUERY PLAN #{clean_sql}"
18
+ else
19
+ "EXPLAIN QUERY PLAN #{clean_sql}"
20
+ end
21
+
22
+ result = @connection.exec_query(statement)
23
+
24
+ plan = result.rows.map do |row|
25
+ {
26
+ "id" => row[0],
27
+ "parent" => row[1],
28
+ "notused" => row[2],
29
+ "detail" => row[3]
30
+ }
31
+ end
32
+
33
+ { adapter: "sqlite", analyze: analyze, columns: result.columns, rows: result.rows, plan: plan }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -13,6 +13,8 @@ module RailsDbInspector
13
13
  RailsDbInspector::Explain::Postgres.new(connection)
14
14
  when /mysql/
15
15
  RailsDbInspector::Explain::MySql.new(connection)
16
+ when /sqlite/
17
+ RailsDbInspector::Explain::Sqlite.new(connection)
16
18
  else
17
19
  raise UnsupportedAdapter, "Unsupported adapter: #{connection.adapter_name}"
18
20
  end
@@ -1,3 +1,3 @@
1
1
  module RailsDbInspector
2
- VERSION = "0.3.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -8,6 +8,7 @@ require_relative "rails_db_inspector/sql_subscriber"
8
8
  require_relative "rails_db_inspector/explain"
9
9
  require_relative "rails_db_inspector/explain/postgres"
10
10
  require_relative "rails_db_inspector/explain/my_sql"
11
+ require_relative "rails_db_inspector/explain/sqlite"
11
12
  require_relative "rails_db_inspector/schema_inspector"
12
13
 
13
14
  module RailsDbInspector
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_db_inspector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - samuel-murphy
@@ -24,9 +24,9 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: '7.1'
26
26
  description: Rails DB Inspector is a mountable Rails engine that captures SQL queries
27
- in real time, detects N+1 query patterns, runs EXPLAIN/EXPLAIN ANALYZE plans, and
28
- visualizes your database schema — all from a built-in dashboard. Supports PostgreSQL
29
- and MySQL.
27
+ in real time, detects N+1 query patterns, runs EXPLAIN/EXPLAIN ANALYZE plans, suggests
28
+ missing and redundant indexes, and visualizes your database schema — all from a
29
+ built-in dashboard. Supports PostgreSQL, MySQL, and SQLite.
30
30
  email:
31
31
  - samuelmurphy15@gmail.com
32
32
  executables: []
@@ -58,6 +58,7 @@ files:
58
58
  - lib/rails_db_inspector/explain.rb
59
59
  - lib/rails_db_inspector/explain/my_sql.rb
60
60
  - lib/rails_db_inspector/explain/postgres.rb
61
+ - lib/rails_db_inspector/explain/sqlite.rb
61
62
  - lib/rails_db_inspector/query_store.rb
62
63
  - lib/rails_db_inspector/schema_inspector.rb
63
64
  - lib/rails_db_inspector/sql_subscriber.rb
@@ -87,5 +88,5 @@ requirements: []
87
88
  rubygems_version: 4.0.3
88
89
  specification_version: 4
89
90
  summary: Mountable Rails engine for SQL query monitoring, N+1 detection, EXPLAIN analysis,
90
- and schema visualization.
91
+ smart index suggestions, and schema visualization.
91
92
  test_files: []