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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 563499f106cd48b6fb921b627408e92cf17388416ab8980485e18e4060c2c1e6
|
|
4
|
+
data.tar.gz: 357910264b9a52d1e9c944e5ff53c8be679ec20ebc7bb4cebf5109866396d48b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 **
|
|
5
|
+
Supports **PostgreSQL**, **MySQL**, and **SQLite**.
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|

|
|
@@ -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
|
|
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…</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
|
data/lib/rails_db_inspector.rb
CHANGED
|
@@ -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.
|
|
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,
|
|
28
|
-
visualizes your database schema — all from a
|
|
29
|
-
and
|
|
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: []
|