Mercurial > pub > Impl
view Lib/IMPL/SQL/Schema/Traits/Diff.pm @ 167:1f7a6d762394
SQL schema in progress
author | sourcer |
---|---|
date | Thu, 12 May 2011 08:57:19 +0400 |
parents | 76515373dac0 |
children | 6148f89bb7bf |
line wrap: on
line source
package IMPL::SQL::Schema::Traits::Diff; use strict; use warnings; use IMPL::lang; use IMPL::SQL::Schema(); use IMPL::SQL::Schema::Traits(); use constant { schema_t => typeof IMPL::SQL::Schema # defining a constant is a good style to enable compile checks }; sub Diff { my ($self,$src,$dst) = @_; die new IMPL::InvalidArgumentException( src => "A valid source schema is required") unless is($src,schema_t); die new IMPL::InvalidArgumentException( dst => "A valid desctination schema is requried" ) unless is($src,schema_t); my %dstTables = map { $_->name, $_ } $dst->GetTables; my @operations; foreach my $srcTable ( $src->GetTables) { my $dstTable = delete $dstTables{$srcTable->name}; if (not $dstTable) { # if a source table doesn't have a corresponding destination table, it should be deleted push @operations, new IMPL::SQL::Schema::Traits::DropTable() } else { # a source table needs to be updated push @operations, $self->_DiffTables($srcTable,$dstTable); } foreach my $tbl ( values %dstTables ) { push @operations, new IMPL::SQL::Schema::Traits::CreateTable( new IMPL::SQL::Schema::Traits::Table( $tbl->name, [ map _Column2Traits($_), $tbl->columns ], [ map _Constraint2Traits($_), $tbl->constraints], $tbl->{tag} ) ) } } } sub _DiffTables { my ($self,$src,$dst) = @_; my @dropConstraints; my @createConstraints; my %srcConstraints = map { $_->name, $_ } $src->GetConstraints(); my %dstConstraints = map { $_->name, $_ } $dst->GetConstraints(); foreach my $cnSrcName (keys %srcConstraints) { if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) { unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) { push @dropConstraints, IMPL::SQL::Schema::Traits::AlterTableDropConstraint->new( $src->name, $cnSrcName ); push @createConstraints, IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) ); } } else { push @dropConstraints, IMPL::SQL::Schema::Traits::AlterTableDropConstrait->new( $src->name, $cnSrcName ); } } foreach my $cnDst (values %dstConstraints) { push @createConstraints, IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) ); } my @deleteColumns; my @addColumns; my @updateColumns; my %dstColumnIndexes = map { my $col = $dst->GetColumnAt($_); ($col->name, { column => $col, index => $_ }) } 0 .. $dst->ColumnsCount-1; # get changed and my @columns; for( my $i=0; $i < $src->ColumnsCount; $i++) { my $colSrc = $src->GetColumnAt($i); if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) { $infoDst->{update} = 1 unless $infoDst->{column}->SameValue($colSrc); push @columns,$infoDst; } else { push @deleteColumns, IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name); } } splice(@columns,$_->{index},0,$_) foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes ); for(my $i =0; $i< @columns; $i ++) { } # determine constraints to be dropped, # drop columns # create columns # update/reorder columns # create constraints } sub _Column2Traits { my ($column) = @_; return new IMPL::SQL::Schema::Traits::Columns( $column->name, $column->type, $column->isNullable, $column->defaultValue, $column->tag ); } sub _Constraint2Traits { my ($constraint) = @_; return new IMPL::SQL::Schema::Traits::Constraint( $constraint->name, [ map $_->name, $_->columns ] ) } 1;