better_structure_sql 0.1.0 → 0.2.1

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.md +240 -31
  4. data/app/controllers/better_structure_sql/schema_versions_controller.rb +5 -4
  5. data/app/views/better_structure_sql/schema_versions/index.html.erb +6 -0
  6. data/app/views/better_structure_sql/schema_versions/show.html.erb +13 -1
  7. data/lib/better_structure_sql/adapters/base_adapter.rb +18 -0
  8. data/lib/better_structure_sql/adapters/mysql_adapter.rb +199 -4
  9. data/lib/better_structure_sql/adapters/postgresql_adapter.rb +321 -37
  10. data/lib/better_structure_sql/adapters/sqlite_adapter.rb +218 -59
  11. data/lib/better_structure_sql/configuration.rb +12 -10
  12. data/lib/better_structure_sql/dumper.rb +230 -102
  13. data/lib/better_structure_sql/errors.rb +24 -0
  14. data/lib/better_structure_sql/file_writer.rb +2 -1
  15. data/lib/better_structure_sql/generators/base.rb +38 -0
  16. data/lib/better_structure_sql/generators/comment_generator.rb +118 -0
  17. data/lib/better_structure_sql/generators/domain_generator.rb +2 -1
  18. data/lib/better_structure_sql/generators/index_generator.rb +3 -1
  19. data/lib/better_structure_sql/generators/table_generator.rb +45 -20
  20. data/lib/better_structure_sql/generators/type_generator.rb +5 -3
  21. data/lib/better_structure_sql/schema_loader.rb +3 -3
  22. data/lib/better_structure_sql/schema_version.rb +17 -1
  23. data/lib/better_structure_sql/schema_versions.rb +223 -20
  24. data/lib/better_structure_sql/store_result.rb +46 -0
  25. data/lib/better_structure_sql/version.rb +1 -1
  26. data/lib/better_structure_sql.rb +4 -1
  27. data/lib/generators/better_structure_sql/templates/README +1 -1
  28. data/lib/generators/better_structure_sql/templates/migration.rb.erb +2 -0
  29. data/lib/tasks/better_structure_sql.rake +35 -18
  30. metadata +4 -2
  31. data/lib/generators/better_structure_sql/templates/add_metadata_migration.rb.erb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e66ec3fc122539bebd5d502233e08b258246a16f8567dbc5fb88bcdb4b98486
4
- data.tar.gz: 0d7bdeaaa4b1e356d3f506fbeefd1e4e20c2e306b469ebe9184e2ab80b224b2e
3
+ metadata.gz: d309fdf24a779a29028226f4e0926d28087b9045fdff1b9625522bdac430f169
4
+ data.tar.gz: db6dbe765d3d385a1b8867d3ad1f54825f7cbeed887ab17b7e02a06f63d5ef48
5
5
  SHA512:
6
- metadata.gz: 357c7013b0db9e2aed20714750783fc5b386cf21bb6bff014b37a613c6aaf3b48e52eabb965b9f75e7a71af5ca136cc1a0b604108d7bb1e4910ad631c36b5bf5
7
- data.tar.gz: cb8046cbfd1b37a4ccdcde40b85dc5461b2b73f179536f88bd4376fcd91fa0ea865edbf7b8936e3524fa138719c5656aa64b0cffdc21f7dbc1fef9b4a14514c8
6
+ metadata.gz: 6d2f15acedf160011639a0653dce7c639cf6e825c4e9a9638bf76e3262ee02d1cd76fc6726b3ff79c03a6054953f2310d6f61fd92af87974face17888574640c
7
+ data.tar.gz: c559251fe213ffabf576ab234ded58970dd54905813db0e6d3c9ee45a951a9435feac53d05eb93c4758df40829b6e91af509eebe647a72349eb036e12df52283
data/CHANGELOG.md CHANGED
@@ -13,6 +13,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Fixed
15
15
 
16
+ ## [0.2.1] - 2025-11-20
17
+
18
+ ### Changed
19
+ - Improved schema version web UI with content hash display (first 8 characters)
20
+ - Increased view limit for better visibility of stored schema versions
21
+
22
+ ## [0.2.0] - 2025-11-20
23
+
24
+ ### Added
25
+ - **Database comments support** - COMMENT ON statements for PostgreSQL and MySQL
26
+ - Comments on tables, columns, indexes, views, functions, and triggers
27
+ - CommentGenerator for generating COMMENT ON SQL statements
28
+ - CommentIntrospector for querying pg_description and information_schema
29
+ - Configurable via `include_comments` option (enabled by default)
30
+ - 10_comments directory in multi-file output with load order after triggers
31
+ - Full test coverage for PostgreSQL and MySQL comment introspection
32
+ - **Hash-based schema version deduplication** - Automatic duplicate detection using MD5 content hashing
33
+ - `content_hash` column (VARCHAR 32) stores MD5 hexdigest of schema content
34
+ - Automatic skip when schema unchanged between storage attempts
35
+ - StoreResult value object for skip/store state communication
36
+ - Filesystem cleanup: delete multi-file directories after ZIP storage
37
+ - Enhanced rake task output showing skip reason or stored confirmation with hash
38
+ - `db:schema:versions` task now displays first 8 characters of content hash
39
+ - Content size and line count automatic tracking
40
+ - Streaming file reads (4MB chunks) for memory-efficient hash calculation
41
+ - Integration with retention management (cleanup only on actual storage)
42
+ - 29 new tests for deduplication workflow (all 355 tests passing)
43
+
44
+ ### Changed
45
+ - **BREAKING**: Schema versions table requires `content_hash` column
46
+ - Run `rails generate better_structure_sql:migration` to add column
47
+ - Existing versions backfilled with calculated MD5 hash during migration
48
+ - `SchemaVersions.store_current` now returns `StoreResult` instead of `SchemaVersion`
49
+ - Use `result.stored?` or `result.skipped?` to check operation type
50
+ - Access version via `result.version` when stored
51
+ - `SchemaVersions.store` now requires `content_hash:` parameter
52
+ - `SchemaVersion.latest` changed from scope to class method (returns record, not Relation)
53
+ - Multi-file directories automatically cleaned up after ZIP archive creation
54
+ - Integration apps configured to use multi-file schema dumps by default
55
+ - Migration numbering scheme changed to support comments directory (20 directories)
56
+
57
+ ### Fixed
58
+ - MySQL compatibility: Removed IF NOT EXISTS from index and type creation
59
+ - Hash calculation now excludes manifest.json to avoid circular dependencies
60
+ - FileWriter properly maps comments directory to correct load order
61
+ - CodeBlock component supports both code prop and children for flexibility
62
+
16
63
  ## [0.1.0] - 2025-11-20
17
64
 
18
65
  ### Added
data/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  </div>
18
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!
19
+ > **⚠️ Beta Notice**: Version 0.2.1 is feature-complete and production-ready for **PostgreSQL**. Multi-database support (MySQL, SQLite) is implemented but considered experimental. APIs are stable but may see minor refinements before v1.0. We welcome feedback and contributions!
20
20
 
21
21
  ## ✨ Why BetterStructureSql?
22
22
 
@@ -67,7 +67,7 @@ Rails' database dump tools (`pg_dump`, `mysqldump`, etc.) create noisy `structur
67
67
  | **Materialized Views** | ✅ | ❌ | ❌ |
68
68
  | **Functions** | ✅ plpgsql, sql | ✅ Stored procedures | ❌ |
69
69
  | **Triggers** | ✅ BEFORE/AFTER/INSTEAD OF | ✅ BEFORE/AFTER | ✅ BEFORE/AFTER |
70
- | **Partitioned Tables** | RANGE/LIST/HASH | ❌ | ❌ |
70
+ | **Partitioned Tables** | 🚧 Planned | ❌ | ❌ |
71
71
  | **Domains** | ✅ | ❌ | ❌ |
72
72
 
73
73
  ### Getting Started by Database
@@ -95,15 +95,16 @@ Rails' database dump tools (`pg_dump`, `mysqldump`, etc.) create noisy `structur
95
95
  - Custom types and enums (PostgreSQL, MySQL SET/ENUM)
96
96
 
97
97
  ### Multi-File Schema Output (Optional)
98
- - **Massive schema support** - Handle tens of thousands of tables effortlessly
98
+ - **Massive schema support** - Designed to handle tens of thousands of database objects
99
99
  - **Directory-based output** - Split schema across organized, numbered directories
100
- - **Smart chunking** - 500 LOC per file with intelligent overflow handling
100
+ - **Smart chunking** - 500 LOC per file (configurable) with intelligent overflow handling
101
101
  - **Better git diffs** - See only changed files, not entire schema
102
102
  - **ZIP downloads** - Download complete directory structure as archive
103
- - **Easy navigation** - Find tables quickly in `4_tables/`, triggers in `9_triggers/`, etc.
103
+ - **Easy navigation** - Find tables quickly in `05_tables/`, triggers in `09_triggers/`, etc.
104
104
 
105
105
  ### Schema Versioning (Optional)
106
106
  - Store schema versions in database with metadata
107
+ - **Hash-based deduplication** - Automatically skip storing when schema unchanged
107
108
  - Track database type and version, format type (SQL/Ruby), creation timestamp
108
109
  - ZIP archive storage for multi-file schemas
109
110
  - Configurable retention policy (keep last N versions)
@@ -141,9 +142,11 @@ Rails' database dump tools (`pg_dump`, `mysqldump`, etc.) create noisy `structur
141
142
  ```ruby
142
143
  # Gemfile
143
144
  gem 'better_structure_sql'
144
- gem 'pg' # or 'mysql2' or 'sqlite3'
145
+ gem 'pg' # For PostgreSQL (or 'mysql2' for MySQL, or 'sqlite3' for SQLite)
145
146
  ```
146
147
 
148
+ **Database adapter is auto-detected** from your `ActiveRecord::Base.connection.adapter_name`. No manual configuration needed!
149
+
147
150
  ```bash
148
151
  bundle install
149
152
  rails generate better_structure_sql:install
@@ -152,6 +155,128 @@ rails db:schema:dump_better
152
155
 
153
156
  **🎉 Your `db/structure.sql` is now clean and maintainable!**
154
157
 
158
+ ## 📦 Schema Versioning with Deduplication
159
+
160
+ BetterStructureSql automatically tracks schema evolution by storing versions in your database. Hash-based deduplication ensures only meaningful schema changes are recorded.
161
+
162
+ ### How It Works
163
+
164
+ When you run `rails db:schema:store`, the gem:
165
+
166
+ 1. **Reads** your current schema files (single or multi-file)
167
+ 2. **Calculates** MD5 hash of the complete schema content
168
+ 3. **Compares** with the most recent stored version's hash
169
+ 4. **Skips storage** if hash matches (no changes detected) ✨
170
+ 5. **Creates new version** if hash differs (schema changed)
171
+
172
+ ### Quick Example
173
+
174
+ ```bash
175
+ # After migrations, dump and store schema
176
+ rails db:migrate
177
+ rails db:schema:dump_better
178
+ rails db:schema:store
179
+
180
+ # First run (no previous version)
181
+ # =>
182
+ # Stored schema version #1
183
+ # Format: sql
184
+ # Mode: single_file
185
+ # PostgreSQL: 15.4
186
+ # Size: 45.2 KB
187
+ # Hash: a3f5c9d2e8b1f4a6c7e9d3f1b5a8c2e4
188
+ # Total versions: 1
189
+
190
+ # Second run (no schema changes)
191
+ # =>
192
+ # No schema changes detected
193
+ # Current schema matches version #1
194
+ # Hash: a3f5c9d2e8b1f4a6c7e9d3f1b5a8c2e4
195
+ # No new version stored
196
+ # Total versions: 1
197
+
198
+ # After adding a table
199
+ rails db:migrate # Adds new table
200
+ rails db:schema:dump_better
201
+ rails db:schema:store
202
+
203
+ # =>
204
+ # Stored schema version #2
205
+ # Format: sql
206
+ # Mode: single_file
207
+ # PostgreSQL: 15.4
208
+ # Size: 48.7 KB
209
+ # Hash: b7e2d1c4f9a6c3e5d8b2f1a4c9e7d3b6
210
+ # Total versions: 2
211
+ ```
212
+
213
+ ### Production Workflow
214
+
215
+ Perfect for deployment automation:
216
+
217
+ ```ruby
218
+ # config/deploy.rb or GitHub Actions
219
+ namespace :deploy do
220
+ task :update_schema do
221
+ # Run migrations (may be zero)
222
+ # Rails automatically dumps schema after migrations
223
+ execute :rake, 'db:migrate'
224
+
225
+ # Store schema version only if changed (automatic deduplication)
226
+ execute :rake, 'db:schema:store'
227
+ end
228
+ end
229
+ ```
230
+
231
+ **Benefits in Production:**
232
+ - ✅ Deploys without migrations don't create duplicate versions
233
+ - ✅ Developers see clean schema evolution timeline
234
+ - ✅ Storage efficient (no duplicate content)
235
+ - ✅ Clear audit trail of actual schema changes
236
+
237
+ ### Viewing Stored Versions
238
+
239
+ ```bash
240
+ # List all versions with hashes
241
+ rails db:schema:versions
242
+
243
+ Schema Versions (3 total)
244
+
245
+ ID | Format | Mode | Files | PostgreSQL | Hash | Created | Size
246
+ -----|--------|-------------|-------|------------|----------|---------------------|-------
247
+ 3 | sql | multi_file | 47 | 15.4 | a3f5c9d2 | 2025-01-20 14:30:15 | 125 KB
248
+ 2 | sql | single_file | - | 15.4 | b7e2d1c4 | 2025-01-19 10:15:42 | 98 KB
249
+ 1 | sql | single_file | - | 15.3 | c9f8a3b2 | 2025-01-18 08:45:30 | 85 KB
250
+ ```
251
+
252
+ ### Configuration
253
+
254
+ ```ruby
255
+ # config/initializers/better_structure_sql.rb
256
+ BetterStructureSql.configure do |config|
257
+ # Enable schema versioning
258
+ config.enable_schema_versions = true
259
+
260
+ # Retain 10 most recent unique versions (0 = unlimited)
261
+ config.schema_versions_limit = 10
262
+ end
263
+ ```
264
+
265
+ ### Web UI Access
266
+
267
+ Developers can view stored schema versions via the web UI without database access:
268
+
269
+ ```ruby
270
+ # config/routes.rb
271
+ authenticate :user, ->(user) { user.admin? } do
272
+ mount BetterStructureSql::Engine, at: '/schema_versions'
273
+ end
274
+ ```
275
+
276
+ Navigate to `/schema_versions` to browse versions, view formatted schema, and download raw SQL files.
277
+
278
+ 📖 See [Schema Versioning Documentation](docs/schema_versions.md) for complete details.
279
+
155
280
  ## Docker Development Environment 🐳
156
281
 
157
282
  Get started with a fully configured development environment in seconds:
@@ -284,14 +409,21 @@ BetterStructureSql.configure do |config|
284
409
  config.enable_schema_versions = true
285
410
  config.schema_versions_limit = 10 # Keep last 10 versions (0 = unlimited)
286
411
 
287
- # Customize output
412
+ # Customize output (feature toggles)
288
413
  config.include_extensions = true
289
414
  config.include_functions = true
290
415
  config.include_triggers = true
291
416
  config.include_views = true
292
-
293
- # Search path
417
+ config.include_materialized_views = true # PostgreSQL only
418
+ config.include_domains = true # PostgreSQL only
419
+ config.include_sequences = true # PostgreSQL only
420
+ config.include_custom_types = true # PostgreSQL ENUM, MySQL ENUM/SET
421
+ # config.include_rules = false # Not yet implemented
422
+ # config.include_comments = false # Not yet implemented
423
+
424
+ # Search path and schema filtering
294
425
  config.search_path = '"$user", public'
426
+ config.schemas = ['public'] # Which schemas to dump
295
427
  end
296
428
  ```
297
429
 
@@ -314,11 +446,20 @@ BetterStructureSql.configure do |config|
314
446
  config.enable_schema_versions = true
315
447
  config.schema_versions_limit = 10
316
448
 
317
- # Feature toggles
449
+ # Feature toggles (same as single-file mode)
318
450
  config.include_extensions = true
319
451
  config.include_functions = true
320
452
  config.include_triggers = true
321
453
  config.include_views = true
454
+ config.include_materialized_views = true
455
+ config.include_domains = true
456
+ config.include_sequences = true
457
+ config.include_custom_types = true
458
+
459
+ # Formatting options
460
+ config.indent_size = 2 # SQL indentation (default: 2)
461
+ config.add_section_spacing = true # Add blank lines between sections
462
+ config.sort_tables = true # Sort tables alphabetically
322
463
  end
323
464
  ```
324
465
 
@@ -330,34 +471,67 @@ When using `config.output_path = 'db/schema'`, your schema is organized by type
330
471
  db/schema/
331
472
  ├── _header.sql # SET statements and search path
332
473
  ├── _manifest.json # Metadata and load order
333
- ├── 1_extensions/
474
+ ├── 01_extensions/
334
475
  │ └── 000001.sql
335
- ├── 2_types/
476
+ ├── 02_types/
336
477
  │ └── 000001.sql
337
- ├── 3_sequences/
478
+ ├── 03_functions/
338
479
  │ └── 000001.sql
339
- ├── 4_tables/
480
+ ├── 04_sequences/
481
+ │ └── 000001.sql
482
+ ├── 05_tables/
340
483
  │ ├── 000001.sql # ~500 lines per file
341
484
  │ ├── 000002.sql
342
485
  │ └── 000003.sql
343
- ├── 5_indexes/
486
+ ├── 06_indexes/
487
+ │ └── 000001.sql
488
+ ├── 07_foreign_keys/
344
489
  │ └── 000001.sql
345
- ├── 6_foreign_keys/
490
+ ├── 08_views/
346
491
  │ └── 000001.sql
347
- ├── 7_views/
492
+ ├── 09_triggers/
348
493
  │ └── 000001.sql
349
- ├── 8_functions/
494
+ ├── 10_comments/
350
495
  │ └── 000001.sql
351
- └── 9_triggers/
496
+ └── 20_migrations/
352
497
  └── 000001.sql
353
498
  ```
354
499
 
355
500
  **Benefits for Large Schemas**:
356
501
  - ✅ Memory efficient - incremental file writing
357
502
  - ✅ Git friendly - only changed files in diffs
358
- - ✅ Easy navigation - find specific tables/triggers quickly
503
+ - ✅ Easy navigation - find specific tables in `05_tables/`, triggers in `09_triggers/`, etc.
359
504
  - ✅ ZIP downloads - complete directory as single archive
360
505
  - ✅ Scalable - handles 50,000+ database objects
506
+ - ✅ AI-friendly - 500-line chunks work better with LLM context windows
507
+
508
+ **Manifest File (_manifest.json)**:
509
+
510
+ The manifest tracks metadata and provides load order information:
511
+
512
+ ```json
513
+ {
514
+ "version": "1.0",
515
+ "total_files": 11,
516
+ "total_lines": 2345,
517
+ "max_lines_per_file": 500,
518
+ "directories": {
519
+ "01_extensions": { "files": 1, "lines": 3 },
520
+ "02_types": { "files": 1, "lines": 13 },
521
+ "03_functions": { "files": 1, "lines": 332 },
522
+ "04_sequences": { "files": 1, "lines": 289 },
523
+ "05_tables": { "files": 2, "lines": 979 },
524
+ "06_indexes": { "files": 1, "lines": 397 },
525
+ "07_foreign_keys": { "files": 1, "lines": 67 },
526
+ "08_views": { "files": 1, "lines": 217 },
527
+ "09_triggers": { "files": 1, "lines": 35 },
528
+ "10_comments": { "files": 1, "lines": 9 },
529
+ "20_migrations": { "files": 1, "lines": 13 }
530
+ }
531
+ }
532
+ ```
533
+
534
+ This example shows a real schema with 2,345 lines split across 11 files. The `05_tables` directory has 2 files because the tables exceed the 500-line limit.
361
535
 
362
536
  ## 📝 Usage & Rake Tasks
363
537
 
@@ -394,15 +568,17 @@ rails db:schema:versions
394
568
 
395
569
  Output example:
396
570
  ```
397
- Total versions: 5
571
+ Total versions: 3
398
572
 
399
573
  ID Format Mode Files PostgreSQL Created Size
400
574
  -----------------------------------------------------------------------------------------------
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
575
+ 3 sql multi_file 12 15.3 2025-01-15 10:30:22 56.42 KB
576
+ 2 sql single_file 1 15.3 2025-01-14 15:20:10 45.21 KB
577
+ 1 sql single_file 1 15.2 2025-01-13 09:45:33 44.03 KB
404
578
  ```
405
579
 
580
+ The multi-file mode example shows 12 files across 10 directories (extensions, types, functions, sequences, tables, indexes, foreign_keys, views, triggers, migrations) stored as a ZIP archive.
581
+
406
582
  **Restore from Version**
407
583
  ```bash
408
584
  # Restore database from a specific version
@@ -436,10 +612,12 @@ end
436
612
  ```
437
613
 
438
614
  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
615
+ - View list of up to 100 most recent schema versions (pagination-ready)
616
+ - Browse formatted schema content with syntax highlighting (for files <200KB)
617
+ - Download raw SQL/Ruby schema files as text
442
618
  - Download ZIP archives for multi-file schemas
619
+ - View manifest metadata for multi-file schemas
620
+ - Stream large files efficiently (>2MB) without memory issues
443
621
  - Compare database versions and formats
444
622
 
445
623
  **Authentication Examples**:
@@ -503,10 +681,13 @@ fi
503
681
  |-----------|---------|-------|
504
682
  | **Ruby** | 2.7+ | Tested up to Ruby 3.4.7 |
505
683
  | **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+ |
684
+ | **rubyzip** | ≥ 2.0.0 | Required for ZIP archive support |
685
+ | **Database Adapter** | | |
686
+ | `pg` | ≥ 1.0 | **Required dependency**. Works with PostgreSQL 12+ |
687
+ | `mysql2` | ≥ 0.5 | Optional. For MySQL 8.0+ (experimental) |
688
+ | `sqlite3` | ≥ 1.4 | Optional. For SQLite 3.35+ (experimental) |
689
+
690
+ **Note**: The gem currently requires the `pg` gem as a dependency. Multi-database support (MySQL, SQLite) is implemented but requires manual gem installation. Future versions may make database adapters optional.
510
691
 
511
692
  ## Migration Guides
512
693
 
@@ -533,6 +714,34 @@ BetterStructureSql supports **both** `schema.rb` and `structure.sql` formats, al
533
714
 
534
715
  ---
535
716
 
717
+ ## 📊 Project Stats
718
+
719
+ **Codebase Metrics** (as of v0.1.0):
720
+ - **47 Ruby files** in `lib/` (~5,296 total lines)
721
+ - **25 test files** in `spec/` (~3,022 lines)
722
+ - **8 adapter files** (PostgreSQL, MySQL, SQLite, Registry, Configs)
723
+ - **13 SQL generators** (Tables, Indexes, Functions, Triggers, Views, etc.)
724
+ - **9 introspection modules** (Extensions, Types, Tables, Indexes, Foreign Keys, etc.)
725
+ - **3 integration apps** (PostgreSQL, MySQL, SQLite) with Docker support
726
+ - **React documentation site** deployed to GitHub Pages
727
+
728
+ **Test Coverage**: Comprehensive RSpec test suite with unit and integration tests across all major components.
729
+
730
+ **Real-World Example**: The integration app generates a multi-file schema with:
731
+ - 11 SQL files across 10 directories
732
+ - 2,345 total lines of SQL
733
+ - Complete PostgreSQL feature coverage (extensions, types, functions, triggers, materialized views)
734
+
735
+ **Production Status**:
736
+ - ✅ **PostgreSQL**: Fully implemented and tested (primary focus)
737
+ - ✅ **Multi-file output**: Complete with ZIP storage and streaming
738
+ - ✅ **Schema versioning**: Full CRUD with web UI
739
+ - ✅ **Rails integration**: Drop-in replacement for default tasks
740
+ - 🧪 **MySQL**: Adapter implemented, integration app available (experimental)
741
+ - 🧪 **SQLite**: Adapter implemented, basic testing (experimental)
742
+
743
+ ---
744
+
536
745
  ## 🤝 Contributing
537
746
 
538
747
  We welcome contributions! Bug reports and pull requests are welcome on [GitHub](https://github.com/sebyx07/better_structure_sql).
@@ -11,8 +11,9 @@ module BetterStructureSql
11
11
  class SchemaVersionsController < ApplicationController
12
12
  # Maximum file size to load into memory (2MB)
13
13
  MAX_MEMORY_SIZE = 2.megabytes
14
- # Maximum file size to display in browser (200KB)
15
- MAX_DISPLAY_SIZE = 200.kilobytes
14
+ # Maximum file size to display in browser (1MB)
15
+ # Large enough for most schemas but keeps browser responsive
16
+ MAX_DISPLAY_SIZE = 1.megabyte
16
17
 
17
18
  # Lists stored schema versions with pagination
18
19
  #
@@ -25,7 +26,7 @@ module BetterStructureSql
25
26
  # Load only metadata for listing (no content or zip_archive)
26
27
  @schema_versions = SchemaVersion
27
28
  .select(:id, :pg_version, :format_type, :output_mode, :created_at,
28
- :content_size, :file_count)
29
+ :content_size, :file_count, :content_hash)
29
30
  .order(created_at: :desc)
30
31
  .limit(100)
31
32
  end
@@ -43,7 +44,7 @@ module BetterStructureSql
43
44
  # Load metadata first
44
45
  @schema_version = SchemaVersion
45
46
  .select(:id, :pg_version, :format_type, :output_mode, :created_at,
46
- :content_size, :line_count, :file_count)
47
+ :content_size, :line_count, :file_count, :content_hash)
47
48
  .find(params[:id])
48
49
 
49
50
  # Only load content for small single-file versions
@@ -27,6 +27,7 @@
27
27
  <thead class="table-light">
28
28
  <tr>
29
29
  <th scope="col" class="text-center" style="width: 80px;">ID</th>
30
+ <th scope="col" style="width: 120px;">Hash</th>
30
31
  <th scope="col" style="width: 120px;">Format</th>
31
32
  <th scope="col" style="width: 150px;">Mode</th>
32
33
  <th scope="col" style="width: 180px;">PostgreSQL</th>
@@ -42,6 +43,11 @@
42
43
  <td class="text-center fw-bold text-muted">
43
44
  #<%= version.id %>
44
45
  </td>
46
+ <td>
47
+ <code class="text-muted small" title="<%= version.content_hash %>">
48
+ <%= version.content_hash[0..7] %>
49
+ </code>
50
+ </td>
45
51
  <td>
46
52
  <%= format_type_badge(version.format_type) %>
47
53
  </td>
@@ -93,6 +93,18 @@
93
93
  </p>
94
94
  </div>
95
95
  </div>
96
+
97
+ <div class="row mt-3">
98
+ <div class="col-md-12">
99
+ <h6 class="text-muted mb-1">
100
+ <i class="bi bi-fingerprint"></i>
101
+ Content Hash (MD5)
102
+ </h6>
103
+ <p class="mb-0">
104
+ <code class="text-muted"><%= @schema_version.content_hash %></code>
105
+ </p>
106
+ </div>
107
+ </div>
96
108
  </div>
97
109
  </div>
98
110
 
@@ -153,7 +165,7 @@
153
165
  <i class="bi bi-exclamation-triangle"></i>
154
166
  <strong>File too large to display</strong>
155
167
  <p class="mb-0 mt-2">
156
- This schema file is too large to display in the browser (limit: 200 KB).
168
+ This schema file is too large to display in the browser (limit: 1 MB).
157
169
  Please use the "Download" button above to download and view it locally.
158
170
  </p>
159
171
  </div>
@@ -112,6 +112,17 @@ module BetterStructureSql
112
112
  raise NotImplementedError, "#{self.class} must implement #fetch_triggers"
113
113
  end
114
114
 
115
+ # Fetch comments on database objects
116
+ #
117
+ # @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection
118
+ # @return [Hash] Hash with object types as keys (:tables, :columns, :indexes, etc.)
119
+ # Each value is a hash mapping object identifier to comment text
120
+ # Example: { tables: { 'users' => 'User accounts', ... }, columns: { 'users.email' => 'Email address', ... } }
121
+ # @raise [NotImplementedError] If not implemented by subclass
122
+ def fetch_comments(connection)
123
+ raise NotImplementedError, "#{self.class} must implement #fetch_comments"
124
+ end
125
+
115
126
  # Capability methods - indicate feature support
116
127
 
117
128
  # Indicates whether this database supports extensions (like PostgreSQL extensions)
@@ -163,6 +174,13 @@ module BetterStructureSql
163
174
  false
164
175
  end
165
176
 
177
+ # Indicates whether this database supports comments on database objects
178
+ #
179
+ # @return [Boolean] True if comments are supported, false otherwise
180
+ def supports_comments?
181
+ false
182
+ end
183
+
166
184
  # Version detection
167
185
 
168
186
  # Detect the database version