view Lib/IMPL/SQL/Schema/MySQL/Processor.pm @ 393:69a1f1508696

minor security refactoring
author cin
date Fri, 14 Feb 2014 16:41:12 +0400
parents 2f06250bab5f
children
line wrap: on
line source

package IMPL::SQL::Schema::MySQL::Processor;
use strict;

use mro;
use IMPL::Const qw(:prop);
use IMPL::declare {
    require => {
        MySQLFormatter           => 'IMPL::SQL::Schema::MySQL::Formatter',
        AlterTableDropConstraint => '-IMPL::SQL::Schema::Traits::AlterTableDropConstraint',
        AlterTableAddConstraint  => '-IMPL::SQL::Schema::Traits::AlterTableAddConstraint',
        DropTable                => '-IMPL::SQL::Schema::Traits::DropTable',
        PrimitiveDropTable       => '-IMPL::SQL::Schema::MySQL::Processor::PrimitiveDropTable',
        CreateTable              => '-IMPL::SQL::Schema::Traits::CreateTable',
        Table                    => '-IMPL::SQL::Schema::Traits::Table',
        ForeignKey               => '-IMPL::SQL::Schema::Traits::ForeignKey',
        
    },
    base  => [
        'IMPL::SQL::Schema::Processor' => sub { $_[0] }
    ],
    props => [
        formatter   => PROP_RO,
        sqlBatch    => PROP_RO
    ]
};
use IMPL::lang qw(is);

sub CTOR {
    my ( $this, $schema, %opts ) = @_;

    $this->formatter( $opts{formatter} || MySQLFormatter );
    $this->sqlBatch([]);
}

sub AddSqlBatch {
    my $this = shift;
    
    push @{$this->sqlBatch}, @_;
}

sub ApplyOperation {
    my ($this, $op, $iteration ) = @_;
    
    my @formatterParams;

    if ( is( $op, AlterTableDropConstraint ) ) {
        my $constraint = $this
            ->dbSchema
            ->GetTable($op->tableName)
            ->GetConstraint($op->constraintName);
            
        push @formatterParams, ref $constraint;
    } else {
        push @formatterParams, $this->dbSchema;        
    }
    
    if ( is( $op, CreateTable ) ) {
        my @constraints;
        my @fk;
        my $table = $op->table;
        
        # отделяем создание внешних ключей от таблиц
        
        foreach my $c (@{$table->{constraints} || []}) {
            if ( is($c,ForeignKey)) {
                push @fk,$c;
            } else {
                push @constraints, $c;
            }
        }
        
        if (@fk) {
            $op = CreateTable->new(
                Table->new(
                    $table->{name},
                    $table->{columns},
                    \@constraints,
                    $table->{options}
                )
            );
            
            $this->AddPendingOperations(
                map AlterTableAddConstraint->new($table->{name},$_), @fk
            );
        }
    }
    
    if (is($op, DropTable)) {
    	my $table = $this->dbSchema->GetTable($op->tableName);
    	
    	if(my $pk = $table->primaryKey) {
            $this->ApplyOperation($_,$iteration)
                foreach
                map
                    AlterTableDropConstraint->new($_->table->name,$_->name),
                    values %{$pk->connectedFK || {}};                    
    	}
    }
    
    $this->next::method($op,$iteration);
    
    $this->AddSqlBatch(
        $this->formatter->Format($op,@formatterParams)
    );
}

package IMPL::SQL::Schema::MySQL::Processor::PrimitiveDropTable;
use IMPL::Const qw(:prop);
use IMPL::declare {
	require => {
		ArgException => '-IMPL::InvalidArgumentException'
	},
	base => [
	   'IMPL::Object' => undef
	],
    props => [
        tableName => PROP_RO,
    ]
};

sub CTOR {
    my ($this,$tableName) = @_;
    
    $this->tableName($tableName) or die ArgException->new("tableName is required");
}

sub CanApply {
    my ($this,$schema) = @_;
    
    my $table = $schema->GetTable( $this->tableName )
        or return 0;

    my $pk = $table->primaryKey
        or return 1;
    
    my $canDrop = keys(%{$pk->connectedFK || {}}) ? 0 : 1;
    
    warn "Can drop ", $this->tableName
        if $canDrop;
    
    return $canDrop;
}

sub Apply {
    my ($this,$schema) = @_;
    
    $schema->RemoveTable($this->tableName);
}

1;