Skip to content

Commit

Permalink
Start playing with red-mogrations
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernando Corrêa de Oliveira committed Mar 11, 2024
1 parent 78d7066 commit 7983cb6
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 55 deletions.
148 changes: 93 additions & 55 deletions bin/red
Original file line number Diff line number Diff line change
@@ -1,88 +1,126 @@
#!env perl6
#!env raku
use Red::Cli;
use Red::Do;
use Red::Database;
use Red::Configuration;

my %*SUB-MAIN-OPTS =
:named-anywhere,
;

my $*RED-DEBUG = False;

proto MAIN(Str :$I, Bool :$debug, |) {
proto MAIN(Str :$I, Bool :$debug, IO() :$config = $*CWD.add("migration.rakuconfig"), |) {
dyn-lib .split: "," with $I;
my $*config = single-config-run :file($config);
$*RED-DEBUG = $debug;
{*}
}

#| List tables in database
multi MAIN(
"list-tables",
Str :$driver!,
*%pars
"migration",
"update"
) {
my $*RED-DB = database($driver, |%pars);
.say for list-tables :$driver, |%pars
note "dump DB into { $*config.new-dump-version-path.relative }";
note "calculate the differences between the DB and the models and create high level changes file on { $*config.migration-red-path.relative }";
note "apply changes file on { $*config.migration-red-path.relative } on local DB";
note "copy changed models files to new dir inside { $*config.model-storage-path.relative }"
}

#| Generate stub code to access models from database schema
multi MAIN(
"print-stub",
Str :$schema-class,
Str :$driver!,
*%pars
"migration",
"revert-update"
) {
my $*RED-DB = database($driver, |%pars);
say gen-stub-code :$schema-class, :$driver, |%pars
note "restore dump from { $*config.dump-version-path.relative }";
note "delete dump from { $*config.dump-version-path.relative }";
note "delete high level changes files from { $*config.migration-red-path.relative }";
note "delete models from { $*config.model-storage-path.relative }"
}


#| Generates migration plan to upgrade database schema
multi MAIN(
"migration-plan",
Str :$model!,
Str :$require = $model,
Str :$driver!,
*%pars
"migration",
"prepare"
) {
my $*RED-DB = database($driver, |%pars);
migration-plan :$model, :$require, :$driver, |%pars
note "convert high lavel DB change from { $*config.migration-red-path.relative } into SQL on { $*config.drivers.map({ $*config.migration-sql-path($_).relative }).join: " and " }";
note "delete all dumps on { $*config.dump-storage-path.relative }";
}

#| Generates models' code from database schema
multi MAIN(
"generate-code",
Str :$path! where { not .defined or .IO.d or $_ eq "-" or fail "Path $_ does not exist." },
Str :$from-sql where { not .defined or .IO.f or $_ eq "-" or fail "SQL $_ do not exist." },
Str :$schema-class,
Bool :$print-stub = False,
Bool :$no-relationships = False,
#Bool :$stub-only,
Str :$driver!,
*%pars
"migration",
"apply",
Str :$driver
) {
my $*RED-DB = database($driver, |%pars);
generate-code
:$path,
:$from-sql,
:$schema-class,
:$print-stub,
:$no-relationships,
:$driver,
|%pars
die "Driver does not exist on configuration (options: { $*config.drivers.join: ", " })" unless $driver ~~ $*config.drivers.any;
note "apply SQL from { $*config.migration-sql-path($driver).relative }";
}

#| Prepare database
multi MAIN(
"prepare-database",
Bool :$populate,
Str :$models!,
Str :$driver!,
*%pars
) {
$GLOBAL::RED-DB = database $driver, |%pars;
prepare-database :$populate, :$models, :$driver, |%pars
}
# #| List tables in database
# multi MAIN(
# "list-tables",
# Str :$driver!,
# *%pars
# ) {
# my $*RED-DB = database($driver, |%pars);
# .say for list-tables :$driver, |%pars
# }
#
# #| Generate stub code to access models from database schema
# multi MAIN(
# "print-stub",
# Str :$schema-class,
# Str :$driver!,
# *%pars
# ) {
# my $*RED-DB = database($driver, |%pars);
# say gen-stub-code :$schema-class, :$driver, |%pars
# }
#
#
# #| Generates migration plan to upgrade database schema
# multi MAIN(
# "migration-plan",
# Str :$model!,
# Str :$require = $model,
# Str :$driver!,
# *%pars
# ) {
# my $*RED-DB = database($driver, |%pars);
# migration-plan :$model, :$require, :$driver, |%pars
# }
#
# #| Generates models' code from database schema
# multi MAIN(
# "generate-code",
# Str :$path! where { not .defined or .IO.d or $_ eq "-" or fail "Path $_ does not exist." },
# Str :$from-sql where { not .defined or .IO.f or $_ eq "-" or fail "SQL $_ do not exist." },
# Str :$schema-class,
# Bool :$print-stub = False,
# Bool :$no-relationships = False,
# #Bool :$stub-only,
# Str :$driver!,
# *%pars
# ) {
# my $*RED-DB = database($driver, |%pars);
# generate-code
# :$path,
# :$from-sql,
# :$schema-class,
# :$print-stub,
# :$no-relationships,
# :$driver,
# |%pars
# }
#
# #| Prepare database
# multi MAIN(
# "prepare-database",
# Bool :$populate,
# Str :$models!,
# Str :$driver!,
# *%pars
# ) {
# $GLOBAL::RED-DB = database $driver, |%pars;
# prepare-database :$populate, :$models, :$driver, |%pars
# }

sub dyn-lib(@libs) {
qq[use lib "{ $_ }"].EVAL for @libs
Expand Down
108 changes: 108 additions & 0 deletions lib/Red/Configuration.rakumod
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
class Red::Configuration {
has UInt $.current-version = self!find-current-version;
has UInt %.model-current-version is default(0) = self!find-all-models-current-version;
has UInt $.dump-current-version = self!find-dump-current-version;
has IO() $.base-path = $*CWD; # where *.add("META6.json") ~~ :f = $*CWD;
has IO() $.migration-base-path = $!base-path.add: "migrations";
has IO() $.dump-path = $!base-path.add: ".db-dumps";
has IO() $.model-storage-path = $!migration-base-path.add: "models";
has IO() $.version-storage-path = $!migration-base-path.add: "versions";
has IO() $.dump-storage-path = $!migration-base-path.add: "dumps";
has Str() $.red-subdir = "red";
has Str() $.sql-subdir = "sql";
has Str() @.drivers = <SQLite Pg>;

has %!versions-cache = self!compute-version-cache;
has %!models-cache = self!compute-models-cache;


method !compute-version-cache {
# TODO: Implement this
note "prepare a hash with all migration versions";
%()
}
method !compute-models-cache {
# TODO: Implememt this
note "prepare a hash with all model versions";
%()
}
method !find-current-version {
# TODO: Impment this
note "find current version";
0
}
method !find-all-models-current-version {
# TODO: Impment this
note "find all models current versions";
%()
}
method !find-dump-current-version {
# TODO: Impment this
note "find dump current version";
0
}
method !random-string {
# FIXME: make it right
[|("a".."z"), |("A".."Z"), |(0..9)].roll(30).join
}

multi method version-path($version) {
$!version-storage-path.add: $version
}

multi method version-path {
$.version-path: $!current-version
}

method new-model-version(Str $model-name) {
++%!model-current-version{$model-name}
}

multi method model-path(Str() $model-name) {
$.model-path: $model-name, %!model-current-version{$model-name}
}

multi method model-path(Str() $model-name, UInt $version) {
$.model-version-path: $model-name, $version
}

multi method model-version-path(Str() $model-name, UInt() $version) {
$!model-storage-path.add: %!models-cache{$model-name}{$version}
}

multi method model-version-path(Str() $model-name-version) {
if $model-name-version ~~ /^$<name>=[<[\w:]>*\w] ":" ["ver<" ~ ">" $<ver>=[\d+]|\w+ "<" ~ ">" \w+]* % ":"/ {
$.model-version-path: $<name>, $<ver> // 0
}
}

multi method dump-version-path(UInt() $version) {
$!dump-storage-path.add: $version
}

multi method dump-version-path {
$.dump-version-path: $!dump-current-version
}

multi method new-dump-version-path {
$.dump-version-path: ++$!dump-current-version
}

multi method migration-red-path {
$.version-path.add($!red-subdir)
}

multi method migration-red-path(UInt $version) {
$.version-path($version).add($!red-subdir)
}

multi method migration-sql-path(Str $driver where @!drivers.one) {
$.version-path.add($!sql-subdir).add: $driver
}

multi method migration-sql-path(Str $driver where @!drivers.one, UInt $version) {
$.version-path($version).add($!sql-subdir).add: $driver
}
}

use Configuration Red::Configuration;

0 comments on commit 7983cb6

Please sign in to comment.