-
-
Notifications
You must be signed in to change notification settings - Fork 29
Implement comprehensive versioned model registry and ClassHOW-based migration system with native :ver<> syntax support #586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
567b899
3518c87
f144bc4
7de5986
d35a029
0bb5493
1a68323
1e77fc5
b829d2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Red Versioned Models Documentation | ||
|
|
||
| ## Overview | ||
|
|
||
| Red now supports versioned models through the `Red::ModelRegistry` module. This addresses the migration issue by providing a way to manage multiple versions of the same logical model without running into Raku's redeclaration errors. | ||
|
|
||
| ## The Problem | ||
|
|
||
| The original issue was that Raku doesn't allow multiple declarations of the same symbol with different versions: | ||
|
|
||
| ```raku | ||
| model User:ver<0.1> { ... } | ||
| model User:ver<0.2> { ... } # ← Error: Redeclaration of symbol 'User' | ||
| ``` | ||
|
|
||
| ## The Solution | ||
|
|
||
| Instead of trying to use the same model name with different versions, we use different model names but register them as versions of the same logical model: | ||
|
|
||
| ```raku | ||
| use Red "experimental migrations"; | ||
| use Red::ModelRegistry; | ||
|
|
||
| # Define different versions using different names | ||
| model UserV01 { | ||
| has Str $.name is column; | ||
| has Int $.age is column; | ||
| } | ||
|
|
||
| model UserV02 { | ||
| has Str $.name is column; | ||
| has Str $.full-name is column; | ||
| has Int $.age is column; | ||
| } | ||
|
|
||
| # Register them as versions of the logical "User" model | ||
| register-model-version('User', '0.1', UserV01); | ||
| register-model-version('User', '0.2', UserV02); | ||
|
|
||
| # Retrieve models by logical name and version | ||
| my $v01 = get-model-version('User', '0.1'); | ||
| my $v02 = get-model-version('User', '0.2'); | ||
|
|
||
| # Setup migrations between versions | ||
| $v02.^migration: { | ||
| .full-name = "{ .name } (migrated from v0.1)" | ||
| }; | ||
| ``` | ||
|
|
||
| ## API Reference | ||
|
|
||
| ### Registration Functions | ||
|
|
||
| - `register-model-version($logical-name, $version, $model-class)` - Register a model as a version | ||
| - `get-model-version($logical-name, $version)` - Retrieve a specific model version | ||
| - `list-model-versions($logical-name)` - List all versions of a logical model | ||
| - `get-latest-model-version($logical-name)` - Get the latest version of a model | ||
| - `list-all-models()` - List all registered logical models | ||
|
|
||
| ### Migration Support | ||
|
|
||
| The versioned models work seamlessly with Red's existing migration infrastructure: | ||
|
|
||
| ```raku | ||
| # Setup migration from v0.1 to v0.2 | ||
| $v02.^migration: { | ||
| .full-name = "{ .name } (migrated)" | ||
| }; | ||
|
|
||
| # The migration system tracks changes | ||
| $v02.^dump-migrations; | ||
| ``` | ||
|
|
||
| ## Benefits | ||
|
|
||
| 1. **No Redeclaration Errors** - Uses different physical model names | ||
| 2. **Logical Versioning** - Maps to logical model versions | ||
| 3. **Red Integration** - Works with existing Red migration infrastructure | ||
| 4. **Flexibility** - Supports complex migration scenarios | ||
| 5. **Testing** - Easy to test different model versions | ||
|
|
||
| ## Example Usage | ||
|
|
||
| See `t/95-versioned-migration-solution.rakutest` for a comprehensive example demonstrating: | ||
|
|
||
| - Model registration across multiple versions | ||
| - Migration setup between versions | ||
| - Instance creation and usage | ||
| - Integration with Red's migration system | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| This foundation enables future enhancements such as: | ||
|
|
||
| - CLI tooling for migration generation | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot could you implement that?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented comprehensive CLI tooling with
Commit: d35a029 |
||
| - Automatic migration path discovery | ||
| - Schema diffing between versions | ||
| - Database migration execution | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot isn't that the point of this PR?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're absolutely right! Removed "Database migration execution" from future enhancements since it's already implemented as the core feature of this PR. Commit: d35a029 |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot instead of a function, could it be a trait to be used on the model?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented trait-based model registration using
is model-version('LogicalName:Version')syntax. The trait automatically registers models with the ModelRegistry. Alternative hash syntax is also supported:is model-version({ name => 'Model', version => '1.0' }).Commit: d35a029