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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +41 -0
- data/LICENSE +21 -0
- data/README.md +557 -0
- data/app/controllers/better_structure_sql/application_controller.rb +61 -0
- data/app/controllers/better_structure_sql/schema_versions_controller.rb +243 -0
- data/app/helpers/better_structure_sql/schema_versions_helper.rb +46 -0
- data/app/views/better_structure_sql/schema_versions/index.html.erb +110 -0
- data/app/views/better_structure_sql/schema_versions/show.html.erb +186 -0
- data/app/views/layouts/better_structure_sql/application.html.erb +105 -0
- data/config/database.yml +3 -0
- data/config/routes.rb +12 -0
- data/lib/better_structure_sql/adapters/base_adapter.rb +234 -0
- data/lib/better_structure_sql/adapters/mysql_adapter.rb +476 -0
- data/lib/better_structure_sql/adapters/mysql_config.rb +32 -0
- data/lib/better_structure_sql/adapters/postgresql_adapter.rb +646 -0
- data/lib/better_structure_sql/adapters/postgresql_config.rb +25 -0
- data/lib/better_structure_sql/adapters/registry.rb +115 -0
- data/lib/better_structure_sql/adapters/sqlite_adapter.rb +644 -0
- data/lib/better_structure_sql/adapters/sqlite_config.rb +26 -0
- data/lib/better_structure_sql/configuration.rb +129 -0
- data/lib/better_structure_sql/database_version.rb +46 -0
- data/lib/better_structure_sql/dependency_resolver.rb +63 -0
- data/lib/better_structure_sql/dumper.rb +544 -0
- data/lib/better_structure_sql/engine.rb +28 -0
- data/lib/better_structure_sql/file_writer.rb +180 -0
- data/lib/better_structure_sql/formatter.rb +70 -0
- data/lib/better_structure_sql/generators/base.rb +33 -0
- data/lib/better_structure_sql/generators/domain_generator.rb +22 -0
- data/lib/better_structure_sql/generators/extension_generator.rb +23 -0
- data/lib/better_structure_sql/generators/foreign_key_generator.rb +43 -0
- data/lib/better_structure_sql/generators/function_generator.rb +33 -0
- data/lib/better_structure_sql/generators/index_generator.rb +50 -0
- data/lib/better_structure_sql/generators/materialized_view_generator.rb +31 -0
- data/lib/better_structure_sql/generators/pragma_generator.rb +23 -0
- data/lib/better_structure_sql/generators/sequence_generator.rb +27 -0
- data/lib/better_structure_sql/generators/table_generator.rb +126 -0
- data/lib/better_structure_sql/generators/trigger_generator.rb +54 -0
- data/lib/better_structure_sql/generators/type_generator.rb +47 -0
- data/lib/better_structure_sql/generators/view_generator.rb +27 -0
- data/lib/better_structure_sql/introspection/extensions.rb +29 -0
- data/lib/better_structure_sql/introspection/foreign_keys.rb +29 -0
- data/lib/better_structure_sql/introspection/functions.rb +29 -0
- data/lib/better_structure_sql/introspection/indexes.rb +29 -0
- data/lib/better_structure_sql/introspection/sequences.rb +29 -0
- data/lib/better_structure_sql/introspection/tables.rb +29 -0
- data/lib/better_structure_sql/introspection/triggers.rb +29 -0
- data/lib/better_structure_sql/introspection/types.rb +37 -0
- data/lib/better_structure_sql/introspection/views.rb +41 -0
- data/lib/better_structure_sql/introspection.rb +31 -0
- data/lib/better_structure_sql/manifest_generator.rb +65 -0
- data/lib/better_structure_sql/migration_patch.rb +196 -0
- data/lib/better_structure_sql/pg_version.rb +44 -0
- data/lib/better_structure_sql/railtie.rb +124 -0
- data/lib/better_structure_sql/schema_loader.rb +168 -0
- data/lib/better_structure_sql/schema_version.rb +86 -0
- data/lib/better_structure_sql/schema_versions.rb +213 -0
- data/lib/better_structure_sql/version.rb +5 -0
- data/lib/better_structure_sql/zip_generator.rb +81 -0
- data/lib/better_structure_sql.rb +81 -0
- data/lib/generators/better_structure_sql/install_generator.rb +44 -0
- data/lib/generators/better_structure_sql/migration_generator.rb +34 -0
- data/lib/generators/better_structure_sql/templates/README +49 -0
- data/lib/generators/better_structure_sql/templates/add_metadata_migration.rb.erb +25 -0
- data/lib/generators/better_structure_sql/templates/better_structure_sql.rb +46 -0
- data/lib/generators/better_structure_sql/templates/migration.rb.erb +26 -0
- data/lib/tasks/better_structure_sql.rake +190 -0
- 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
|
+
[](https://badge.fury.io/rb/better_structure_sql)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
[](https://www.ruby-lang.org/)
|
|
11
|
+
[](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
|