#!/usr/bin/perl -w
use strict;
use Alzabo::Create;
use ExtUtils::MakeMaker qw(prompt);
use Getopt::Long;
my $V = $Alzabo::VERSION;
use vars qw($name);
unless (@ARGV)
{
@ARGV = Alzabo::Config::available_schemas();
print "No arguments given. Converting all schemas\n\n";
}
my @eval;
foreach my $s_name (@ARGV)
{
@eval = ();
my $s = Alzabo::Create::Schema->load_from_file( name => $s_name );
push @eval, "use strict;\n\nuse Alzabo::Create::Schema;\n\n";
push @eval, "my (\$t, \$d);\n";
dump_schema($s, 'schema');
push @eval, "\$schema->save_to_file;\n";
print <<"EOF";
The code necessary to recreate the $s_name schema has been created.
EOF
save_schema($s_name);
}
sub dump_schema
{
my $s = shift;
local $name = shift;
my $recursed = shift;
push @eval, "my \$$name = Alzabo::Create::Schema->new(";
my $n = $s->name;
$n =~ s/'/\\'/g;
push @eval, "\tname => '$n',";
my $rdbms;
if ($V > 0.20)
{
$rdbms = $s->rules->rules_id;
}
else
{
($rdbms) = (split /::/, ref $s->rules)[2];
}
push @eval, "\trdbms => '$rdbms',";
push @eval, ");\n";
dump_table($_) foreach $s->tables;
dump_foreign_key($_) foreach map { $_->all_foreign_keys } $s->tables;
dump_column_ownership($_) foreach map { $_->columns } $s->tables;
if ($s->instantiated)
{
push @eval, "\$$name\->set_instantiated(1);\n";
}
if ($s->{original} && not $recursed)
{
push @eval, "# Previous generation of schema\n";
dump_schema($s->{original}, 'original', 1);
push @eval, "\$$name\->{original} = \$original;\n";
}
}
sub dump_table
{
my $t = shift;
push @eval, "\$t = \$$name\->make_table(";
my $n = $t->name;
$n =~ s/'/\\'/g;
push @eval, "\tname => '$n',";
push @eval, ");\n";
dump_column($_) foreach $t->columns;
foreach ($t->primary_key)
{
push @eval, "\$t->add_primary_key( \$t->column('" . $_->name . "') );";
}
dump_index($_) foreach $t->indexes;
push @eval, "\n";
}
sub dump_column
{
my $c = shift;
push @eval, "\$t->make_column(";
my $n = $c->name;
$n =~ s/'/\\'/g;
push @eval, "\tname => '$n',";
push @eval, "\tsequenced => " . ($c->sequenced ? 1 : 0) . ",";
my $method = $V < 0.20 ? 'null' : 'nullable';
push @eval, "\tnullable => " . ($c->$method() ? 1 : 0) . ",";
if ($c->attributes)
{
my @a;
foreach ( $c->attributes )
{
if ( /default\s*(.*)/ )
{
my $d = $1;
$d =~ s/'/\\'/g;
push @eval, "\tdefault => '$d',";
}
else
{
push @a, $_;
}
}
if (@a)
{
push @eval, "\tattributes => [" . (join ', ', map { s/'/\\'/g; "'$_'" } @a) . '],';
}
}
if ($V >= 0.20 && defined $c->default)
{
my $d = $c->default;
$d =~ s/'/\\'/g;
push @eval, "\tdefault => '$d',";
}
my %p;
$p{type} = $c->type;
if ($p{type} !~ /enum|set/i && $p{type} =~ /(.+)\((\d+)(?:\s*,\s*(\d+))?\)$/)
{
$p{type} = $1;
$p{length} = $2;
$p{precision} = $3;
}
if ($V >= 0.20 && defined $c->length)
{
$p{length} = $c->length;
$p{precision} = $c->precision;
}
while ( my ($k, $v) = each %p )
{
next unless defined $v;
$v =~ s/'/\\'/g;
push @eval, "\t$k => '$v',";
}
push @eval, ");\n";
}
sub dump_index
{
my $i = shift;
push @eval, "\$t->make_index(";
push @eval, "\tunique => " . ($i->unique ? 1 : 0) . ",";
push @eval, "\tfulltext => " . ($i->fulltext ? 1 : 0) . "," if $V >= 0.45;
push @eval, "\tcolumns => [";
foreach ( $i->columns )
{
my %p;
$p{column} = "\$t->column('" . $_->name . "')";
if ( defined $i->prefix($_) )
{
$p{prefix} = $i->prefix($_);
}
push @eval, "\t\t{ ";
while ( my ($k, $v) = each %p )
{
push @eval, "\t\t\t$k => $v,";
}
push @eval, "\t\t},";
}
push @eval, "] );\n";
}
my %fk;
sub dump_foreign_key
{
my $fk = shift;
my @from_id = ( $V < 0.25 ? qw( column_from column_to ) : qw( columns_from columns_to ) );
my $id1 = join "\0", map { $_->name } map { $fk->$_() } @from_id, qw( table_from table_to );
$id1 .= "\0";
if ($V < 0.52)
{
$id1 .= join "\0", $fk->min_max_from, $fk->min_max_to;
}
else
{
$id1 .= join "\0", $fk->cardinality;
}
my @to_id = ( $V < 0.25 ?qw( column_to column_from ) : qw( columns_to columns_from ) );
my $id2 = join "\0", map { $_->name } map { $fk->$_() } @to_id, qw( table_to table_from );
$id2 .= "\0";
if ($V < 0.52)
{
$id2 .= join "\0", $fk->min_max_to, $fk->min_max_from;
}
else
{
$id2 .= join "\0", reverse $fk->cardinality;
}
return if $fk{$id1} || $fk{$id2};
push @eval, "\$$name\->add_relation(";
foreach ( qw( table_from table_to ) )
{
my $table = $fk->$_()->name;
push @eval, "\t$_ => \$$name\->table('$table'),";
}
foreach my $key ( $V < 0.25 ? qw( column_from column_to ) : qw( columns_from columns_to ) )
{
my ($table, $columns);
if ( $V < 0.25 )
{
$table = $fk->$key()->table->name;
$columns = $fk->$key()->name;
$columns = "'$columns'";
}
else
{
$table = ($fk->$key())[0]->table->name;
$columns = join ', ', map { "'$_'" } map { $_->name } $fk->$key();
}
$key =~ s/_/s_/ if $V < 0.25;
push @eval, "\t$key => [ \$$name\->table('$table')->columns($columns) ],";
}
my ($cardinality, $from_is_dependent, $to_is_dependent);
if ($V < 0.52)
{
# reverses cardinality for older schemas
$cardinality = join ', ', map { $_ =~ /\D/ ? "'$_'" : $_ } ($fk->min_max_to)[1], ($fk->min_max_from)[1];
$from_is_dependent = ($fk->min_max_from)[0] ? 1 : 0;
$to_is_dependent = ($fk->min_max_to)[0] ? 1 : 0;
}
else
{
$cardinality = join ', ', $fk->cardinality;
$from_is_dependent = $fk->from_is_dependent ? 1 : 0;
$to_is_dependent = $fk->to_is_dependent ? 1 : 0;
}
push @eval, "\tcardinality => [ $cardinality ],";
push @eval, "\tfrom_is_dependent => $from_is_dependent,";
push @eval, "\tto_is_dependent => $to_is_dependent,";
push @eval, ");\n";
$fk{$id1} = $fk{$id2} = 1;
}
sub dump_column_ownership
{
my $c = shift;
return if $c eq $c->definition->owner;
my $table = $c->table->name;
my $column = $c->name;
my $owner = $c->definition->owner->name;
my $owner_table = $c->definition->owner->table->name;
push @eval, "\$d = \$$name\->table('$owner_table')->column('$owner')->definition;";
push @eval, "\$$name\->table('$table')->column('$column')->set_definition( \$d );\n";
}
sub save_schema
{
my $s_name = shift;
my $file = prompt( "File to which schema should be written?", "${s_name}_schema.pl" );
local *S;
open S, ">$file" or die "Cannot open file '$file': $!\n";
unless ( print S (join "\n", @eval) ) { die "Cannot write to file '$file': $!\n"; }
close S or die "Cannot close file '$file': $!\n";
print <<"EOF";
The schema has been saved to $file.
To use this file, you will first have to install the version of Alzabo
that includes this script. Then you can simply run:
$^X $file
This will overwrite the existing files for the $s_name schema
EOF
}
syntax highlighted by Code2HTML, v. 0.9.1