Alzabo
view release on metacpan or search on metacpan
lib/Alzabo/Create/Schema.pm view on Meta::CPAN
$self->{sql} = Alzabo::SQLMaker->load( rdbms => $p{rdbms} );
params_exception "Alzabo::Create::Schema->new requires a name parameter\n"
unless exists $p{name};
$self->set_name($p{name});
$self->{tables} = Tie::IxHash->new;
$self->_save_to_cache unless $p{no_cache};
return $self;
}
sub load_from_file
{
return shift->_load_from_file(@_);
}
sub reverse_engineer
{
my $proto = shift;
my $class = ref $proto || $proto;
my %p = @_;
my $self = $class->new( name => $p{name},
rdbms => $p{rdbms},
no_cache => 1,
);
delete $p{rdbms};
$self->{driver}->connect(%p);
$self->{rules}->reverse_engineer($self);
$self->set_instantiated(1);
my $driver = delete $self->{driver};
$self->{original} = Storable::dclone($self);
$self->{driver} = $driver;
delete $self->{original}{original};
return $self;
}
sub set_name
{
my $self = shift;
validate_pos( @_, { type => SCALAR } );
my $name = shift;
return if defined $self->{name} && $name eq $self->{name};
my $old_name = $self->{name};
$self->{name} = $name;
eval { $self->rules->validate_schema_name($self); };
if ($@)
{
$self->{name} = $old_name;
rethrow_exception($@);
}
# Gotta clean up old files or we have a mess!
$self->delete( name => $old_name ) if $old_name;
$self->set_instantiated(0);
undef $self->{original};
}
sub set_instantiated
{
my $self = shift;
validate_pos( @_, 1 );
$self->{instantiated} = shift;
}
sub make_table
{
my $self = shift;
my %p = @_;
my %p2;
foreach ( qw( before after ) )
{
$p2{$_} = delete $p{$_} if exists $p{$_};
}
$self->add_table( table => Alzabo::Create::Table->new( schema => $self,
%p ),
%p2 );
return $self->table( $p{name} );
}
sub add_table
{
my $self = shift;
validate( @_, { table => { isa => 'Alzabo::Create::Table' },
before => { optional => 1 },
after => { optional => 1 } } );
my %p = @_;
my $table = $p{table};
params_exception "Table " . $table->name . " already exists in schema"
if $self->{tables}->EXISTS( $table->name );
$self->{tables}->STORE( $table->name, $table );
foreach ( qw( before after ) )
{
if ( exists $p{$_} )
{
$self->move_table( $_ => $p{$_},
table => $table );
last;
}
}
}
lib/Alzabo/Create/Schema.pm view on Meta::CPAN
$p{columns_to} :
[ $p{columns_to} ] ) :
undef );
my $f_table = $p{table_from} || $p{columns_from}->[0]->table;
my $t_table = $p{table_to} || $p{columns_to}->[0]->table;
if ( $p{columns_from} && $p{columns_to} )
{
params_exception
"Cannot create a relationship with differing numbers of columns " .
"on either side of the relation"
unless @{ $p{columns_from} } == @{ $p{columns_to} };
}
foreach ( [ columns_from => $f_table ], [ columns_to => $t_table ] )
{
my ($key, $table) = @$_;
if ( defined $p{$key} )
{
params_exception
"All the columns in a given side of the relationship ".
"must be from the same table"
if grep { $_->table ne $table } @{ $p{$key} };
}
}
# Determined later. This is the column that the relationship is
# to. As in table A/column B maps _to_ table X/column Y
my ($col_from, $col_to);
# cardinality from -> to
my $cardinality =
( $p{cardinality}->[0] eq '1' && $p{cardinality}->[1] eq '1' ?
'1_to_1' :
$p{cardinality}->[0] eq '1' && $p{cardinality}->[1] eq 'n' ?
'1_to_n' :
'n_to_1'
);
my $method = "_create_${cardinality}_relationship";
($col_from, $col_to) = $self->$method( %p,
table_from => $f_table,
table_to => $t_table,
);
eval
{
$f_table->make_foreign_key( columns_from => $col_from,
columns_to => $col_to,
cardinality => $p{cardinality},
from_is_dependent => $p{from_is_dependent},
to_is_dependent => $p{to_is_dependent},
comment => $p{comment},
);
};
if ($@)
{
$tracker->backout;
rethrow_exception($@);
}
my @fk;
eval
{
foreach my $c ( @$col_from )
{
push @fk, $f_table->foreign_keys( table => $t_table,
column => $c );
}
};
if ($@)
{
$tracker->backout;
rethrow_exception($@);
}
$tracker->add( sub { $f_table->delete_foreign_key($_) foreach @fk } );
# cardinality to -> to
my $inverse_cardinality =
( $p{cardinality}->[1] eq '1' && $p{cardinality}->[0] eq '1' ?
'1_to_1' :
$p{cardinality}->[1] eq '1' && $p{cardinality}->[0] eq 'n' ?
'1_to_n' :
'n_to_1'
);
my $inverse_method = "_create_${inverse_cardinality}_relationship";
($col_from, $col_to) = $self->$method( table_from => $t_table,
table_to => $f_table,
columns_from => $col_to,
columns_to => $col_from,
cardinality => [ @{ $p{cardinality} }[1,0] ],
from_is_dependent => $p{to_is_dependent},
to_is_dependent => $p{from_is_dependent},
);
if ($p{from_is_dependent})
{
$_->nullable(0) foreach @{ $p{columns_from} };
}
if ($p{to_is_dependent})
{
$_->nullable(0) foreach @{ $p{columns_to} };
}
eval
{
$t_table->make_foreign_key( columns_from => $col_from,
columns_to => $col_to,
cardinality => [ @{ $p{cardinality} }[1,0] ],
from_is_dependent => $p{to_is_dependent},
to_is_dependent => $p{from_is_dependent},
comment => $p{comment},
);
};
if ($@)
{
$tracker->backout;
rethrow_exception($@);
}
}
# old name - deprecated
*add_relation = \&add_relationship;
sub _check_add_relationship_args
{
my $self = shift;
my %p = @_;
foreach my $t ( $p{table_from}, $p{table_to} )
{
next unless defined $t;
params_exception "Table " . $t->name . " doesn't exist in schema"
unless $self->{tables}->EXISTS( $t->name );
}
params_exception "Incorrect number of cardinality elements"
unless scalar @{ $p{cardinality} } == 2;
foreach my $c ( @{ $p{cardinality} } )
{
params_exception "Invalid cardinality: $c"
unless $c =~ /^[01n]$/i;
}
# No such thing as 1..0 or n..0
params_exception "Invalid cardinality: $p{cardinality}->[0]..$p{cardinality}->[1]"
if $p{cardinality}->[1] eq '0';
}
sub _create_1_to_1_relationship
{
my $self = shift;
my %p = @_;
return @p{ 'columns_from', 'columns_to' }
if $p{columns_from} && $p{columns_to};
# Add these columns to the table which _must_ participate in the
# relationship, if there is one. This reduces NULL values.
# Otherwise, just add to the first table specified in the
# relation.
my @order;
# If the from table is dependent or neither one is or both are ...
if ( $p{from_is_dependent} ||
$p{from_is_dependent} == $p{to_is_dependent} )
{
@order = ( 'from', 'to' );
}
# The to table is dependent
else
{
@order = ( 'to', 'from' );
}
# Determine which table we are linking from. This gets a new
# column or has its column adjusted) ...
my $f_table = $p{"table_$order[0]"};
lib/Alzabo/Create/Schema.pm view on Meta::CPAN
$t2_col = \@c;
}
# First we create the table.
my $linking;
my $name;
if ( exists $p{name} )
{
$name = $p{name};
}
elsif ( lc $t1->name eq $t1->name )
{
$name = join '_', $t1->name, $t2->name;
}
else
{
$name = join '', $t1->name, $t2->name;
}
$linking = $self->make_table( name => $name );
$tracker->add( sub { $self->delete_table($linking) } );
eval
{
foreach my $c ( @$t1_col, @$t2_col )
{
$linking->make_column( name => $c->name,
definition => $c->definition,
primary_key => 1,
);
}
$self->add_relationship
( table_from => $t1,
table_to => $linking,
columns_from => $t1_col,
columns_to => [ $linking->columns( map { $_->name } @$t1_col ) ],
cardinality => [ '1', 'n' ],
from_is_dependent => $p{from_is_dependent},
to_is_dependent => 1,
comment => $p{comment},
);
$self->add_relationship
( table_from => $t2,
table_to => $linking,
columns_from => $t2_col,
columns_to => [ $linking->columns( map { $_->name } @$t2_col ) ],
cardinality => [ '1', 'n' ],
from_is_dependent => $p{to_is_dependent},
to_is_dependent => 1,
comment => $p{comment},
);
};
if ($@)
{
$tracker->backout;
rethrow_exception($@);
}
}
sub instantiated
{
my $self = shift;
return $self->{instantiated};
}
sub create
{
my $self = shift;
my %p = @_;
my @sql = $self->make_sql;
local $self->{db_schema_name} = delete $p{schema_name}
if exists $p{schema_name};
$self->{driver}->create_database(%p)
unless $self->_has_been_instantiated(%p);
$self->{driver}->connect(%p);
foreach my $statement (@sql)
{
$self->{driver}->do( sql => $statement );
}
$self->save_current_name;
$self->set_instantiated(1);
my $driver = delete $self->{driver};
$self->{original} = Storable::dclone($self);
$self->{driver} = $driver;
delete $self->{original}{original};
}
sub _has_been_instantiated
{
my $self = shift;
my $db_schema_name = $self->db_schema_name;
return 1 if grep { $db_schema_name eq $_ } $self->{driver}->schemas(@_);
}
sub make_sql
{
my $self = shift;
if ($self->{instantiated})
{
return $self->rules->schema_sql_diff( old => $self->{original},
new => $self );
}
else
{
return $self->rules->schema_sql($self);
( run in 0.639 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )