rails-uuid-pk 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ef202d7fd8ed44687383011c2306cdafc16fc9a05505270c270a753d4fd4a33
4
- data.tar.gz: fd9416e86ae299c7d693fcba9bc0e71d179940cd4e1e29dbd4bfc892e30e0248
3
+ metadata.gz: 46d317c27d7ed27fb503bba3020d93e48f770e2492c8561c347544c9e8d4db4f
4
+ data.tar.gz: 39ed2abf06c8424ae2e431ee5cd09e20849a475c671266e6be7345768473bffd
5
5
  SHA512:
6
- metadata.gz: 4f675cb556f985b0060cc34297182d5dbe1860a05cce42ce1b8de62e4b5f4ea89b07ae84669615dbb109d6f4c4bc0779c6a90bcaf9b0af3cc1b8d42b8588f8cc
7
- data.tar.gz: 9ac0c2032a0036bc9a5a7441391f30b3991c0557446605ac1bb9b35a100e8fdb9cad565443536ef4b833f3c7c0793ff085b51996e1d75a5e018472ff4edd92af
6
+ metadata.gz: eca0cdf854a9924f4268d3cf33d8c9b4c13061d569e9551e6ceb591873f406e5c451daccc26206b44ebcacd054a4ea4a7d486a32596790fd61a0ef61b5dd0380
7
+ data.tar.gz: 10852d080506a8305adf8c2c538a788d9f6790c2dec4770a7329f8cb2acaf95e66d2903daf8b69ac0753d6f16ec5c9e1d478e9841cc73088227b6f710711580f
data/ARCHITECTURE.md ADDED
@@ -0,0 +1,508 @@
1
+ # Architecture Overview
2
+
3
+ This document outlines the architectural decisions, design principles, and technical trade-offs made in rails-uuid-pk. It serves as a guide for understanding why certain approaches were chosen and the implications of those decisions.
4
+
5
+ ## Core Design Principles
6
+
7
+ ### Zero-Configuration Philosophy
8
+ **Decision**: Automatic UUIDv7 primary keys for all models by default
9
+ - **Rationale**: Maximize ease of adoption for Rails developers while modernizing primary key usage
10
+ - **Implementation**: Railtie-based automatic inclusion in `ActiveRecord::Base` with opt-out mechanism
11
+ - **Impact**: Just add the gem to Gemfile - all models use UUIDv7 PKs, exceptions require explicit opt-out
12
+
13
+ ### Database Agnosticism
14
+ **Decision**: Support PostgreSQL, MySQL, and SQLite with unified API
15
+ - **Rationale**: Enable database portability and CI/testing flexibility
16
+ - **Implementation**: Adapter-specific extensions with common interface
17
+ - **Impact**: Developers can switch databases without code changes
18
+
19
+ ### App-Level UUID Generation
20
+ **Decision**: Generate UUIDs in application code, not database
21
+ - **Rationale**: Maximum compatibility across database versions and types
22
+ - **Implementation**: `before_create` callback using `SecureRandom.uuid_v7`
23
+ - **Trade-offs**: No database-native UUID functions, but universal compatibility
24
+
25
+ ## Architectural Components
26
+
27
+ ### 1. Core Modules
28
+
29
+ #### Concern (`lib/rails_uuid_pk/concern.rb`)
30
+ ```ruby
31
+ module RailsUuidPk
32
+ module HasUuidv7PrimaryKey
33
+ extend ActiveSupport::Concern
34
+
35
+ included do
36
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? }
37
+ end
38
+
39
+ private
40
+
41
+ def assign_uuidv7_if_needed
42
+ # Skip if id was already set (manual set, bulk insert with ids, etc)
43
+ return if id.present?
44
+
45
+ uuid = SecureRandom.uuid_v7
46
+ RailsUuidPk.log(:debug, "Assigned UUIDv7 #{uuid} to #{self.class.name}")
47
+ self.id = uuid
48
+ end
49
+ end
50
+ end
51
+ ```
52
+
53
+ **Responsibilities**:
54
+ - UUIDv7 generation logic
55
+ - Defensive programming (only assign if id is nil)
56
+ - Hook into ActiveRecord lifecycle
57
+
58
+ #### Migration Helpers (`lib/rails_uuid_pk/migration_helpers.rb`)
59
+ **Responsibilities**:
60
+ - Automatic foreign key type detection
61
+ - Polymorphic association support
62
+ - Schema inspection and caching
63
+
64
+ #### Custom Type (`lib/rails_uuid_pk/type.rb`)
65
+ **Responsibilities**:
66
+ - UUID validation and casting
67
+ - Schema dumping compatibility
68
+ - Rails version awareness
69
+
70
+ #### Railtie (`lib/rails_uuid_pk/railtie.rb`)
71
+ **Responsibilities**:
72
+ - Automatic gem integration
73
+ - Database adapter extensions
74
+ - Generator configuration
75
+
76
+ #### Logging Framework (`lib/rails_uuid_pk.rb`)
77
+ **Responsibilities**:
78
+ - Structured logging infrastructure
79
+ - Rails logger integration with fallback
80
+ - Debug logging for UUID assignment, migration helpers, and adapter registration
81
+ - Production observability support
82
+ - Structured logging with `[RailsUuidPk]` prefix for easy filtering
83
+ - Compatible with existing Rails logging and monitoring systems (Datadog, CloudWatch, etc.)
84
+
85
+ ### 2. Database Adapter Extensions
86
+
87
+ #### PostgreSQL (Native Support)
88
+ - Uses PostgreSQL's native UUID type support (16 bytes)
89
+ - No adapter extension needed - Rails handles UUID types natively
90
+ - Full database function compatibility
91
+ - Optimized for PostgreSQL 18's enhanced UUID handling
92
+
93
+ #### Shared UUID Adapter Extension
94
+ ```ruby
95
+ # lib/rails_uuid_pk/uuid_adapter_extension.rb
96
+ module RailsUuidPk
97
+ module UuidAdapterExtension
98
+ # Common UUID type support methods shared by MySQL and SQLite adapters
99
+ def native_database_types
100
+ super.merge(uuid: { name: "varchar", limit: 36 })
101
+ end
102
+
103
+ def valid_type?(type)
104
+ return true if type == :uuid
105
+ super
106
+ end
107
+
108
+ def register_uuid_types(m = type_map)
109
+ RailsUuidPk.log(:debug, "Registering UUID types on #{m.class}")
110
+ m.register_type(/varchar\(36\)/i) { RailsUuidPk::Type::Uuid.new }
111
+ m.register_type("uuid") { RailsUuidPk::Type::Uuid.new }
112
+ end
113
+
114
+ def initialize_type_map(m = type_map)
115
+ super
116
+ register_uuid_types(m)
117
+ end
118
+
119
+ def configure_connection
120
+ super
121
+ register_uuid_types
122
+ end
123
+
124
+ def type_to_dump(column)
125
+ if column.type == :uuid
126
+ return [ :uuid, {} ]
127
+ end
128
+ super
129
+ end
130
+ end
131
+ end
132
+ ```
133
+
134
+ #### MySQL (`mysql2` gem integration)
135
+ ```ruby
136
+ # lib/rails_uuid_pk/mysql2_adapter_extension.rb
137
+ module RailsUuidPk
138
+ module Mysql2AdapterExtension
139
+ include UuidAdapterExtension
140
+
141
+ # MySQL-specific connection configuration
142
+ def configure_connection
143
+ super # Standard UUID type registration
144
+ end
145
+ end
146
+ end
147
+ ```
148
+
149
+ #### SQLite (`sqlite3` gem integration)
150
+ ```ruby
151
+ # lib/rails_uuid_pk/sqlite3_adapter_extension.rb
152
+ module RailsUuidPk
153
+ module Sqlite3AdapterExtension
154
+ include UuidAdapterExtension
155
+
156
+ # SQLite-specific connection configuration with transaction awareness
157
+ def configure_connection
158
+ # Only call super if not inside a transaction, as PRAGMA statements
159
+ # cannot be executed inside transactions in SQLite
160
+ super unless open_transactions > 0
161
+ end
162
+ end
163
+ end
164
+ ```
165
+
166
+ ## Key Architectural Decisions
167
+
168
+ ### Decision 1: App-Level vs Database-Level Generation
169
+
170
+ #### Chosen Approach: App-Level Generation
171
+ ```ruby
172
+ # In application code
173
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? }
174
+
175
+ def assign_uuidv7_if_needed
176
+ return if id.present?
177
+ self.id = SecureRandom.uuid_v7
178
+ end
179
+ ```
180
+
181
+ #### Alternative Considered: Database-Level Generation
182
+ ```sql
183
+ -- PostgreSQL native approach
184
+ CREATE TABLE users (
185
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
186
+ name VARCHAR(255)
187
+ );
188
+ ```
189
+
190
+ #### Trade-off Analysis
191
+
192
+ | Aspect | App-Level | Database-Level |
193
+ |--------|-----------|----------------|
194
+ | **Compatibility** | Universal (all DBs) | DB-specific functions required |
195
+ | **Performance** | Minimal overhead | Potentially faster (no app round-trip) |
196
+ | **Testing** | Consistent across environments | Requires DB function setup |
197
+ | **Migration** | App manages UUIDs | DB manages UUIDs |
198
+ | **Dependencies** | Ruby SecureRandom only | Database extensions/functions |
199
+ | **Consistency** | Guaranteed across transactions | Dependent on DB implementation |
200
+
201
+ #### Rationale for App-Level Choice
202
+ 1. **Universal Compatibility**: Works with any database without extensions
203
+ 2. **Testing Simplicity**: Same behavior in development, test, and production
204
+ 3. **Migration Safety**: UUIDs are assigned before database constraints
205
+ 4. **Zero Dependencies**: No database-specific setup or extensions required
206
+ 5. **Performance**: `SecureRandom.uuid_v7` is sufficiently fast for most applications
207
+
208
+ #### Bulk Operations Limitation
209
+ The app-level callback approach has one important limitation: bulk operations bypass ActiveRecord callbacks. This means operations like `Model.import` or `Model.insert_all` won't automatically generate UUIDs. Applications requiring bulk imports must explicitly assign UUIDs:
210
+
211
+ ```ruby
212
+ # Manual UUID assignment required for bulk operations
213
+ users = [{ name: "Alice", id: SecureRandom.uuid_v7 }, { name: "Bob", id: SecureRandom.uuid_v7 }]
214
+ User.insert_all(users) # Bypasses callbacks, requires explicit IDs
215
+ ```
216
+
217
+ This is a conscious trade-off for universal compatibility and zero-configuration benefits.
218
+
219
+ ### Decision 2: UUIDv7 vs Other UUID Versions
220
+
221
+ #### Chosen: UUIDv7 (RFC 9562)
222
+ - **Monotonic Ordering**: Time-based ordering reduces index fragmentation
223
+ - **Cryptographically Secure**: Uses system CSPRNG for randomness
224
+ - **Standard Compliant**: Latest UUID standard with time-based ordering
225
+ - **Database Friendly**: Better index locality than random UUIDs
226
+
227
+ #### Alternatives Considered
228
+ - **UUIDv4**: Random, maximum unpredictability, poor index performance
229
+ - **UUIDv1**: MAC address based, privacy concerns, time-ordered
230
+ - **Sequential IDs**: Auto-increment, predictable, good performance but security issues
231
+
232
+ #### UUIDv7 Advantages for Rails Applications
233
+ 1. **Index Performance**: Monotonic ordering improves B-tree efficiency
234
+ 2. **Audit Capabilities**: Time-based ordering enables temporal queries
235
+ 3. **Security**: Cryptographically secure generation
236
+ 4. **Standards Compliance**: RFC 9562 adherence
237
+
238
+ ### Decision 3: Railtie-Based Integration
239
+
240
+ #### Chosen: Automatic Railtie Integration
241
+ ```ruby
242
+ # lib/rails_uuid_pk/railtie.rb
243
+ module RailsUuidPk
244
+ class Railtie < ::Rails::Railtie
245
+ initializer "rails_uuid_pk.configure" do
246
+ ActiveSupport.on_load(:active_record) do
247
+ ActiveRecord::Base.include HasUuidv7PrimaryKey
248
+ end
249
+ end
250
+ end
251
+ end
252
+ ```
253
+
254
+ #### Benefits
255
+ - **Zero Configuration**: Works immediately after bundle install
256
+ - **Convention over Configuration**: Follows Rails patterns
257
+ - **Backwards Compatible**: Doesn't break existing applications
258
+ - **Automatic**: No manual model changes required
259
+
260
+ #### Alternative: Explicit Inclusion
261
+ ```ruby
262
+ # Would require developers to add to each model
263
+ class User < ApplicationRecord
264
+ include RailsUuidPk::HasUuidv7PrimaryKey
265
+ end
266
+ ```
267
+
268
+ ### Decision 4: Database Adapter Extension Pattern
269
+
270
+ #### Chosen: Selective Adapter Extensions
271
+ **PostgreSQL**: No extension needed - uses Rails' native UUID type support
272
+ **MySQL & SQLite**: Custom extensions for VARCHAR(36) UUID storage
273
+
274
+ ```ruby
275
+ # MySQL extension - provides VARCHAR(36) type mapping
276
+ # lib/rails_uuid_pk/mysql2_adapter_extension.rb
277
+ module RailsUuidPk
278
+ module Mysql2AdapterExtension
279
+ def native_database_types
280
+ super.merge(uuid: { name: "varchar", limit: 36 })
281
+ end
282
+
283
+ def register_uuid_types(m = type_map)
284
+ m.register_type(/varchar\(36\)/i) { RailsUuidPk::Type::Uuid.new }
285
+ end
286
+ end
287
+ end
288
+
289
+ # SQLite extension - provides VARCHAR(36) type mapping
290
+ # lib/rails_uuid_pk/sqlite3_adapter_extension.rb
291
+ module RailsUuidPk
292
+ module Sqlite3AdapterExtension
293
+ def native_database_types
294
+ super.merge(uuid: { name: "varchar", limit: 36 })
295
+ end
296
+
297
+ def register_uuid_types(m = type_map)
298
+ m.register_type(/varchar\(36\)/i) { RailsUuidPk::Type::Uuid.new }
299
+ end
300
+ end
301
+ end
302
+ ```
303
+
304
+ #### Benefits
305
+ - **Database-Specific Optimization**: Each database gets appropriate handling
306
+ - **Clean Separation**: Adapter concerns are isolated
307
+ - **Extensible**: Easy to add new database support
308
+ - **Testable**: Each adapter can be tested independently
309
+
310
+ ### Decision 5: Opt-out Mechanism for Selective UUID Generation
311
+
312
+ #### Chosen: Class-Level Opt-out with Migration Helper Integration
313
+ ```ruby
314
+ # lib/rails_uuid_pk/concern.rb
315
+ module RailsUuidPk
316
+ module HasUuidv7PrimaryKey
317
+ extend ActiveSupport::Concern
318
+
319
+ module ClassMethods
320
+ def use_integer_primary_key
321
+ @uses_integer_primary_key = true
322
+ end
323
+
324
+ def uses_uuid_primary_key?
325
+ !@uses_integer_primary_key
326
+ end
327
+ end
328
+
329
+ included do
330
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? && self.class.uses_uuid_primary_key? }
331
+ end
332
+ end
333
+ end
334
+ ```
335
+
336
+ #### Migration Helper Integration
337
+ ```ruby
338
+ # lib/rails_uuid_pk/migration_helpers.rb
339
+ def references(*args, **options)
340
+ ref_name = args.first
341
+ ref_table = options.delete(:to_table) || ref_name.to_s.pluralize
342
+
343
+ # Automatic type detection for mixed PK scenarios
344
+ if uuid_primary_key?(ref_table)
345
+ options[:type] = :uuid
346
+ end
347
+
348
+ super(*args, **options)
349
+ end
350
+ ```
351
+
352
+ #### Migration Schema Updates
353
+ When opting out of UUID primary keys, developers must also modify the generated migration:
354
+
355
+ ```ruby
356
+ # Generated migration (modify this line)
357
+ create_table :legacy_models, id: :uuid do |t| # Change :uuid to :integer
358
+ t.string :name
359
+ end
360
+
361
+ # After modification
362
+ create_table :legacy_models, id: :integer do |t| # Now uses integer primary keys
363
+ t.string :name
364
+ end
365
+ ```
366
+
367
+ #### Benefits
368
+ - **Selective Control**: Individual models can opt out while maintaining overall UUID usage
369
+ - **Migration Intelligence**: Automatic foreign key type detection for mixed scenarios
370
+ - **Zero Breaking Changes**: Existing applications continue to work unchanged
371
+ - **Clean API**: Simple declarative syntax for opting out
372
+ - **Inheritance Aware**: Subclasses must explicitly opt out (no automatic inheritance)
373
+
374
+ #### Trade-offs
375
+ - **Inheritance Behavior**: Opt-out is not inherited - each model must explicitly declare preference
376
+ - **Migration Complexity**: Foreign key type detection becomes more complex in mixed environments
377
+ - **Testing Requirements**: Mixed scenarios require additional test coverage
378
+
379
+ ## Migration Performance Implications
380
+
381
+ ### Schema Inspection Caching
382
+ ```ruby
383
+ # lib/rails_uuid_pk/migration_helpers.rb
384
+ def uuid_primary_key?(table_name)
385
+ @uuid_pk_cache ||= {}
386
+ return @uuid_pk_cache[table_name] if @uuid_pk_cache.key?(table_name)
387
+
388
+ # Database schema inspection
389
+ conn = connection
390
+ pk_column = find_primary_key_column(table_name, conn)
391
+ @uuid_pk_cache[table_name] = !!(pk_column && pk_column.sql_type =~ /uuid|varchar\(36\)/)
392
+ end
393
+ ```
394
+
395
+ **Performance Impact**:
396
+ - **Caching**: Reduces database queries during migrations
397
+ - **Memory**: Small memory footprint for cache
398
+ - **Accuracy**: Cache is per-migration instance, ensuring freshness
399
+
400
+ ### Foreign Key Type Detection
401
+ ```ruby
402
+ def references(*args, **options)
403
+ ref_name = args.first
404
+ ref_table = options.delete(:to_table) || ref_name.to_s.pluralize
405
+
406
+ # Automatic type detection
407
+ if uuid_primary_key?(ref_table)
408
+ options[:type] = :uuid
409
+ end
410
+
411
+ super(*args, **options)
412
+ end
413
+ ```
414
+
415
+ **Benefits**:
416
+ - **Automatic**: No manual foreign key type specification
417
+ - **Correct**: Ensures type consistency across relationships
418
+ - **Polymorphic**: Handles complex association scenarios
419
+
420
+ ## Database Replication and Backup Considerations
421
+
422
+ ### Replication Compatibility
423
+ - **UUID Generation**: App-level generation is replication-safe
424
+ - **No Conflicts**: UUIDs are globally unique by design
425
+ - **Ordering**: Time-based UUIDs maintain logical ordering across replicas
426
+
427
+ ### Backup and Restore
428
+ - **Data Integrity**: UUIDs remain valid across backup/restore cycles
429
+ - **References**: Foreign key relationships preserved
430
+ - **Consistency**: No auto-increment conflicts or renumbering issues
431
+
432
+ ### Multi-Region Deployments
433
+ - **Global Uniqueness**: UUIDs work across geographically distributed systems
434
+ - **Conflict Resolution**: No primary key conflicts in multi-master setups
435
+ - **Audit Trails**: Time-based UUIDs enable global event ordering
436
+
437
+ ## ORM and Query Builder Impact
438
+
439
+ ### ActiveRecord Integration
440
+ - **Seamless**: Works with all ActiveRecord features
441
+ - **Associations**: Supports belongs_to, has_many, has_one relationships
442
+ - **Validations**: Compatible with all Rails validations
443
+ - **Callbacks**: Integrates with Rails callback system
444
+
445
+ ### Query Performance
446
+ - **Index Usage**: Leverages database indexes effectively
447
+ - **Range Queries**: UUIDv7 enables efficient time-based queries
448
+ - **Join Performance**: Foreign key relationships perform well
449
+ - **Batch Operations**: Compatible with find_each, find_in_batches
450
+
451
+ ### Development Experience
452
+ - **No Code Changes**: Existing Rails code works unchanged
453
+ - **Migration Helpers**: Automatic foreign key type detection
454
+ - **Schema Dumping**: Compatible with Rails schema tools
455
+ - **Testing**: Works with all Rails testing frameworks
456
+
457
+ ## Error Handling and Resilience
458
+
459
+ ### Database Connection Failures
460
+ ```ruby
461
+ def uuid_primary_key?(table_name)
462
+ conn = connection
463
+ return false unless conn.respond_to?(:table_exists?) && conn.table_exists?(table_name)
464
+
465
+ # Graceful fallback on errors
466
+ pk_column = find_primary_key_column(table_name, conn)
467
+ !!(pk_column && pk_column.sql_type =~ /uuid|varchar\(36\)/)
468
+ rescue => e
469
+ # Log warning and return false on connection errors
470
+ Rails.logger.warn "rails-uuid-pk: Could not check table #{table_name}: #{e.message}"
471
+ false
472
+ end
473
+ ```
474
+
475
+ ### Schema Inconsistencies
476
+ - **Defensive Programming**: Handles missing tables gracefully
477
+ - **Type Safety**: Validates UUID format before database operations
478
+ - **Migration Safety**: Works during schema changes and rollbacks
479
+
480
+ ## Future Evolution Considerations
481
+
482
+ ### Extensibility Points
483
+ - **Configuration System**: Planned configuration options for customization
484
+ - **Plugin Architecture**: Extensible adapter system for new databases
485
+ - **Performance Monitoring**: Optional telemetry and metrics collection
486
+
487
+ ### Migration Path
488
+ - **Backwards Compatibility**: Current design supports gradual migration
489
+ - **Version Pinning**: Semantic versioning for breaking changes
490
+ - **Deprecation Warnings**: Clear communication of deprecated features
491
+
492
+ ### Performance Optimizations
493
+ - **Native Database Functions**: Future option for database-level generation
494
+ - **Bulk Operations**: Optimized handling for large data imports
495
+ - **Index Strategies**: Advanced indexing recommendations
496
+
497
+ ## Conclusion
498
+
499
+ The rails-uuid-pk architecture prioritizes **compatibility**, **simplicity**, and **performance** while maintaining **security** and **reliability**. Key decisions like app-level UUID generation and Railtie-based integration enable the zero-configuration experience while ensuring robust operation across diverse Rails applications and database environments.
500
+
501
+ The architecture successfully balances competing concerns:
502
+ - **Developer Experience**: Zero-configuration adoption
503
+ - **Database Compatibility**: Works across PostgreSQL, MySQL, and SQLite
504
+ - **Performance**: UUIDv7 provides better characteristics than alternatives
505
+ - **Maintainability**: Clean, modular design with clear separation of concerns
506
+ - **Future-Proofing**: Extensible architecture for ongoing evolution
507
+
508
+ This architectural foundation enables rails-uuid-pk to serve as a reliable, production-ready solution for UUID primary keys in Rails applications.
data/CHANGELOG.md CHANGED
@@ -5,6 +5,68 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v1.0.0.html).
7
7
 
8
+ ## [0.13.0] - 2026-01-20
9
+
10
+ ### Added
11
+ - **`rails_uuid_pk:add_opt_outs` Rails Generator**: New generator to automatically add `use_integer_primary_key` to models with integer primary keys in existing applications
12
+ - Scans all ActiveRecord models in `app/models/**/*.rb`
13
+ - Inspects database schema to detect integer primary keys
14
+ - Adds `use_integer_primary_key` calls to eligible models
15
+ - Command-line options: `--dry-run` (preview changes), `--verbose` (detailed output)
16
+ - Idempotent operation - safe to run multiple times
17
+ - Comprehensive error handling and user feedback
18
+ - **Trilogy Adapter Support**: Added support for the trilogy gem as an alternative to mysql2 for MySQL connections
19
+ - New `TrilogyAdapterExtension` module for trilogy adapter integration
20
+ - Automatic detection and registration of trilogy adapter for UUID type support
21
+ - Comprehensive test suite for trilogy adapter functionality
22
+ - Updated documentation to reflect trilogy compatibility alongside mysql2
23
+ - Added trilogy as development dependency for testing
24
+
25
+ ### Changed
26
+ - **Documentation Consistency**: Ensured all documentation files consistently communicate that UUIDv7 is the default behavior, while opt-out functionality exists for exceptional cases (legacy tables, third-party integrations, etc.)
27
+
28
+ ### Documentation
29
+ - **Clarified Default UUIDv7 Behavior**: Updated all documentation files to explicitly state that rails-uuid-pk assumes UUIDv7 primary keys by default for all models, with `use_integer_primary_key` being an exception for models requiring integer primary keys
30
+ - **README.md**: Emphasized "Assumes UUIDv7 primary keys by default" and clarified opt-out as "Exception: Opting Out"
31
+ - **ARCHITECTURE.md**: Updated "Zero-Configuration Philosophy" to highlight automatic UUIDv7 primary keys by default
32
+ - **DEVELOPMENT.md**: Clarified opt-out functionality as "exceptions only" for specific use cases
33
+ - **AGENTS.md**: Updated project overview to state "automatically assumes UUIDv7 primary keys by default... Models requiring integer primary keys are treated as exceptions"
34
+ - **Bulk Operations Documentation**: Added comprehensive documentation about bulk operations performance and limitations across README.md and PERFORMANCE.md, explaining that UUIDs are not automatically generated during bulk insert operations (`insert_all`, `upsert_all`, `Model.import`) and require manual UUID assignment using `SecureRandom.uuid_v7`, while highlighting the significant performance benefits when properly implemented
35
+
36
+ ### Technical Details
37
+ - Added `lib/generators/rails_uuid_pk/add_opt_outs_generator.rb` with full Rails generator implementation
38
+ - Added `lib/generators/rails_uuid_pk/templates/.keep` for directory structure maintenance
39
+ - Added `test/generators/add_opt_outs_generator_test.rb` with comprehensive test suite (9 tests, 18 assertions)
40
+ - Added `test/railtie_test.rb` with dedicated railtie functionality tests
41
+ - Updated `lib/rails_uuid_pk.rb` to load generator components
42
+ - Generator includes smart model file parsing, database schema inspection, and safe file modification
43
+ - Full cross-database compatibility (PostgreSQL, MySQL, SQLite)
44
+ - Production-ready with proper error handling and logging integration
45
+ - Added `lib/rails_uuid_pk/trilogy_adapter_extension.rb` with trilogy-specific adapter extension
46
+ - Updated `lib/rails_uuid_pk/railtie.rb` to include trilogy adapter hooks and type registration
47
+ - Updated `lib/rails_uuid_pk.rb` to load trilogy adapter extension
48
+ - Added `test/database_adapters/trilogy_test.rb` with comprehensive trilogy adapter tests
49
+ - Added trilogy database configuration to test suite
50
+ - Updated gemspec with trilogy development dependency
51
+ - Enhanced README.md and gemspec descriptions to mention trilogy support
52
+
53
+ ### Fixed
54
+ - **Migration Helpers Robustness**: Enhanced primary key detection with improved error handling and safety checks
55
+ - Added safe navigation operators (`&.`) for `sql_type` access to prevent `NoMethodError` on nil objects
56
+ - Added comprehensive error handling with rescue blocks for database connection failures
57
+ - Restricted UUID primary key detection to only consider standard Rails primary keys named 'id'
58
+ - Graceful fallback to integer foreign keys when database operations fail
59
+
60
+ ### Testing
61
+ - **Comprehensive Test Suite Expansion**: Added extensive test coverage for edge cases and error scenarios
62
+ - Added `test/railtie_test.rb` with 1 test covering railtie connection registration logic
63
+ - Expanded `test/configuration/setup_test.rb` with 5 additional tests (12 total) covering railtie UUID type registration, database configurations, migration helpers inclusion, adapter extension registration, and schema format configuration
64
+ - Enhanced `test/database_adapters/mysql_test.rb` with 1 additional test for MySQL adapter extension `configure_connection` behavior
65
+ - Enhanced `test/database_adapters/sqlite_test.rb` with 1 additional test for SQLite adapter extension transaction-aware configuration
66
+ - Enhanced `test/database_adapters/uuid_adapter_extension_test.rb` with 2 additional tests covering `type_to_dump` functionality and migration helpers edge cases
67
+ - Expanded `test/migration_helpers/references_test.rb` with 6 additional tests (11 total) covering polymorphic associations with mixed primary key types, nil options handling, empty polymorphic options, column lookup error handling, method chaining safety, and rescue block behavior
68
+ - Total test expansion: 16 new tests across 6 test files, improving robustness and edge case coverage
69
+
8
70
  ## [0.12.0] - 2026-01-17
9
71
 
10
72
  ### Changed