| 
407
 | 
     1 package IMPL::SQL::Schema::MySQL::Processor;
 | 
| 
 | 
     2 use strict;
 | 
| 
 | 
     3 
 | 
| 
 | 
     4 use mro;
 | 
| 
 | 
     5 use IMPL::Const qw(:prop);
 | 
| 
 | 
     6 use IMPL::declare {
 | 
| 
 | 
     7     require => {
 | 
| 
 | 
     8         MySQLFormatter           => 'IMPL::SQL::Schema::MySQL::Formatter',
 | 
| 
 | 
     9         AlterTableDropConstraint => '-IMPL::SQL::Schema::Traits::AlterTableDropConstraint',
 | 
| 
 | 
    10         AlterTableAddConstraint  => '-IMPL::SQL::Schema::Traits::AlterTableAddConstraint',
 | 
| 
 | 
    11         DropTable                => '-IMPL::SQL::Schema::Traits::DropTable',
 | 
| 
 | 
    12         PrimitiveDropTable       => '-IMPL::SQL::Schema::MySQL::Processor::PrimitiveDropTable',
 | 
| 
 | 
    13         CreateTable              => '-IMPL::SQL::Schema::Traits::CreateTable',
 | 
| 
 | 
    14         Table                    => '-IMPL::SQL::Schema::Traits::Table',
 | 
| 
 | 
    15         ForeignKey               => '-IMPL::SQL::Schema::Traits::ForeignKey',
 | 
| 
 | 
    16         
 | 
| 
 | 
    17     },
 | 
| 
 | 
    18     base  => [
 | 
| 
 | 
    19         'IMPL::SQL::Schema::Processor' => sub { $_[0] }
 | 
| 
 | 
    20     ],
 | 
| 
 | 
    21     props => [
 | 
| 
 | 
    22         formatter   => PROP_RO,
 | 
| 
 | 
    23         sqlBatch    => PROP_RO
 | 
| 
 | 
    24     ]
 | 
| 
 | 
    25 };
 | 
| 
 | 
    26 use IMPL::lang qw(is);
 | 
| 
 | 
    27 
 | 
| 
 | 
    28 sub CTOR {
 | 
| 
 | 
    29     my ( $this, $schema, %opts ) = @_;
 | 
| 
 | 
    30 
 | 
| 
 | 
    31     $this->formatter( $opts{formatter} || MySQLFormatter );
 | 
| 
 | 
    32     $this->sqlBatch([]);
 | 
| 
 | 
    33 }
 | 
| 
 | 
    34 
 | 
| 
 | 
    35 sub AddSqlBatch {
 | 
| 
 | 
    36     my $this = shift;
 | 
| 
 | 
    37     
 | 
| 
 | 
    38     push @{$this->sqlBatch}, @_;
 | 
| 
 | 
    39 }
 | 
| 
 | 
    40 
 | 
| 
 | 
    41 sub ApplyOperation {
 | 
| 
 | 
    42     my ($this, $op, $iteration ) = @_;
 | 
| 
 | 
    43     
 | 
| 
 | 
    44     my @formatterParams;
 | 
| 
 | 
    45 
 | 
| 
 | 
    46     if ( is( $op, AlterTableDropConstraint ) ) {
 | 
| 
 | 
    47         my $constraint = $this
 | 
| 
 | 
    48             ->dbSchema
 | 
| 
 | 
    49             ->GetTable($op->tableName)
 | 
| 
 | 
    50             ->GetConstraint($op->constraintName);
 | 
| 
 | 
    51             
 | 
| 
 | 
    52         push @formatterParams, ref $constraint;
 | 
| 
 | 
    53     } else {
 | 
| 
 | 
    54         push @formatterParams, $this->dbSchema;        
 | 
| 
 | 
    55     }
 | 
| 
 | 
    56     
 | 
| 
 | 
    57     if ( is( $op, CreateTable ) ) {
 | 
| 
 | 
    58         my @constraints;
 | 
| 
 | 
    59         my @fk;
 | 
| 
 | 
    60         my $table = $op->table;
 | 
| 
 | 
    61         
 | 
| 
 | 
    62         # отделяем создание внешних ключей от таблиц
 | 
| 
 | 
    63         
 | 
| 
 | 
    64         foreach my $c (@{$table->{constraints} || []}) {
 | 
| 
 | 
    65             if ( is($c,ForeignKey)) {
 | 
| 
 | 
    66                 push @fk,$c;
 | 
| 
 | 
    67             } else {
 | 
| 
 | 
    68                 push @constraints, $c;
 | 
| 
 | 
    69             }
 | 
| 
 | 
    70         }
 | 
| 
 | 
    71         
 | 
| 
 | 
    72         if (@fk) {
 | 
| 
 | 
    73             $op = CreateTable->new(
 | 
| 
 | 
    74                 Table->new(
 | 
| 
 | 
    75                     $table->{name},
 | 
| 
 | 
    76                     $table->{columns},
 | 
| 
 | 
    77                     \@constraints,
 | 
| 
 | 
    78                     $table->{options}
 | 
| 
 | 
    79                 )
 | 
| 
 | 
    80             );
 | 
| 
 | 
    81             
 | 
| 
 | 
    82             $this->AddPendingOperations(
 | 
| 
 | 
    83                 map AlterTableAddConstraint->new($table->{name},$_), @fk
 | 
| 
 | 
    84             );
 | 
| 
 | 
    85         }
 | 
| 
 | 
    86     }
 | 
| 
 | 
    87     
 | 
| 
 | 
    88     if (is($op, DropTable)) {
 | 
| 
 | 
    89     	my $table = $this->dbSchema->GetTable($op->tableName);
 | 
| 
 | 
    90     	
 | 
| 
 | 
    91     	if(my $pk = $table->primaryKey) {
 | 
| 
 | 
    92             $this->ApplyOperation($_,$iteration)
 | 
| 
 | 
    93                 foreach
 | 
| 
 | 
    94                 map
 | 
| 
 | 
    95                     AlterTableDropConstraint->new($_->table->name,$_->name),
 | 
| 
 | 
    96                     values %{$pk->connectedFK || {}};                    
 | 
| 
 | 
    97     	}
 | 
| 
 | 
    98     }
 | 
| 
 | 
    99     
 | 
| 
 | 
   100     $this->next::method($op,$iteration);
 | 
| 
 | 
   101     
 | 
| 
 | 
   102     $this->AddSqlBatch(
 | 
| 
 | 
   103         $this->formatter->Format($op,@formatterParams)
 | 
| 
 | 
   104     );
 | 
| 
 | 
   105 }
 | 
| 
 | 
   106 
 | 
| 
 | 
   107 package IMPL::SQL::Schema::MySQL::Processor::PrimitiveDropTable;
 | 
| 
 | 
   108 use IMPL::Const qw(:prop);
 | 
| 
 | 
   109 use IMPL::declare {
 | 
| 
 | 
   110 	require => {
 | 
| 
 | 
   111 		ArgException => '-IMPL::InvalidArgumentException'
 | 
| 
 | 
   112 	},
 | 
| 
 | 
   113 	base => [
 | 
| 
 | 
   114 	   'IMPL::Object' => undef
 | 
| 
 | 
   115 	],
 | 
| 
 | 
   116     props => [
 | 
| 
 | 
   117         tableName => PROP_RO,
 | 
| 
 | 
   118     ]
 | 
| 
 | 
   119 };
 | 
| 
 | 
   120 
 | 
| 
 | 
   121 sub CTOR {
 | 
| 
 | 
   122     my ($this,$tableName) = @_;
 | 
| 
 | 
   123     
 | 
| 
 | 
   124     $this->tableName($tableName) or die ArgException->new("tableName is required");
 | 
| 
 | 
   125 }
 | 
| 
 | 
   126 
 | 
| 
 | 
   127 sub CanApply {
 | 
| 
 | 
   128     my ($this,$schema) = @_;
 | 
| 
 | 
   129     
 | 
| 
 | 
   130     my $table = $schema->GetTable( $this->tableName )
 | 
| 
 | 
   131         or return 0;
 | 
| 
 | 
   132 
 | 
| 
 | 
   133     my $pk = $table->primaryKey
 | 
| 
 | 
   134         or return 1;
 | 
| 
 | 
   135     
 | 
| 
 | 
   136     my $canDrop = keys(%{$pk->connectedFK || {}}) ? 0 : 1;
 | 
| 
 | 
   137     
 | 
| 
 | 
   138     warn "Can drop ", $this->tableName
 | 
| 
 | 
   139         if $canDrop;
 | 
| 
 | 
   140     
 | 
| 
 | 
   141     return $canDrop;
 | 
| 
 | 
   142 }
 | 
| 
 | 
   143 
 | 
| 
 | 
   144 sub Apply {
 | 
| 
 | 
   145     my ($this,$schema) = @_;
 | 
| 
 | 
   146     
 | 
| 
 | 
   147     $schema->RemoveTable($this->tableName);
 | 
| 
 | 
   148 }
 | 
| 
 | 
   149 
 | 
| 
 | 
   150 1;
 |