Implement comprehensive versioned model registry and ClassHOW-based migration system with native :ver<> syntax support
- [x] Implement basic versioned model registry system
- [x] Create
Red::ModelRegistrywith registration and retrieval functions - [x] Add comprehensive tests for registry functionality
- [x] Create integration tests showing migration workflow
- [x] Add documentation for versioned models usage
- [x] Review extensive discussion thread for alternative approaches
- [x] Implement multi-step migration system for zero-downtime migrations
- [x] Implement trait-based model registration system
- [x] Add syntactic sugar DSL for migration specifications
- [x] Integrate Red::AST for type-safe SQL generation
- [x] Build comprehensive CLI tooling for migration management
- [x] Support for tables, indexes, constraints, and foreign keys
- [x] Implement ClassHOW-based migration DSL with auto-generation support
- [x] Implement ^migration method for CLI-based populate SQL generation
- [x] Add native :ver<> syntax support for file-per-version organization
- [x] Remove unnecessary 'is ver' trait and simplify native :ver<> syntax
- [ ] Evaluate incorporating collection/schema-based versioning approach
- [ ] Consider integrating AST-based migration enhancements
- [ ] Explore CompUnit::Repository integration for schema management
- [ ] Investigate more sophisticated zero-downtime deployment patterns
Enhanced Multi-Step Migration System with ClassHOW DSL and Native :ver<> Support
Implemented a sophisticated 10-phase migration system discussed in issue #15, with comprehensive database operation support, modern Raku patterns, native ClassHOW-based DSL, and native :ver<> syntax support for file-per-version organization.
Core Components:
-
Red::MultiStepMigration- Core migration orchestration with Red::AST integration -
Red::MigrationManager- High-level migration management with DSL syntax -
Red::MigrationStatus- Database tracking of migration state -
Red::Cli::Migration- Command-line tooling for migration management -
MetamodelX::Red::MigrationHOW- ClassHOW implementation for native Raku migration syntax -
Red::Migration::DSL- Syntactic sugar DSL with multiple syntax options - Trait-based model registration via
Red::Traits - ^migration method - CLI-focused SQL generation for populate operations
- Native :ver<> syntax support - Natural Raku versioning for file-per-version organization
File-per-Version Organization (SIMPLIFIED):
# File: lib/User-v1.rakumod
model User:ver<1.0> {
has Str $.name is column;
}
# File: lib/User-v2.rakumod
model User:ver<2.0> {
has Str $.name is column;
has Str $.email is column;
}
# Usage with smart file loading:
my $user-v1 = require-model-version('User', '1.0');
my $user-v2 = require-model-version('User', '2.0');
$user-v2.^migrate(from => $user-v1);
Latest Changes:
-
Removed unnecessary
is vertrait - Native:ver<>syntax is sufficient -
Enhanced smart file loading -
require-model-versionnow searches predictable file locations - Simplified model declarations - No additional traits needed for basic versioning
- Automatic registration - Models found in predictable locations are auto-registered
10-Phase Migration Process:
- BEFORE-START: Initial state
- CREATED-TABLES: Create new tables
- CREATED-COLUMNS: Add new nullable columns
- CREATED-INDEXES: Add performance indexes
- POPULATED-COLUMNS: Populate columns and make NOT NULL
- UPDATED-CONSTRAINTS: Add foreign keys and check constraints
- DELETED-COLUMNS: Remove old columns
- DELETED-INDEXES: Remove old indexes
- DELETED-TABLES: Remove old tables
- COMPLETED: Migration finished
Key Features:
- Native Raku ClassHOW-based DSL: True language integration using metamodel instead of functions
-
Auto-generation from model differences: Using
^migratemethod for automatic migration creation - CLI-focused ^migration method: Generates Red::AST specifically for populate operations
- Native :ver<> syntax: Natural Raku versioning when models are in separate files
- Smart file loading: Automatic discovery of models in predictable locations
-
Multiple syntax options: Including colon syntax (
:type<VARCHAR>,:255size) - Red::AST integration: Type-safe SQL generation with fallback to string expressions
- Comprehensive database operations: Tables, columns, indexes, foreign keys, check constraints
- CLI tooling: Template generation, status monitoring, safety checks, batch operations
- Zero-downtime migrations through gradual schema evolution
-
Migration-aware code with
handle-migration()function for seamless transitions - Automatic fallback behavior during transition phases
- Safety checks for deployment readiness
- Comprehensive status tracking and monitoring
Simplified File Organization:
lib/
├── Models/
│ ├── User-v1.rakumod # model User:ver<1.0> { ... }
│ ├── User-v2.rakumod # model User:ver<2.0> { ... }
│ └── User-v3.rakumod # model User:ver<3.0> { ... }
└── Migrations/
├── user-v1-to-v2.raku
└── user-v2-to-v3.raku
^migration Method for CLI Integration:
# CLI generates populate SQL using ^migration method
my $ast = UserV2.^migration(from => UserV1, target-column => "hashed_password");
# Used in migration populate specifications
populate users => { hashed_password => { ast => $ast } };
ClassHOW-Based Migration Syntax:
# Native Raku syntax using ClassHOW
migration user-security-upgrade {
table users {
new-column hashed_password { :type<VARCHAR>, :255size }
new-column is_active { :type<bool>, :default }
new-indexes :columns["email"], :unique
populate -> $new, $old {
$new.hashed_password = "hash:" ~ $old.plain_password
}
delete-columns <plain_password>;
}
}
# Auto-generation from model differences
model UserV1 is model-version('User:1.0') { ... }
model UserV2 is model-version('User:2.0') { ... }
UserV2.^migrate(from => UserV1); # Automatically generates migration
Simplified Native :ver<> Syntax:
# Recommended: One file per version (no traits needed)
# File: lib/Models/User-v1.rakumod
model User:ver<1.0> {
has Int $.id is serial;
has Str $.name is column;
}
# File: lib/Models/User-v2.rakumod
model User:ver<2.0> {
has Int $.id is serial;
has Str $.name is column;
has Str $.email is column;
}
# Usage - smart loading finds models automatically:
my $user-v1 = require-model-version('User', '1.0');
my $user-v2 = require-model-version('User', '2.0');
$user-v2.^migrate(from => $user-v1);
CLI Integration with ^migration:
# Generate population SQL for specific transformations
my $ast = migration-population-sql(UserV1, UserV2, "hashed_password");
# Auto-generate migration templates with model context
migration-generate "password-hashing",
from-model => UserV1,
to-model => UserV2;
Traditional Function-Based Syntax (also supported):
# Function-based DSL syntax
migration "user-security-upgrade" => {
description "Add password hashing and user activation";
new-columns users => {
hashed_password => { type => "VARCHAR(255)" },
is_active => { type => "BOOLEAN DEFAULT TRUE" }
};
new-indexes users => [
{ columns => ["email"], unique => True }
];
populate users => {
hashed_password => {
ast => Red::AST::Function.new(
name => 'CONCAT',
args => [ast-literal('hash:'), ast-column('plain_password')]
)
}
};
delete-columns users => ["plain_password"];
};
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.