sql_genius 0.9.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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +195 -0
  3. data/LICENSE.txt +65 -0
  4. data/README.md +178 -0
  5. data/Rakefile +8 -0
  6. data/app/controllers/concerns/sql_genius/ai_features.rb +332 -0
  7. data/app/controllers/concerns/sql_genius/database_analysis.rb +67 -0
  8. data/app/controllers/concerns/sql_genius/query_execution.rb +87 -0
  9. data/app/controllers/concerns/sql_genius/shared_view_helpers.rb +76 -0
  10. data/app/controllers/sql_genius/base_controller.rb +29 -0
  11. data/app/controllers/sql_genius/queries_controller.rb +94 -0
  12. data/app/views/layouts/sql_genius/application.html.erb +285 -0
  13. data/config/routes.rb +34 -0
  14. data/docs/guides/ai-features.md +115 -0
  15. data/docs/guides/getting-started-rails.md +118 -0
  16. data/docs/guides/ssh-tunnel-connections.md +151 -0
  17. data/docs/screenshots/ai_tools.png +0 -0
  18. data/docs/screenshots/dashboard.png +0 -0
  19. data/docs/screenshots/duplicate_indexes.png +0 -0
  20. data/docs/screenshots/query_explore.png +0 -0
  21. data/docs/screenshots/query_stats.png +0 -0
  22. data/docs/screenshots/server.png +0 -0
  23. data/docs/screenshots/table_sizes.png +0 -0
  24. data/lib/generators/sql_genius/install/install_generator.rb +19 -0
  25. data/lib/generators/sql_genius/install/templates/initializer.rb +56 -0
  26. data/lib/sql_genius/configuration.rb +114 -0
  27. data/lib/sql_genius/core/ai/client.rb +155 -0
  28. data/lib/sql_genius/core/ai/config.rb +47 -0
  29. data/lib/sql_genius/core/ai/connection_advisor.rb +96 -0
  30. data/lib/sql_genius/core/ai/describe_query.rb +41 -0
  31. data/lib/sql_genius/core/ai/dialect_hints.rb +35 -0
  32. data/lib/sql_genius/core/ai/index_advisor.rb +43 -0
  33. data/lib/sql_genius/core/ai/index_planner.rb +91 -0
  34. data/lib/sql_genius/core/ai/innodb_interpreter.rb +78 -0
  35. data/lib/sql_genius/core/ai/migration_risk.rb +51 -0
  36. data/lib/sql_genius/core/ai/optimization.rb +81 -0
  37. data/lib/sql_genius/core/ai/pattern_grouper.rb +94 -0
  38. data/lib/sql_genius/core/ai/rewrite_query.rb +51 -0
  39. data/lib/sql_genius/core/ai/schema_context_builder.rb +82 -0
  40. data/lib/sql_genius/core/ai/schema_review.rb +46 -0
  41. data/lib/sql_genius/core/ai/suggestion.rb +74 -0
  42. data/lib/sql_genius/core/ai/variable_reviewer.rb +113 -0
  43. data/lib/sql_genius/core/ai/workload_digest.rb +86 -0
  44. data/lib/sql_genius/core/analysis/columns.rb +63 -0
  45. data/lib/sql_genius/core/analysis/duplicate_indexes.rb +85 -0
  46. data/lib/sql_genius/core/analysis/query_history.rb +50 -0
  47. data/lib/sql_genius/core/analysis/query_stats.rb +76 -0
  48. data/lib/sql_genius/core/analysis/server_overview.rb +294 -0
  49. data/lib/sql_genius/core/analysis/stats_collector.rb +118 -0
  50. data/lib/sql_genius/core/analysis/stats_history.rb +42 -0
  51. data/lib/sql_genius/core/analysis/table_sizes.rb +52 -0
  52. data/lib/sql_genius/core/analysis/unused_indexes.rb +62 -0
  53. data/lib/sql_genius/core/column_definition.rb +30 -0
  54. data/lib/sql_genius/core/connection/active_record_adapter.rb +75 -0
  55. data/lib/sql_genius/core/connection/fake_adapter.rb +114 -0
  56. data/lib/sql_genius/core/connection.rb +37 -0
  57. data/lib/sql_genius/core/execution_result.rb +27 -0
  58. data/lib/sql_genius/core/index_definition.rb +23 -0
  59. data/lib/sql_genius/core/query_builders/mysql.rb +169 -0
  60. data/lib/sql_genius/core/query_builders/postgresql.rb +185 -0
  61. data/lib/sql_genius/core/query_builders.rb +27 -0
  62. data/lib/sql_genius/core/query_explainer.rb +113 -0
  63. data/lib/sql_genius/core/query_runner/config.rb +21 -0
  64. data/lib/sql_genius/core/query_runner.rb +123 -0
  65. data/lib/sql_genius/core/result.rb +43 -0
  66. data/lib/sql_genius/core/server_info.rb +54 -0
  67. data/lib/sql_genius/core/sql_validator.rb +149 -0
  68. data/lib/sql_genius/core/views/sql_genius/queries/_shared_results.html.erb +59 -0
  69. data/lib/sql_genius/core/views/sql_genius/queries/_tab_ai_tools.html.erb +43 -0
  70. data/lib/sql_genius/core/views/sql_genius/queries/_tab_dashboard.html.erb +97 -0
  71. data/lib/sql_genius/core/views/sql_genius/queries/_tab_duplicate_indexes.html.erb +35 -0
  72. data/lib/sql_genius/core/views/sql_genius/queries/_tab_query_explorer.html.erb +110 -0
  73. data/lib/sql_genius/core/views/sql_genius/queries/_tab_query_stats.html.erb +43 -0
  74. data/lib/sql_genius/core/views/sql_genius/queries/_tab_server.html.erb +59 -0
  75. data/lib/sql_genius/core/views/sql_genius/queries/_tab_slow_queries.html.erb +17 -0
  76. data/lib/sql_genius/core/views/sql_genius/queries/_tab_table_sizes.html.erb +33 -0
  77. data/lib/sql_genius/core/views/sql_genius/queries/_tab_unused_indexes.html.erb +54 -0
  78. data/lib/sql_genius/core/views/sql_genius/queries/dashboard.html.erb +1826 -0
  79. data/lib/sql_genius/core/views/sql_genius/queries/query_detail.html.erb +465 -0
  80. data/lib/sql_genius/core.rb +72 -0
  81. data/lib/sql_genius/engine.rb +31 -0
  82. data/lib/sql_genius/slow_query_monitor.rb +43 -0
  83. data/lib/sql_genius/version.rb +5 -0
  84. data/lib/sql_genius.rb +29 -0
  85. data/sql_genius.gemspec +47 -0
  86. metadata +171 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f20a1a129d62d967470cbf11082c11772b3e2f8a8041a8d3de7edefd7e2f789c
4
+ data.tar.gz: ce514b35658ebfbebff2b7d7b11a29da096dfd8e01082c0c3aad3ed7e1081eae
5
+ SHA512:
6
+ metadata.gz: 8effd028d592666cc4054f505c85969e2f908fd2775909f0cfcc48f91e5fbf726bdbdaf25b1d1ad0f62f4baa1f4db90a9c126feeb0442b7d000d183ef17b28f1
7
+ data.tar.gz: be54e67e85e4c12aa52264c46946328d94400513c308032d82dabbe29fe48e95e016adef010ea9602b58a66371fc065a929a0d0fb786e4e3ae4f4f9fb452e114
data/CHANGELOG.md ADDED
@@ -0,0 +1,195 @@
1
+ # Changelog
2
+
3
+ ## 0.9.0
4
+
5
+ ### Added
6
+ - **PostgreSQL support across the dashboard.** Analyses (table sizes, query stats, unused indexes, server overview, duplicate indexes, query history) and the query detail page now run against PostgreSQL in addition to MySQL/MariaDB. Dialect is detected automatically from the `ActiveRecord::Base.connection`.
7
+ - `SqlGenius::Core::QueryBuilders` — dialect-aware SQL generation layer with two builders (`Mysql` covering MySQL/MariaDB, `Postgresql`). Analyses delegate SQL generation through it.
8
+ - `SqlGenius::Core::Analysis::QueryHistory` — single-digest stats lookup used by the query detail page; reads `pg_stat_statements` on PG, `performance_schema.events_statements_summary_by_digest` on MySQL.
9
+ - `SqlGenius::Core::Analysis::DuplicateIndexes` now includes a `drop_sql` field per result (`ALTER TABLE ... DROP INDEX` on MySQL, `DROP INDEX IF EXISTS "..."` on PG). The dashboard JS uses this instead of assembling MySQL syntax client-side.
10
+ - `SqlGenius::Core::UnsupportedDialect` error class. `VariableReviewer`, `ConnectionAdvisor`, and `InnodbInterpreter` raise it on PG so the UI surfaces a clear "MySQL/MariaDB-only" message instead of a raw `PG::SyntaxError`. Controller-side `root_cause` and `anomaly_detection` short-circuit on PG with the same kind of error.
11
+ - `Core::ServerInfo` recognises `:postgresql` as a vendor; exposes `#postgresql?` and `#dialect`.
12
+ - `Core::QueryRunner` issues `SET statement_timeout = ms` (and resets to 0 in an `ensure` block) on PostgreSQL; recognises `canceling statement due to statement timeout` as a timeout error.
13
+ - `Core::SqlValidator` blocks PG system schemas (`pg_catalog`, `pg_toast`, `pg_temp`) and parses double-quoted identifiers.
14
+
15
+ ### Changed
16
+ - The gem and public brand now use `sql_genius` / `SqlGenius`. The default mount path, install generator, initializer path, require paths, GitHub links, and RubyGems publishing workflow now use the new name.
17
+ - **`sql_genius-core` has been merged back into the main `sql_genius` gem.** The split was originally added to support a planned desktop app; with that path discontinued, the two gems become one. Host apps no longer need `gem "sql_genius-core"` in their Gemfile — it's gone, and the runtime dependency in `sql_genius.gemspec` is gone too. The `SqlGenius::Core::*` namespace is preserved, so all existing `require` paths and constant lookups continue to work unchanged.
18
+ - `ActiveRecordAdapter#server_version` is memoized — dialect detection runs `SELECT VERSION()` at most once per adapter instance.
19
+ - Tab header text in Tables / Query Stats / Unused Indexes no longer mentions `performance_schema` / `information_schema` by name.
20
+
21
+ ### Removed
22
+ - The `sql_genius-desktop` gem stub. Desktop sidecar / macOS DMG packaging scripts (`packaging/macos/`) are removed; they only assembled the now-deleted gem.
23
+ - `SqlGenius::Core::VERSION` constant. Use `SqlGenius::VERSION`.
24
+
25
+ ### Unused Indexes: PgHero-style context
26
+ - `GET /sql_genius/unused_indexes` now returns `{ indexes: [...], stats_reset_at, min_scans }` instead of a bare array. The Unused Indexes tab shows "Stats last reset N ago · threshold: scans ≤ M" above the table so an empty/fresh stats source doesn't read as "everything is unused."
27
+ - New `config.min_unused_index_scans` (default 0 — PgHero parity). Raise it (e.g. 50) to ignore indexes that are technically used but rarely enough to consider dropping.
28
+ - The PG query now sorts results by index byte size DESC (largest first — biggest wins). Each result hash carries a `size_bytes` field; the table shows a Size column. `pg_relation_size` is the source.
29
+ - Removed the `c.reltuples > 0` filter so indexes on empty tables show up too (matches PgHero — empty tables with indexes are still actionable noise).
30
+
31
+ ### Notes
32
+ - PostgreSQL query stats require the `pg_stat_statements` extension to be installed and enabled (`shared_preload_libraries`).
33
+ - Slow query log capture remains MySQL-only.
34
+
35
+ ## 0.8.1
36
+
37
+ ### Fixed
38
+ - **Older MySQL compatibility** — the `DIGEST` column in `performance_schema.events_statements_summary_by_digest` is not present on all MySQL/MariaDB versions. `QueryStats` now checks for column existence before including it in the SELECT. Query links in the Query Stats tab gracefully degrade to plain text when the digest is unavailable.
39
+
40
+ ## 0.8.0
41
+
42
+ ### Added
43
+ - **6 new AI analysis features:**
44
+ - **Variable Config Reviewer** — reviews my.cnf settings against observed workload
45
+ - **Connection Pressure Advisor** — diagnoses connection pool health
46
+ - **Workload Digest** — executive summary of the entire query workload
47
+ - **InnoDB Health Interpreter** — plain English translation of `SHOW ENGINE INNODB STATUS`
48
+ - **Index Consolidation Planner** — holistic drop/merge/add index plan across tables
49
+ - **Slow Query Pattern Grouper** — groups slow queries by shared root cause
50
+ - AI buttons added to Server tab, Query Stats tab, and Indexes tabs
51
+ - `sql_genius` now declares runtime dependency on `sql_genius-core ~> 0.8.0`
52
+
53
+ ## 0.7.2
54
+
55
+ ### Added
56
+ - **Anthropic Messages API support** — `x-api-key` auth style with `anthropic-version` header, top-level `system` parameter, `content[0].text` response parsing.
57
+ - **Configurable `max_tokens`** — new field on `Core::Ai::Config` (default 4096), sent to both OpenAI and Anthropic APIs.
58
+ - **Copy response button** on all AI result sections (schema review, migration risk, optimization, describe query, rewrite, index advisor, root cause, anomaly detection).
59
+ - **Dark mode contrast fixes** for AI result sections — proper CSS classes with dark-mode variants replace hardcoded light-mode inline styles.
60
+ - **`capability?(:standalone_header)`** guard hides the dashboard header when rendered inside a layout that already provides one.
61
+
62
+ ## 0.7.1
63
+
64
+ Lockstep version bump with `sql_genius-core 0.7.1` which fixes missing ERB templates in the gem package.
65
+
66
+ ## 0.7.0
67
+
68
+ ### Added
69
+ - **`capability?(name)` helper** in `SharedViewHelpers`. The Rails adapter returns `true` for all capabilities; the desktop sidecar uses it to hide Redis-backed features (slow_queries, anomaly_detection, root_cause) from the shared dashboard templates.
70
+ - **Query detail page** at `GET /queries/:digest` with syntax-highlighted SQL, Explain button, aggregate stats cards, and three inline SVG time-series charts (Total Time, Average Time, Calls).
71
+ - **`Core::Analysis::StatsHistory`** — thread-safe in-memory ring buffer for per-digest query stats snapshots (24hr retention at 60s intervals).
72
+ - **`Core::Analysis::StatsCollector`** — background thread that samples `performance_schema.events_statements_summary_by_digest` every 60s, computes deltas, and records to StatsHistory.
73
+ - **`DIGEST` hash** added to `Core::Analysis::QueryStats` return value for stable URL keys.
74
+ - **Stats collection config option** (`stats_collection`, default `true`) — controls whether the background collector starts on boot.
75
+ - **Query Stats tab linkification** — SQL cells in the Query Stats table are now clickable links to the query detail page.
76
+ - `sql_genius` now declares runtime dependency on `sql_genius-core ~> 0.7.0`.
77
+
78
+ ## 0.6.0
79
+
80
+ ### Changed
81
+ - **Dropped Rails 5.2 support.** The gemspec floor is now Rails 6.0 (`activerecord`/`railties` constraint is `">= 6.0", "< 9"`). Rails 5.2 has been end-of-life since June 2022 and its incompatibilities with modern Rack (`ActionDispatch::Static#initialize` arity mismatch, `MiddlewareStack#operations` removal) started surfacing as CI failures once Phase 2a's integration specs booted Rails in test. Pin `sql_genius 0.5.0` (`gem "sql_genius", "~> 0.5.0"`) if you can't upgrade Rails yet.
82
+ - `sql_genius` now declares runtime dependency on `sql_genius-core ~> 0.6.0` (was `~> 0.5.0`).
83
+
84
+ ### Fixed
85
+ - **CI matrix: Ruby 3.x + Rails 5.2/6.0/6.1 compatibility.** `spec/rails_helper.rb` and `spec/dummy/config/application.rb` now explicitly `require "logger"` before loading Rails. Works around a `Logger::Severity` reference inside `ActiveSupport::LoggerThreadSafeLevel` that fails on Ruby 3.x + older Rails because Logger is no longer autoloaded in modern Ruby. Only affects the test suite; no runtime impact on host apps.
86
+
87
+ ### Internal
88
+ - **`rails_connection` consolidated into `BaseController`.** Nine inline `SqlGenius::Core::Connection::ActiveRecordAdapter.new(ActiveRecord::Base.connection)` call sites in the three controller concerns, plus two separate private helper definitions in `QueriesController` and `AiFeatures`, collapse to one private method on `BaseController`. Shared across all concerns via Ruby's standard method lookup.
89
+ - **`ai_domain_context` helper inlined and deleted.** Its two remaining callers (`anomaly_detection` and `root_cause`) now compute a local `domain_ctx` string before building their message array.
90
+ - **`fake_result(columns:, rows:, to_a:)` test helper extracted** into `spec/support/fake_connection.rb` alongside `fake_column`. Four duplicated `instance_double("ActiveRecord::Result", columns:, rows:, to_a:)` call sites in request specs refactored.
91
+ - **`Core::Analysis::Columns` spec** covers the `default: false` branch (6th column outside `default_columns`).
92
+ - **`actions/checkout@v4` bumped to `@v5`** in both `.github/workflows/ci.yml` and `.github/workflows/publish.yml`. Prepares for GitHub's June 2026 Node 20 deprecation.
93
+ - **Gemspec `source_code_uri` duplicate dropped** from both gemspecs (was equal to `homepage_uri` and triggered a RubyGems build warning on every release).
94
+
95
+ ### Documentation
96
+ - README Compatibility table no longer lists Rails 5.2. The note explaining the drop and pinning instructions stays in place.
97
+
98
+ ## 0.5.0
99
+
100
+ ### Changed
101
+ - **ERB templates moved into `sql_genius-core`.** All 11 view files (`dashboard.html.erb` and 10 partials) have been extracted from `app/views/sql_genius/queries/` into `gems/sql_genius-core/lib/sql_genius/core/views/sql_genius/queries/`. The index template is renamed to `dashboard.html.erb`. The engine registers `SqlGenius::Core.views_path` before `:add_view_paths` so Rails finds templates in both view roots. Non-Rails adapters (Phase 2b `sql_genius-desktop` sidecar) can register this same path with their own view loader and implement `path_for`/`render_partial` to reuse the templates.
102
+ - **`QueriesController#index`** now sets `@framework_version_major` and `@framework_version_minor` instance variables (replacing direct `Rails::VERSION` references in the template) and explicitly renders `"sql_genius/queries/dashboard"`.
103
+ - **`SharedViewHelpers`** — new concern providing `path_for(name)` and `render_partial(name)` as the 2-method contract the shared templates depend on. `render_partial` delegates to `view_context.render(partial: "sql_genius/queries/#{name}")`.
104
+ - Extracted 5 AI prompt builders from the `AiFeatures` concern into `SqlGenius::Core::Ai::{DescribeQuery, SchemaReview, RewriteQuery, IndexAdvisor, MigrationRisk}` plus a shared `Core::Ai::SchemaContextBuilder` helper. `anomaly_detection` and `root_cause` remain in the Rails concern because they depend on the Redis-backed `SlowQueryMonitor`.
105
+ - Extracted `QueriesController#columns` logic into `SqlGenius::Core::Analysis::Columns` with a tagged-result struct. Retires the `masked_column?` helper added in the 0.4.1 hotfix.
106
+ - `SqlGenius::Core::Ai::Config` gains a `domain_context:` field. The Rails adapter defaults it to a Rails-specific string; `sql_genius-desktop` will default to empty.
107
+ - `sql_genius` now declares runtime dependency on `sql_genius-core ~> 0.5.0` (was `~> 0.4.0`).
108
+
109
+ ### Added
110
+ - Integration test suite at `spec/dummy/` + `spec/rails_helper.rb` + `spec/requests/`. Boots a minimal Rails engine dummy app and dispatches real HTTP requests against the mounted engine via `Rack::Test`. Dedicated regression specs at `spec/regressions/` pin the two Phase 1b latent bugs (`Core::Connection::ActiveRecordAdapter` boot-order and `QueriesController#masked_column?` helper deletion) so they can never silently return.
111
+ - `CLAUDE.md` updated: the "no Rails boot in tests" rule is relaxed to a two-tier model (unit specs stub AR, integration specs boot Rails via `spec/dummy/`).
112
+
113
+ ### Internal
114
+ - `SqlGenius::Core.views_path` — new public module method returning the absolute path to the shared ERB template directory.
115
+
116
+ ## 0.4.1
117
+
118
+ ### Fixed
119
+ - **`GET /columns` endpoint raised `NoMethodError: undefined method 'masked_column?'` at runtime** — a second Phase 1b regression (0.4.0 also shipped the `ActiveRecordAdapter` boot-order bug). When `SqlValidator::masked_column?` was promoted to a 2-arg class method during Phase 1b, the one remaining caller in `QueriesController#columns` was not updated. Clicking a table in the Query Explorer dropdown on 0.4.0 hits this route and triggers a 500. Fixed by reintroducing a private `masked_column?(name)` helper on `QueriesController` that delegates to `SqlGenius::Core::SqlValidator.masked_column?(name, sql_genius_config.masked_column_patterns)`. The call site on line 30 is untouched. Regression guard is deferred to Phase 2a's planned `spec/dummy/` Rails dummy app — the project's "no Rails boot in tests" policy blocks writing a controller-level unit spec for this without novel scaffolding. Empirically verified in-process: `masked_column?("password_hash") == true`, `masked_column?("email") == false`, `masked_column?("api_token") == true`.
120
+
121
+ ## 0.4.0
122
+
123
+ ### Fixed
124
+ - **Boot-order bug: `SqlGenius::Core::Connection::ActiveRecordAdapter` was not required by `lib/sql_genius.rb`** — shipped in Phase 1a but never wired into the production require chain. Invisible to CI because the adapter's spec file explicitly required it, and invisible in development because pre-Phase-1b concerns didn't reference it. Phase 1b's extracted delegators instantiate it in every action, so the missing require would have surfaced as `uninitialized constant` on every tab (tables, query stats, unused indexes, duplicate indexes, server overview, execute, explain, AI suggest, AI optimize) in any host app that installed 0.4.0 without the fix. `lib/sql_genius.rb` now explicitly requires the adapter after loading `sql_genius/core`, and `spec/spec_helper.rb` has a regression guard that aborts the spec suite at boot if the constant is not reachable via a plain `require "sql_genius"`.
125
+
126
+ ### Changed
127
+ - **Internal refactor: extracted Rails-free core library into a new `sql_genius-core` gem.** The validator, AI services, value objects, database analyses, query runner, and query explainer now live in `sql_genius-core`; the `sql_genius` Rails engine delegates through a new `Core::Connection::ActiveRecordAdapter`. Public API, routes, config DSL, and JSON response shapes are unchanged — host apps see no difference after `bundle update`. See [the design spec](docs/superpowers/specs/2026-04-10-desktop-app-design.md) for the motivation: the new core gem is the foundation for a forthcoming `sql_genius-desktop` standalone app.
128
+ - `sql_genius` now declares a runtime dependency on `sql_genius-core ~> 0.4.0`. The two gems release in lockstep under matching version numbers (0.4.0 is the first paired release); the dependency resolves transitively, so host apps do not need to add `sql_genius-core` to their Gemfile.
129
+ - `SqlGenius::SqlValidator` moved to `SqlGenius::Core::SqlValidator`.
130
+ - `SqlGenius::AiClient`, `SqlGenius::AiSuggestionService`, `SqlGenius::AiOptimizationService` moved to `SqlGenius::Core::Ai::{Client, Suggestion, Optimization}` and now take an explicit `Core::Ai::Config` instead of reading `SqlGenius.configuration` at construction time.
131
+ - The 5 database analyses (`table_sizes`, `duplicate_indexes`, `query_stats`, `unused_indexes`, `server_overview`) moved from the `DatabaseAnalysis` controller concern into `SqlGenius::Core::Analysis::*` classes, each taking a `Core::Connection`. The concern shrunk from ~295 lines to 47 lines of thin delegating wrappers.
132
+ - `SqlGenius::Core::QueryRunner` now owns SQL validation, row-limit application, timeout-hint wrapping (MySQL / MariaDB flavors), execution, column masking, and timeout detection. The `execute` controller action delegates to it. Audit logging stays in the Rails adapter.
133
+ - `SqlGenius::Core::QueryExplainer` now owns the EXPLAIN path with optional validation-skipping for captured slow queries. The `explain` controller action delegates to it.
134
+
135
+ ### Documentation
136
+ - Added README troubleshooting section covering `SSL_connect ... EC lib` / `unable to decode issuer public key` errors that hit Ruby 2.7 + OpenSSL 1.1.x users talking to Google Trust Services-backed hosts like Ollama Cloud. Recommends local Ollama (`http://localhost:11434`) as the fastest unblock, `SSL_CERT_FILE` pointing at a fresher CA bundle as an intermediate fix, and upgrading to Ruby 3.2+ as the durable fix.
137
+ - Added `docs/superpowers/specs/2026-04-10-desktop-app-design.md` — the full design spec for the eventual `sql_genius-desktop` standalone app.
138
+
139
+ ## 0.3.2
140
+
141
+ ### Fixed
142
+ - **Query Stats tab stuck on loading spinner** -- commented-out HTML controls in `_tab_query_stats.html.erb` left corresponding JavaScript (`el('qstats-sort').value` and two `addEventListener` calls) throwing `TypeError` on null elements, killing `loadQueryStats` before it could issue its fetch. The commented-out markup and the dead JavaScript have both been removed; client-side sortable column headers continue to provide sort UX.
143
+
144
+ ## 0.3.1
145
+
146
+ ### Added
147
+ - **Sortable columns** -- click any column header to sort ascending/descending on all data tables
148
+ - **Automated RubyGems publishing** -- GitHub Actions workflow publishes gem on tag push
149
+
150
+ ### Fixed
151
+ - **Query stats noise** -- SQLGenius internal queries (information_schema, performance_schema, SHOW, etc.) are now excluded from the Query Stats tab
152
+
153
+ ## 0.3.0
154
+
155
+ ### Improved
156
+ - **SQL syntax highlighting** -- SQL code blocks in tables now feature a dark-themed syntax highlighter with distinct colors for keywords, functions, strings, numbers, operators, identifiers, and placeholders (Catppuccin Mocha palette)
157
+ - **Table visual hierarchy** -- redesigned table headers (uppercase, thicker bottom border, rounded top corners), improved row hover states (blue tint), cleaner alternating row colors, removed vertical cell borders
158
+ - **Numeric column formatting** -- right-aligned with monospace tabular-nums font for easy scanning; duration values color-coded green/amber/red by severity
159
+ - **Overall dashboard polish** -- more generous cell padding, improved inline `code` tag styling, added `mg-badge-success` variant
160
+ - **Tab persistence** -- active tab is remembered across page reloads via URL hash
161
+
162
+ ### Fixed
163
+ - **Unused indexes SQL error on MySQL 8.0+** -- `reads` and `writes` are reserved words and now use backtick quoting
164
+
165
+ ### Added
166
+ - **Dark theme** -- auto-detects system preference, manual toggle via sun/moon button, persisted in localStorage
167
+ - **Tables tab** -- renamed from "Table Sizes", now shows engine, collation, auto-increment, last updated, and accurate row counts via `COUNT(*)`
168
+ - **Optimize suggestions** -- tables with >10% fragmentation are flagged with an optimize badge
169
+
170
+ ## 0.2.0
171
+
172
+ - **Dashboard-first redesign** -- new default landing page with server health, top slow queries, top expensive queries, and index alert badges
173
+ - **Query Explorer** -- merged Visual Builder and SQL Query into one tab with a mode toggle
174
+ - **Suggested migrations** -- duplicate and unused index tabs generate timestamped Rails migrations with copy-to-clipboard
175
+ - **Install generator** -- `rails generate sql_genius:install` creates initializer and mounts the engine
176
+ - **RuboCop** -- added rubocop-shopify and rubocop-rspec, enforced across the codebase
177
+ - **CI matrix** -- added Ruby 3.4, Rails 8.0 and 8.1; excluded incompatible Ruby 3.4 + Rails 6.1/7.0 combos
178
+ - **Smarter AI prompts** -- schema review now includes primary keys and Rails-aware context (no foreign key constraint recommendations, recommends indexes on FK columns instead)
179
+ - **SSL fix** -- explicit CA certificate file for AI API requests
180
+ - Tab reorder: Dashboard, Slow Queries, Query Stats, Server, Table Sizes, Unused Indexes, Duplicate Indexes, Query Explorer, AI Tools
181
+ - Dashboard links to Server tab for full details
182
+ - Clipboard fallback for non-HTTPS environments
183
+ - Gemspec description updated to lead with monitoring features
184
+
185
+ ## 0.1.0
186
+
187
+ - Initial release
188
+ - Visual query builder with column selection, filters, and ordering
189
+ - Safe SQL execution (read-only, blocked tables, masked columns, row limits, timeouts)
190
+ - EXPLAIN analysis
191
+ - AI-powered query suggestions (optional)
192
+ - AI-powered query optimization from EXPLAIN output (optional)
193
+ - Slow query monitoring via Redis
194
+ - Audit logging
195
+ - MariaDB support
data/LICENSE.txt ADDED
@@ -0,0 +1,65 @@
1
+ SQLGenius Source-Available Non-Commercial License 1.0
2
+
3
+ Copyright (c) 2026 Antarr Byrd
4
+
5
+ 1. Grant of rights
6
+
7
+ You may use, copy, modify, and distribute this software and any modified
8
+ version of it for non-commercial purposes only, subject to the terms of this
9
+ license.
10
+
11
+ 2. Non-commercial use only
12
+
13
+ "Non-commercial" means a use that is not primarily intended for or directed
14
+ toward commercial advantage or monetary compensation.
15
+
16
+ Without prior written permission from the copyright holder, you may not use
17
+ this software:
18
+
19
+ - in connection with a business or other for-profit activity;
20
+ - for paid client work, consulting, or contract services;
21
+ - as part of a hosted or managed service, including SaaS;
22
+ - inside an internal business system or other revenue-supporting operation;
23
+ - as part of a commercial product, bundle, or offering that is sold,
24
+ licensed, or monetized; or
25
+ - in any other way primarily intended for commercial advantage or monetary
26
+ compensation.
27
+
28
+ 3. Commercial licensing
29
+
30
+ Any commercial use requires prior written permission from the copyright
31
+ holder. Commercial licenses may require payment or another separately agreed
32
+ consideration. A donation by itself does not grant commercial rights unless
33
+ the copyright holder expressly says so in writing.
34
+
35
+ 4. Redistribution
36
+
37
+ If you distribute this software or a modified version of it, you must:
38
+
39
+ - include this license text and the copyright notice with the distribution;
40
+ - clearly state that the software is licensed for non-commercial use only;
41
+ and
42
+ - clearly mark any material modifications you made.
43
+
44
+ You may not distribute this software under terms that grant recipients
45
+ commercial rights not granted by this license.
46
+
47
+ 5. No trademark rights
48
+
49
+ This license does not grant any right to use the names, logos, or trademarks
50
+ of the copyright holder, except as necessary for reasonable attribution.
51
+
52
+ 6. Termination
53
+
54
+ Any use of the software outside the scope of this license automatically
55
+ terminates your rights under it.
56
+
57
+ 7. Disclaimer of warranty and limitation of liability
58
+
59
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
63
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
64
+ OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
65
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # SQLGenius
2
+
3
+ An AI-powered SQL dashboard for Rails to help you inspect and optimize MySQL, MariaDB, and PostgreSQL databases.
4
+
5
+ ## Screenshots
6
+
7
+ ### Dashboard
8
+
9
+ At-a-glance server health, top slow queries, most expensive queries, and index alerts.
10
+
11
+ ![Dashboard](docs/screenshots/dashboard.png)
12
+
13
+ ### Query Stats
14
+
15
+ Top queries from `performance_schema` sorted by total time, with SQL syntax highlighting and color-coded durations.
16
+
17
+ ![Query Stats](docs/screenshots/query_stats.png)
18
+
19
+ ### Server Dashboard
20
+
21
+ Server health: version, connections, InnoDB buffer pool, and query activity with AI-powered diagnostics.
22
+
23
+ ![Server](docs/screenshots/server.png)
24
+
25
+ ### Tables
26
+
27
+ Row counts, data size, index size, engine, fragmentation, and optimize suggestions for every table.
28
+
29
+ ![Table Sizes](docs/screenshots/table_sizes.png)
30
+
31
+ ### Duplicate Index Detection
32
+
33
+ Find redundant indexes whose columns are a left-prefix of another index, with ready-to-run `DROP INDEX` statements.
34
+
35
+ ![Duplicate Indexes](docs/screenshots/duplicate_indexes.png)
36
+
37
+ ### Query Explorer
38
+
39
+ Build queries visually or write raw SQL. Optional AI assistant generates queries from plain English descriptions.
40
+
41
+ ![Query Explorer](docs/screenshots/query_explore.png)
42
+
43
+ ### AI Tools
44
+
45
+ Schema review, query optimization, index advisor, anomaly detection, root cause analysis, and migration risk assessment.
46
+
47
+ ![AI Tools](docs/screenshots/ai_tools.png)
48
+
49
+ ## Features
50
+
51
+ - **Dashboard** -- server health, slow queries, expensive queries, index alerts at a glance
52
+ - **Query Explorer** -- visual builder + raw SQL editor with AI assistant
53
+ - **SQL Syntax Highlighting** -- dark-themed code blocks with color-coded keywords, functions, strings
54
+ - **Safe SQL Execution** -- read-only enforcement, blocked tables, masked columns, row limits, timeouts
55
+ - **EXPLAIN Analysis** -- run EXPLAIN on any query and view the execution plan
56
+ - **9 AI Tools** -- suggestions, optimization, schema review, query rewrite, index advisor, anomaly detection, root cause analysis, migration risk ([details](https://github.com/antarr/sql_genius/wiki/AI-Features))
57
+ - **Slow Query Monitoring** -- captures slow queries via ActiveSupport notifications and Redis ([details](https://github.com/antarr/sql_genius/wiki/Slow-Query-Monitoring))
58
+ - **Index Analysis** -- duplicate index detection, unused index detection with DROP statements
59
+ - **Dark Theme** -- auto-detects system preference with manual toggle ([details](https://github.com/antarr/sql_genius/wiki/Dark-Theme))
60
+ - **MariaDB Support** -- automatically detects MariaDB and uses appropriate timeout syntax
61
+ - **PostgreSQL Support** -- core analyses (table sizes, query stats, unused indexes, server overview) work on PostgreSQL via `pg_stat_statements` and `pg_stat_user_indexes`; dialect detected automatically
62
+ - **Self-contained UI** -- no external CSS/JS dependencies, no jQuery, works with any Rails layout
63
+
64
+ ## Quick Start
65
+
66
+ ```ruby
67
+ # Gemfile
68
+ gem "sql_genius"
69
+ ```
70
+
71
+ ```bash
72
+ bundle install
73
+ rails generate sql_genius:install
74
+ ```
75
+
76
+ Visit `/sql_genius` in your browser.
77
+
78
+ For detailed setup, see the [Installation guide](https://github.com/antarr/sql_genius/wiki/Installation).
79
+
80
+ ## Configuration
81
+
82
+ ```ruby
83
+ SqlGenius.configure do |config|
84
+ config.base_controller = "ApplicationController"
85
+ config.authenticate = ->(controller) { controller.current_user&.admin? }
86
+ config.blocked_tables += %w[oauth_tokens api_keys]
87
+ end
88
+ ```
89
+
90
+ For full configuration options, see the [Configuration guide](https://github.com/antarr/sql_genius/wiki/Configuration).
91
+
92
+ ## AI Features (optional)
93
+
94
+ Works with OpenAI, Azure OpenAI, Ollama Cloud, local Ollama, or any OpenAI-compatible API.
95
+
96
+ ```ruby
97
+ SqlGenius.configure do |config|
98
+ config.ai_endpoint = "https://api.openai.com/v1/chat/completions"
99
+ config.ai_api_key = ENV["OPENAI_API_KEY"]
100
+ config.ai_model = "gpt-4o"
101
+ config.ai_auth_style = :bearer
102
+ end
103
+ ```
104
+
105
+ For all provider examples, see the [AI Features guide](https://github.com/antarr/sql_genius/wiki/AI-Features).
106
+
107
+ ### Troubleshooting TLS errors with Ollama Cloud
108
+
109
+ If you see `SSL_connect ... unable to decode issuer public key` or `SSL_connect ... EC lib` when using an AI feature, your Rails host's Ruby is linked against an older OpenSSL that can't verify modern ECDSA certificate chains (Ollama Cloud is served behind Google Trust Services, whose ECDSA roots trip up OpenSSL 1.1.x and earlier). This is not specific to `sql_genius` — it affects any Ruby HTTPS call to those hosts.
110
+
111
+ Three ways to fix it, in order of effort:
112
+
113
+ **Use a local Ollama instead.** Point the endpoint at `http://localhost:11434/v1/chat/completions`. Your Rails app talks plain HTTP to the local `ollama` binary, which handles the upstream TLS itself using its own modern cert handling. For cloud-backed models, run `ollama signin` once and use the `:cloud` model suffix (e.g., `gemma3:27b-cloud`).
114
+
115
+ ```ruby
116
+ SqlGenius.configure do |config|
117
+ config.ai_endpoint = "http://localhost:11434/v1/chat/completions"
118
+ config.ai_api_key = "unused-but-required" # any non-empty string
119
+ config.ai_model = "gemma3:27b-cloud" # or any local model
120
+ config.ai_auth_style = :bearer
121
+ end
122
+ ```
123
+
124
+ **Point Ruby at a fresher CA bundle.** Set `SSL_CERT_FILE` in the environment where Rails boots. On macOS with Homebrew:
125
+
126
+ ```bash
127
+ SSL_CERT_FILE=/opt/homebrew/etc/openssl@3/cert.pem bin/rails s
128
+ ```
129
+
130
+ This helps if the problem is a stale trust store, but does **not** help if the underlying OpenSSL itself is too old to parse the cert's key algorithm.
131
+
132
+ **Upgrade Ruby** to 3.2 or newer. Ruby 2.7 is end-of-life (March 2023); newer Rubies link against OpenSSL 3.x which handles modern ECDSA chains correctly. This is the durable fix and the one we recommend for any project still on 2.7.
133
+
134
+ ## Compatibility
135
+
136
+ | Rails | Ruby |
137
+ |-------|------|
138
+ | 6.0 | 2.7, 3.0, 3.1 |
139
+ | 6.1 | 2.7, 3.0, 3.1, 3.2, 3.3 |
140
+ | 7.0 | 2.7, 3.0, 3.1, 3.2, 3.3 |
141
+ | 7.1 | 2.7, 3.0, 3.1, 3.2, 3.3, 3.4 |
142
+ | 7.2 | 3.1, 3.2, 3.3, 3.4 |
143
+ | 8.0 | 3.2, 3.3, 3.4 |
144
+ | 8.1 | 3.2, 3.3, 3.4 |
145
+
146
+ > **Rails 5.2:** dropped in `sql_genius 0.6.0`. `sql_genius 0.5.0` is the last version to support Rails 5.2 — pin it (`gem "sql_genius", "~> 0.5.0"`) if you can't upgrade Rails yet. Rails 5.2 has been end-of-life since June 2022, and its incompatibilities with modern Rack (`ActionDispatch::Static#initialize` arity mismatch, `MiddlewareStack#operations` removal) surfaced as CI failures once Phase 2a's integration specs booted Rails in test.
147
+
148
+ ## Documentation
149
+
150
+ Full documentation is available on the [Wiki](https://github.com/antarr/sql_genius/wiki).
151
+
152
+ ## Licensing
153
+
154
+ SqlGenius is source-available.
155
+
156
+ - Free for personal, educational, hobby, nonprofit, and other non-commercial use
157
+ - Commercial use requires prior written permission from the copyright holder
158
+ - Commercial use includes internal business use, paid client work, SaaS/hosting, resale, and bundling with a paid product or service
159
+ - Voluntary donations are welcome for non-commercial users, but a donation alone does not grant commercial rights
160
+
161
+ For commercial licensing requests, contact Antarr Byrd at antarr.t.byrd@uth.tmc.edu.
162
+
163
+ ## Development
164
+
165
+ ```bash
166
+ git clone https://github.com/antarr/sql_genius.git
167
+ cd sql_genius
168
+ bin/setup
169
+ bundle exec rspec
170
+ ```
171
+
172
+ ## Contributing
173
+
174
+ Bug reports and pull requests are welcome on GitHub at https://github.com/antarr/sql_genius.
175
+
176
+ ## License
177
+
178
+ This project is licensed under the terms of the [SQLGenius Source-Available Non-Commercial License](LICENSE.txt). It is not distributed under the MIT License or another OSI-approved open source license.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec