better_structure_sql 0.1.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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +41 -0
  3. data/LICENSE +21 -0
  4. data/README.md +557 -0
  5. data/app/controllers/better_structure_sql/application_controller.rb +61 -0
  6. data/app/controllers/better_structure_sql/schema_versions_controller.rb +243 -0
  7. data/app/helpers/better_structure_sql/schema_versions_helper.rb +46 -0
  8. data/app/views/better_structure_sql/schema_versions/index.html.erb +110 -0
  9. data/app/views/better_structure_sql/schema_versions/show.html.erb +186 -0
  10. data/app/views/layouts/better_structure_sql/application.html.erb +105 -0
  11. data/config/database.yml +3 -0
  12. data/config/routes.rb +12 -0
  13. data/lib/better_structure_sql/adapters/base_adapter.rb +234 -0
  14. data/lib/better_structure_sql/adapters/mysql_adapter.rb +476 -0
  15. data/lib/better_structure_sql/adapters/mysql_config.rb +32 -0
  16. data/lib/better_structure_sql/adapters/postgresql_adapter.rb +646 -0
  17. data/lib/better_structure_sql/adapters/postgresql_config.rb +25 -0
  18. data/lib/better_structure_sql/adapters/registry.rb +115 -0
  19. data/lib/better_structure_sql/adapters/sqlite_adapter.rb +644 -0
  20. data/lib/better_structure_sql/adapters/sqlite_config.rb +26 -0
  21. data/lib/better_structure_sql/configuration.rb +129 -0
  22. data/lib/better_structure_sql/database_version.rb +46 -0
  23. data/lib/better_structure_sql/dependency_resolver.rb +63 -0
  24. data/lib/better_structure_sql/dumper.rb +544 -0
  25. data/lib/better_structure_sql/engine.rb +28 -0
  26. data/lib/better_structure_sql/file_writer.rb +180 -0
  27. data/lib/better_structure_sql/formatter.rb +70 -0
  28. data/lib/better_structure_sql/generators/base.rb +33 -0
  29. data/lib/better_structure_sql/generators/domain_generator.rb +22 -0
  30. data/lib/better_structure_sql/generators/extension_generator.rb +23 -0
  31. data/lib/better_structure_sql/generators/foreign_key_generator.rb +43 -0
  32. data/lib/better_structure_sql/generators/function_generator.rb +33 -0
  33. data/lib/better_structure_sql/generators/index_generator.rb +50 -0
  34. data/lib/better_structure_sql/generators/materialized_view_generator.rb +31 -0
  35. data/lib/better_structure_sql/generators/pragma_generator.rb +23 -0
  36. data/lib/better_structure_sql/generators/sequence_generator.rb +27 -0
  37. data/lib/better_structure_sql/generators/table_generator.rb +126 -0
  38. data/lib/better_structure_sql/generators/trigger_generator.rb +54 -0
  39. data/lib/better_structure_sql/generators/type_generator.rb +47 -0
  40. data/lib/better_structure_sql/generators/view_generator.rb +27 -0
  41. data/lib/better_structure_sql/introspection/extensions.rb +29 -0
  42. data/lib/better_structure_sql/introspection/foreign_keys.rb +29 -0
  43. data/lib/better_structure_sql/introspection/functions.rb +29 -0
  44. data/lib/better_structure_sql/introspection/indexes.rb +29 -0
  45. data/lib/better_structure_sql/introspection/sequences.rb +29 -0
  46. data/lib/better_structure_sql/introspection/tables.rb +29 -0
  47. data/lib/better_structure_sql/introspection/triggers.rb +29 -0
  48. data/lib/better_structure_sql/introspection/types.rb +37 -0
  49. data/lib/better_structure_sql/introspection/views.rb +41 -0
  50. data/lib/better_structure_sql/introspection.rb +31 -0
  51. data/lib/better_structure_sql/manifest_generator.rb +65 -0
  52. data/lib/better_structure_sql/migration_patch.rb +196 -0
  53. data/lib/better_structure_sql/pg_version.rb +44 -0
  54. data/lib/better_structure_sql/railtie.rb +124 -0
  55. data/lib/better_structure_sql/schema_loader.rb +168 -0
  56. data/lib/better_structure_sql/schema_version.rb +86 -0
  57. data/lib/better_structure_sql/schema_versions.rb +213 -0
  58. data/lib/better_structure_sql/version.rb +5 -0
  59. data/lib/better_structure_sql/zip_generator.rb +81 -0
  60. data/lib/better_structure_sql.rb +81 -0
  61. data/lib/generators/better_structure_sql/install_generator.rb +44 -0
  62. data/lib/generators/better_structure_sql/migration_generator.rb +34 -0
  63. data/lib/generators/better_structure_sql/templates/README +49 -0
  64. data/lib/generators/better_structure_sql/templates/add_metadata_migration.rb.erb +25 -0
  65. data/lib/generators/better_structure_sql/templates/better_structure_sql.rb +46 -0
  66. data/lib/generators/better_structure_sql/templates/migration.rb.erb +26 -0
  67. data/lib/tasks/better_structure_sql.rake +190 -0
  68. metadata +299 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4e66ec3fc122539bebd5d502233e08b258246a16f8567dbc5fb88bcdb4b98486
4
+ data.tar.gz: 0d7bdeaaa4b1e356d3f506fbeefd1e4e20c2e306b469ebe9184e2ab80b224b2e
5
+ SHA512:
6
+ metadata.gz: 357c7013b0db9e2aed20714750783fc5b386cf21bb6bff014b37a613c6aaf3b48e52eabb965b9f75e7a71af5ca136cc1a0b604108d7bb1e4910ad631c36b5bf5
7
+ data.tar.gz: cb8046cbfd1b37a4ccdcde40b85dc5461b2b73f179536f88bd4376fcd91fa0ea865edbf7b8936e3524fa138719c5656aa64b0cffdc21f7dbc1fef9b4a14514c8
data/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Fixed
15
+
16
+ ## [0.1.0] - 2025-11-20
17
+
18
+ ### Added
19
+ - Initial Phase 1 implementation with core PostgreSQL support
20
+ - Phase 2 schema versioning with retention management
21
+ - Phase 3 advanced PostgreSQL features (views, functions, triggers, partitioned tables)
22
+ - Phase 4 multi-file schema output with ZIP storage
23
+ - Multi-database adapter support (PostgreSQL, MySQL, SQLite)
24
+ - Rails Engine with Web UI for browsing schema versions
25
+ - Docker development environment with integration apps
26
+ - GitHub Pages React documentation site
27
+ - Core introspection for PostgreSQL, MySQL, and SQLite metadata
28
+ - Table, index, foreign key, and extension generators
29
+ - Configuration system with validation and feature toggles
30
+ - Rails Railtie integration with rake tasks
31
+ - Comprehensive test coverage (unit, integration, comparison tests)
32
+ - Clean, deterministic SQL formatting
33
+ - Support for schema.rb and structure.sql formats
34
+ - Directory-based multi-file dumps with 500 LOC chunking
35
+ - Manifest-driven schema loading with dependency ordering
36
+ - ZIP archive storage for multi-file schemas in database
37
+ - Web UI with Bootstrap 5 for viewing and downloading schemas
38
+ - Authentication patterns for securing engine routes
39
+ - MySQL stored procedures and triggers support
40
+ - SQLite PRAGMA settings and inline foreign keys
41
+ - Comprehensive documentation with database-specific guides
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BetterStructureSql
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,557 @@
1
+ <div align="center">
2
+
3
+ # 🗄️ BetterStructureSql
4
+
5
+ ### Clean, maintainable database schema dumps for Rails
6
+ **PostgreSQL • MySQL • SQLite**
7
+
8
+ [![Gem Version](https://badge.fury.io/rb/better_structure_sql.svg)](https://badge.fury.io/rb/better_structure_sql)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
10
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%202.7-red.svg)](https://www.ruby-lang.org/)
11
+ [![Rails](https://img.shields.io/badge/rails-%3E%3D%207.0-red.svg)](https://rubyonrails.org/)
12
+
13
+ **[📚 Documentation](https://sebyx07.github.io/better_structure_sql/)** • **[🐙 GitHub](https://github.com/sebyx07/better_structure_sql)** • **[💎 RubyGems](https://rubygems.org/gems/better_structure_sql)**
14
+
15
+ ---
16
+
17
+ </div>
18
+
19
+ > **⚠️ Beta Notice**: This gem is currently in beta (version 0.1.0). APIs may change between releases until v1.0. We welcome feedback and contributions!
20
+
21
+ ## ✨ Why BetterStructureSql?
22
+
23
+ Rails' database dump tools (`pg_dump`, `mysqldump`, etc.) create noisy `structure.sql` files with version-specific comments, inconsistent formatting, and metadata that pollutes git diffs.
24
+
25
+ **BetterStructureSql** uses pure Ruby introspection to generate clean schema files:
26
+
27
+ <table>
28
+ <tr>
29
+ <td width="50%">
30
+
31
+ ### 🎯 Core Benefits
32
+
33
+ - ✅ **Clean diffs** - Only actual schema changes
34
+ - ✅ **No external tools** - Pure Ruby introspection
35
+ - ✅ **Multi-database** - PostgreSQL, MySQL, SQLite
36
+ - ✅ **Deterministic** - Same input = identical output
37
+
38
+ </td>
39
+ <td width="50%">
40
+
41
+ ### 🚀 Advanced Features
42
+
43
+ - ✅ **Complete coverage** - Tables, views, triggers, functions
44
+ - ✅ **Schema versioning** - Store & retrieve versions
45
+ - ✅ **Multi-file output** - Handle massive schemas
46
+ - ✅ **Rails integration** - Drop-in replacement
47
+
48
+ </td>
49
+ </tr>
50
+ </table>
51
+
52
+ ---
53
+
54
+ ## 🗃️ Database Support
55
+
56
+ | Feature | PostgreSQL 12+ | MySQL 8.0+ | SQLite 3.35+ |
57
+ |---------|----------------|------------|--------------|
58
+ | **Tables & Columns** | ✅ Full | ✅ Full | ✅ Full |
59
+ | **Indexes** | ✅ btree, gin, gist, hash, brin | ✅ btree, hash, fulltext | ✅ btree |
60
+ | **Foreign Keys** | ✅ All actions | ✅ All actions | ✅ Inline with CREATE TABLE |
61
+ | **Unique Constraints** | ✅ | ✅ | ✅ |
62
+ | **Check Constraints** | ✅ | ✅ (8.0.16+) | ✅ |
63
+ | **Extensions** | ✅ pgcrypto, uuid-ossp, pg_trgm, etc. | ❌ | ❌ (PRAGMA settings instead) |
64
+ | **Custom Types (ENUM)** | ✅ CREATE TYPE | ❌ (inline ENUM/SET) | ❌ (CHECK constraints) |
65
+ | **Sequences** | ✅ CREATE SEQUENCE | ❌ (AUTO_INCREMENT) | ❌ (AUTOINCREMENT) |
66
+ | **Views** | ✅ Regular views | ✅ Regular views | ✅ Regular views |
67
+ | **Materialized Views** | ✅ | ❌ | ❌ |
68
+ | **Functions** | ✅ plpgsql, sql | ✅ Stored procedures | ❌ |
69
+ | **Triggers** | ✅ BEFORE/AFTER/INSTEAD OF | ✅ BEFORE/AFTER | ✅ BEFORE/AFTER |
70
+ | **Partitioned Tables** | ✅ RANGE/LIST/HASH | ❌ | ❌ |
71
+ | **Domains** | ✅ | ❌ | ❌ |
72
+
73
+ ### Getting Started by Database
74
+
75
+ - **PostgreSQL**: [Installation →](https://www.postgresql.org/download/) | [Rails Guide →](https://guides.rubyonrails.org/configuring.html#configuring-a-postgresql-database)
76
+ - **MySQL**: [Installation →](https://dev.mysql.com/downloads/mysql/) | [Rails Guide →](https://guides.rubyonrails.org/configuring.html#configuring-a-mysql-or-mariadb-database)
77
+ - **SQLite**: [Installation →](https://www.sqlite.org/download.html) | [Rails Guide →](https://guides.rubyonrails.org/configuring.html#configuring-a-sqlite3-database)
78
+
79
+ 📖 See [Feature Compatibility Matrix](docs/features/multi-database-adapter-support/README.md#feature-compatibility-matrix) for detailed comparison.
80
+
81
+ ## Features
82
+
83
+ ### Core Features
84
+ - **Pure Ruby implementation** - No external tool dependencies (pg_dump, mysqldump, sqlite3 CLI)
85
+ - **Multi-database adapter pattern** - Auto-detects database type from ActiveRecord connection
86
+ - **Clean structure.sql** - Only essential schema information
87
+ - **Complete database support**:
88
+ - Tables with all column types and defaults
89
+ - Primary keys, foreign keys, and constraints
90
+ - Indexes (including partial, unique, and expression indexes)
91
+ - Views (and materialized views for PostgreSQL)
92
+ - Functions/stored procedures and triggers (database-dependent)
93
+ - Extensions (PostgreSQL)
94
+ - Sequences (PostgreSQL)
95
+ - Custom types and enums (PostgreSQL, MySQL SET/ENUM)
96
+
97
+ ### Multi-File Schema Output (Optional)
98
+ - **Massive schema support** - Handle tens of thousands of tables effortlessly
99
+ - **Directory-based output** - Split schema across organized, numbered directories
100
+ - **Smart chunking** - 500 LOC per file with intelligent overflow handling
101
+ - **Better git diffs** - See only changed files, not entire schema
102
+ - **ZIP downloads** - Download complete directory structure as archive
103
+ - **Easy navigation** - Find tables quickly in `4_tables/`, triggers in `9_triggers/`, etc.
104
+
105
+ ### Schema Versioning (Optional)
106
+ - Store schema versions in database with metadata
107
+ - Track database type and version, format type (SQL/Ruby), creation timestamp
108
+ - ZIP archive storage for multi-file schemas
109
+ - Configurable retention policy (keep last N versions)
110
+ - Browse and download versions via web UI (mountable Rails engine)
111
+ - Works with both `structure.sql` and `schema.rb`
112
+ - Works across all database types (PostgreSQL, MySQL, SQLite)
113
+ - Restore from any stored version
114
+
115
+ ### Web UI Engine
116
+ - **Mountable Rails Engine** - Browse schema versions in any Rails app
117
+ - **Bootstrap 5 interface** - No asset compilation required (CDN-based)
118
+ - **View schema versions** - List, view formatted schema, download raw text
119
+ - **Configurable authentication** - Integrate with Devise, Pundit, or custom auth
120
+ - **Developer onboarding** - Easy access to latest schema for new team members
121
+
122
+ ### Rails Integration
123
+ - Drop-in replacement: `rake db:schema:dump` → uses BetterStructureSql (when enabled)
124
+ - Configuration via `config/initializers/better_structure_sql.rb`
125
+ - **Rake Tasks**:
126
+ - `db:schema:dump_better` - Explicitly dump schema using BetterStructureSql
127
+ - `db:schema:load_better` - Load schema (supports both file and directory mode)
128
+ - `db:schema:store` - Store current schema as a version in database
129
+ - `db:schema:versions` - List all stored schema versions
130
+ - `db:schema:cleanup` - Remove old versions based on retention limit
131
+ - `db:schema:restore[VERSION_ID]` - Restore database from specific version
132
+
133
+ ### Docker Development Environment
134
+ - **Single command setup** - `docker compose up` for full environment
135
+ - **PostgreSQL included** - No local database installation needed
136
+ - **Live code reloading** - Changes reflect immediately
137
+ - **Integration app** - Test and demo environment included
138
+
139
+ ## 🚀 Quick Start
140
+
141
+ ```ruby
142
+ # Gemfile
143
+ gem 'better_structure_sql'
144
+ gem 'pg' # or 'mysql2' or 'sqlite3'
145
+ ```
146
+
147
+ ```bash
148
+ bundle install
149
+ rails generate better_structure_sql:install
150
+ rails db:schema:dump_better
151
+ ```
152
+
153
+ **🎉 Your `db/structure.sql` is now clean and maintainable!**
154
+
155
+ ## Docker Development Environment 🐳
156
+
157
+ Get started with a fully configured development environment in seconds:
158
+
159
+ ```bash
160
+ # Start PostgreSQL + Rails integration app
161
+ docker compose up
162
+
163
+ # Visit http://localhost:3000
164
+ ```
165
+
166
+ See [DOCKER.md](DOCKER.md) for complete Docker documentation.
167
+
168
+ ## Documentation 📚
169
+
170
+ ### 🌐 Documentation Website
171
+ **[Visit the full documentation site →](https://sebyx07.github.io/better_structure_sql/)**
172
+
173
+ Interactive documentation with tutorials, database-specific guides, and real-world examples showing how to use SQL databases to their fullest with BetterStructureSql. Features include:
174
+ - Step-by-step tutorials for PostgreSQL, MySQL, and SQLite
175
+ - Real-world examples using advanced database features (triggers, views, functions)
176
+ - Production deployment guides with automatic schema versioning
177
+ - API reference and configuration examples
178
+ - AI-friendly multi-file schema benefits
179
+
180
+ ### General Documentation
181
+ - [Installation](docs/installation.md) - Setup and configuration
182
+ - [Configuration](docs/configuration.md) - All configuration options
183
+ - [Usage](docs/usage.md) - Rake tasks and examples
184
+ - [Schema Versions](docs/schema_versions.md) - Version storage feature
185
+ - [Troubleshooting](docs/usage.md#troubleshooting) - Common issues and solutions
186
+ - [Multi-File Schema Output](docs/features/multi-file-schema-output/README.md) - Handle massive schemas
187
+ - [Web UI Engine](docs/features/dev-environment-docker-web-ui/README.md) - Browse versions via web interface
188
+ - [Docker Development](DOCKER.md) - Complete Docker environment guide
189
+ - [Testing](docs/testing.md) - RSpec testing guide
190
+ - [MVP Phases](docs/mvp/) - Implementation roadmap
191
+
192
+ ### Multi-Database Support
193
+ - [Multi-Database Architecture](docs/features/multi-database-adapter-support/README.md) - Overview and feature matrix
194
+ - [Database Adapters Architecture](docs/features/multi-database-adapter-support/architecture.md) - Technical deep dive
195
+ - [Implementation Phases](docs/features/multi-database-adapter-support/plan/) - Phased rollout plan
196
+
197
+ ## 📊 Example Output
198
+
199
+ <table>
200
+ <tr>
201
+ <td width="50%">
202
+
203
+ ### ❌ Before (pg_dump)
204
+
205
+ ```sql
206
+ --
207
+ -- PostgreSQL database dump
208
+ --
209
+
210
+ -- Dumped from database version 14.5
211
+ -- Dumped by pg_dump version 14.5
212
+
213
+ SET statement_timeout = 0;
214
+ SET lock_timeout = 0;
215
+ SET idle_in_transaction_session_timeout = 0;
216
+ SET client_encoding = 'UTF8';
217
+ SET standard_conforming_strings = on;
218
+ SELECT pg_catalog.set_config('search_path', '', false);
219
+ SET check_function_bodies = false;
220
+ SET xmloption = content;
221
+ SET client_min_messages = warning;
222
+ SET row_security = off;
223
+ -- ... 50+ more lines ...
224
+ ```
225
+
226
+ **😕 Issues:**
227
+ - Version-specific comments
228
+ - Noisy SET commands
229
+ - Non-deterministic output
230
+ - Hard to review diffs
231
+
232
+ </td>
233
+ <td width="50%">
234
+
235
+ ### ✅ After (BetterStructureSql)
236
+
237
+ ```sql
238
+ SET client_encoding = 'UTF8';
239
+
240
+ -- Extensions
241
+ CREATE EXTENSION IF NOT EXISTS plpgsql
242
+ WITH SCHEMA pg_catalog;
243
+ CREATE EXTENSION IF NOT EXISTS pgcrypto
244
+ WITH SCHEMA public;
245
+
246
+ -- Tables
247
+ CREATE TABLE users (
248
+ id bigserial PRIMARY KEY,
249
+ email varchar NOT NULL,
250
+ created_at timestamp(6) NOT NULL,
251
+ updated_at timestamp(6) NOT NULL
252
+ );
253
+
254
+ CREATE INDEX index_users_on_email
255
+ ON users (email);
256
+ ```
257
+
258
+ **🎯 Benefits:**
259
+ - Clean, minimal output
260
+ - Deterministic
261
+ - Easy to review
262
+ - Version control friendly
263
+
264
+ </td>
265
+ </tr>
266
+ </table>
267
+
268
+ ## ⚙️ Configuration
269
+
270
+ ### 📄 Single-File Output (Default)
271
+
272
+ ```ruby
273
+ # config/initializers/better_structure_sql.rb
274
+ BetterStructureSql.configure do |config|
275
+ # Single file output (default)
276
+ config.output_path = 'db/structure.sql'
277
+
278
+ # Replace default rake db:schema:dump (opt-in, default: false)
279
+ # When false, use explicit tasks: rails db:schema:dump_better
280
+ config.replace_default_dump = false
281
+ config.replace_default_load = false
282
+
283
+ # Schema version storage (optional)
284
+ config.enable_schema_versions = true
285
+ config.schema_versions_limit = 10 # Keep last 10 versions (0 = unlimited)
286
+
287
+ # Customize output
288
+ config.include_extensions = true
289
+ config.include_functions = true
290
+ config.include_triggers = true
291
+ config.include_views = true
292
+
293
+ # Search path
294
+ config.search_path = '"$user", public'
295
+ end
296
+ ```
297
+
298
+ ### 📁 Multi-File Output (Recommended for Large Projects)
299
+
300
+ > **💡 Recommended:** Use `db/schema` directory mode for projects with 100+ tables for better git diffs, easier navigation, and AI-friendly organization.
301
+
302
+ ```ruby
303
+ # config/initializers/better_structure_sql.rb
304
+ BetterStructureSql.configure do |config|
305
+ # Multi-file output - splits schema across directories
306
+ config.output_path = 'db/schema'
307
+
308
+ # Chunking configuration
309
+ config.max_lines_per_file = 500 # Soft limit per file (default: 500)
310
+ config.overflow_threshold = 1.1 # 10% overflow allowed (default: 1.1)
311
+ config.generate_manifest = true # Create _manifest.json (default: true)
312
+
313
+ # Schema version storage with ZIP archives
314
+ config.enable_schema_versions = true
315
+ config.schema_versions_limit = 10
316
+
317
+ # Feature toggles
318
+ config.include_extensions = true
319
+ config.include_functions = true
320
+ config.include_triggers = true
321
+ config.include_views = true
322
+ end
323
+ ```
324
+
325
+ ### 📂 Directory Structure (Multi-File Mode)
326
+
327
+ When using `config.output_path = 'db/schema'`, your schema is organized by type with numbered directories indicating load order:
328
+
329
+ ```
330
+ db/schema/
331
+ ├── _header.sql # SET statements and search path
332
+ ├── _manifest.json # Metadata and load order
333
+ ├── 1_extensions/
334
+ │ └── 000001.sql
335
+ ├── 2_types/
336
+ │ └── 000001.sql
337
+ ├── 3_sequences/
338
+ │ └── 000001.sql
339
+ ├── 4_tables/
340
+ │ ├── 000001.sql # ~500 lines per file
341
+ │ ├── 000002.sql
342
+ │ └── 000003.sql
343
+ ├── 5_indexes/
344
+ │ └── 000001.sql
345
+ ├── 6_foreign_keys/
346
+ │ └── 000001.sql
347
+ ├── 7_views/
348
+ │ └── 000001.sql
349
+ ├── 8_functions/
350
+ │ └── 000001.sql
351
+ └── 9_triggers/
352
+ └── 000001.sql
353
+ ```
354
+
355
+ **Benefits for Large Schemas**:
356
+ - ✅ Memory efficient - incremental file writing
357
+ - ✅ Git friendly - only changed files in diffs
358
+ - ✅ Easy navigation - find specific tables/triggers quickly
359
+ - ✅ ZIP downloads - complete directory as single archive
360
+ - ✅ Scalable - handles 50,000+ database objects
361
+
362
+ ## 📝 Usage & Rake Tasks
363
+
364
+ ### Core Schema Tasks
365
+
366
+ ```bash
367
+ # Dump schema using BetterStructureSql (explicit)
368
+ rails db:schema:dump_better
369
+
370
+ # Load schema from file or directory
371
+ rails db:schema:load_better
372
+ ```
373
+
374
+ ### Schema Versioning Tasks
375
+
376
+ **Store Current Schema**
377
+ ```bash
378
+ # Store the current schema as a version in the database
379
+ rails db:schema:store
380
+ ```
381
+
382
+ This command:
383
+ - Reads your current `db/structure.sql` or `db/schema` directory
384
+ - Stores it in the `better_structure_sql_schema_versions` table
385
+ - Includes metadata: format type, output mode, database version, file count
386
+ - For multi-file schemas, creates a ZIP archive of all files
387
+ - Automatically manages retention (keeps last N versions based on config)
388
+
389
+ **List Stored Versions**
390
+ ```bash
391
+ # View all stored schema versions
392
+ rails db:schema:versions
393
+ ```
394
+
395
+ Output example:
396
+ ```
397
+ Total versions: 5
398
+
399
+ ID Format Mode Files PostgreSQL Created Size
400
+ -----------------------------------------------------------------------------------------------
401
+ 5 sql multi_file 47 15.3 2025-01-15 10:30:22 156.42 KB
402
+ 4 sql single_file 1 15.3 2025-01-14 15:20:10 89.21 KB
403
+ 3 sql single_file 1 15.2 2025-01-13 09:45:33 87.03 KB
404
+ ```
405
+
406
+ **Restore from Version**
407
+ ```bash
408
+ # Restore database from a specific version
409
+ rails db:schema:restore[5]
410
+
411
+ # Or using environment variable
412
+ VERSION_ID=5 rails db:schema:restore
413
+ ```
414
+
415
+ **Cleanup Old Versions**
416
+ ```bash
417
+ # Remove old versions based on retention limit
418
+ rails db:schema:cleanup
419
+ ```
420
+
421
+ ### Web UI Engine
422
+
423
+ Mount the web interface to browse schema versions:
424
+
425
+ ```ruby
426
+ # config/routes.rb
427
+ Rails.application.routes.draw do
428
+ # With authentication (recommended for production)
429
+ authenticate :user, ->(user) { user.admin? } do
430
+ mount BetterStructureSql::Engine, at: '/schema_versions'
431
+ end
432
+
433
+ # Or without authentication (development only)
434
+ mount BetterStructureSql::Engine, at: '/schema_versions' if Rails.env.development?
435
+ end
436
+ ```
437
+
438
+ Access at `http://localhost:3000/schema_versions` to:
439
+ - View list of all stored schema versions
440
+ - Browse formatted schema content with syntax highlighting
441
+ - Download raw SQL/Ruby schema files
442
+ - Download ZIP archives for multi-file schemas
443
+ - Compare database versions and formats
444
+
445
+ **Authentication Examples**:
446
+
447
+ ```ruby
448
+ # Devise with admin check
449
+ authenticate :user, ->(user) { user.admin? } do
450
+ mount BetterStructureSql::Engine, at: '/admin/schema'
451
+ end
452
+
453
+ # Custom constraint class
454
+ class AdminConstraint
455
+ def matches?(request)
456
+ user = request.env['warden']&.user
457
+ user&.admin?
458
+ end
459
+ end
460
+
461
+ constraints AdminConstraint.new do
462
+ mount BetterStructureSql::Engine, at: '/schema_versions'
463
+ end
464
+
465
+ # Environment-based
466
+ if Rails.env.production?
467
+ # Add your production auth here
468
+ else
469
+ mount BetterStructureSql::Engine, at: '/schema_versions'
470
+ end
471
+ ```
472
+
473
+ ### Automatic Schema Storage Workflow
474
+
475
+ **Option 1: After Each Migration (Recommended)**
476
+ ```bash
477
+ # Run migration and store schema version
478
+ rails db:migrate && rails db:schema:store
479
+ ```
480
+
481
+ **Option 2: Git Hooks**
482
+ ```bash
483
+ # .git/hooks/post-merge
484
+ #!/bin/bash
485
+ if git diff HEAD@{1} --name-only | grep -q "db/migrate"; then
486
+ echo "Migrations detected, storing schema version..."
487
+ rails db:schema:store
488
+ fi
489
+ ```
490
+
491
+ **Option 3: CI/CD Pipeline**
492
+ ```yaml
493
+ # .github/workflows/deploy.yml
494
+ - name: Run migrations and store schema
495
+ run: |
496
+ rails db:migrate
497
+ rails db:schema:store
498
+ ```
499
+
500
+ ## 📋 Requirements
501
+
502
+ | Component | Version | Notes |
503
+ |-----------|---------|-------|
504
+ | **Ruby** | 2.7+ | Tested up to Ruby 3.4.7 |
505
+ | **Rails** | 7.0+ | Works with Rails 8.1.1+ |
506
+ | **Database Adapter** | | Choose one: |
507
+ | `pg` | ≥ 1.0 | For PostgreSQL 12+ |
508
+ | `mysql2` | ≥ 0.5 | For MySQL 8.0+ |
509
+ | `sqlite3` | ≥ 1.4 | For SQLite 3.35+ |
510
+
511
+ ## Migration Guides
512
+
513
+ ### Migrating from schema.rb to structure.sql
514
+
515
+ If you're currently using Rails' `schema.rb` (Ruby format) and want to switch to `structure.sql` (SQL format) with BetterStructureSql, we have a comprehensive guide:
516
+
517
+ **[📖 Migration Guide: From schema.rb to structure.sql](docs/migration-guides/from-schema-rb-to-structure-sql.md)**
518
+
519
+ This guide covers:
520
+ - Why migrate from schema.rb to structure.sql
521
+ - Step-by-step migration process
522
+ - Configuration for both formats
523
+ - Switching between formats dynamically
524
+ - Comparing SQL vs Ruby schema versions
525
+ - Rollback procedures
526
+ - Best practices and troubleshooting
527
+
528
+ BetterStructureSql supports **both** `schema.rb` and `structure.sql` formats, allowing you to:
529
+ - Store versions of either format
530
+ - Switch between formats using `SCHEMA_FORMAT` environment variable
531
+ - Compare different formats in the web UI
532
+ - Migrate gradually from Ruby to SQL format
533
+
534
+ ---
535
+
536
+ ## 🤝 Contributing
537
+
538
+ We welcome contributions! Bug reports and pull requests are welcome on [GitHub](https://github.com/sebyx07/better_structure_sql).
539
+
540
+ ### How to Contribute
541
+
542
+ 1. Fork the repository
543
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
544
+ 3. Run the tests (`bundle exec rspec`)
545
+ 4. Commit your changes (`git commit -m 'Add amazing feature'`)
546
+ 5. Push to the branch (`git push origin feature/amazing-feature`)
547
+ 6. Open a Pull Request
548
+
549
+ ## 📄 License
550
+
551
+ This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
552
+
553
+ ---
554
+
555
+ **Made with ❤️ by [sebyx07](https://github.com/sebyx07) and [contributors](https://github.com/sebyx07/better_structure_sql/graphs/contributors)**
556
+
557
+ ⭐ **Star this repo if you find it useful!** ⭐
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterStructureSql
4
+ # Base controller for BetterStructureSql Rails Engine
5
+ #
6
+ # Provides authentication and authorization hooks for the web UI
7
+ # that displays stored schema versions. By default, no authentication
8
+ # is required (open access), but this should be overridden in production.
9
+ #
10
+ # @example Using Devise route constraints (recommended)
11
+ # authenticate :user, ->(user) { user.admin? } do
12
+ # mount BetterStructureSql::Engine, at: "/better_structure_sql"
13
+ # end
14
+ #
15
+ # @example Using controller-level authentication
16
+ # BetterStructureSql::ApplicationController.class_eval do
17
+ # before_action :authenticate_admin!
18
+ #
19
+ # private
20
+ #
21
+ # def authenticate_admin!
22
+ # head :unauthorized unless current_user&.admin?
23
+ # end
24
+ # end
25
+ class ApplicationController < ActionController::Base
26
+ layout 'better_structure_sql/application'
27
+
28
+ # Override this method in your host application to add authentication
29
+ # Example using Devise route constraints (recommended):
30
+ # authenticate :user, ->(user) { user.admin? } do
31
+ # mount BetterStructureSql::Engine, at: "/better_structure_sql"
32
+ # end
33
+ #
34
+ # Or override at controller level:
35
+ # BetterStructureSql::ApplicationController.class_eval do
36
+ # before_action :authenticate_admin!
37
+ #
38
+ # private
39
+ #
40
+ # def authenticate_admin!
41
+ # head :unauthorized unless current_user&.admin?
42
+ # end
43
+ # end
44
+ before_action :authenticate_access!
45
+
46
+ private
47
+
48
+ # Authentication hook for engine access control
49
+ #
50
+ # Default implementation allows open access. Override this method
51
+ # in your host application to add authentication and authorization.
52
+ # This method is called before all controller actions via before_action.
53
+ #
54
+ # @return [Boolean] true to allow access, false or head :unauthorized to deny
55
+ def authenticate_access!
56
+ # Default: no authentication (open access)
57
+ # Override this in your host application for production use
58
+ true
59
+ end
60
+ end
61
+ end