comparison Lib/IMPL/SQL/Schema/Traits/Diff.pm @ 168:6148f89bb7bf

IMPL::SQL::Schema::Traits::Diff alfa version IMPL::lang added hash traits
author sourcer
date Mon, 16 May 2011 04:30:38 +0400
parents 1f7a6d762394
children fd92830036c3
comparison
equal deleted inserted replaced
167:1f7a6d762394 168:6148f89bb7bf
1 package IMPL::SQL::Schema::Traits::Diff; 1 package IMPL::SQL::Schema::Traits::Diff;
2 use strict; 2 use strict;
3 use warnings; 3 use warnings;
4 use IMPL::lang; 4 use IMPL::lang qw(:compare :hash is);
5 5
6 use IMPL::SQL::Schema(); 6 use IMPL::SQL::Schema();
7 use IMPL::SQL::Schema::Traits(); 7 use IMPL::SQL::Schema::Traits();
8 8
9 use constant { 9 use constant {
23 foreach my $srcTable ( $src->GetTables) { 23 foreach my $srcTable ( $src->GetTables) {
24 my $dstTable = delete $dstTables{$srcTable->name}; 24 my $dstTable = delete $dstTables{$srcTable->name};
25 25
26 if (not $dstTable) { 26 if (not $dstTable) {
27 # if a source table doesn't have a corresponding destination table, it should be deleted 27 # if a source table doesn't have a corresponding destination table, it should be deleted
28 push @operations, new IMPL::SQL::Schema::Traits::DropTable() 28 push @operations, new IMPL::SQL::Schema::Traits::DropTable($srcTable->name);
29 } else { 29 } else {
30 # a source table needs to be updated 30 # a source table needs to be updated
31 push @operations, $self->_DiffTables($srcTable,$dstTable); 31 push @operations, $self->_DiffTables($srcTable,$dstTable);
32 } 32 }
33 33
34 foreach my $tbl ( values %dstTables ) { 34 }
35 push @operations, new IMPL::SQL::Schema::Traits::CreateTable( 35
36 new IMPL::SQL::Schema::Traits::Table( 36 foreach my $tbl ( values %dstTables ) {
37 $tbl->name, 37 push @operations, new IMPL::SQL::Schema::Traits::CreateTable(
38 [ map _Column2Traits($_), $tbl->columns ], 38 new IMPL::SQL::Schema::Traits::Table(
39 [ map _Constraint2Traits($_), $tbl->constraints], 39 $tbl->name,
40 $tbl->{tag} 40 [ map _Column2Traits($_), @{$tbl->columns} ],
41 ) 41 [ map _Constraint2Traits($_), $tbl->GetConstraints()],
42 $tbl->{tag}
42 ) 43 )
43 } 44 )
45 }
44 46
45 } 47 return \@operations;
46 } 48 }
47 49
48 sub _DiffTables { 50 sub _DiffTables {
49 my ($self,$src,$dst) = @_; 51 my ($self,$src,$dst) = @_;
50 52
56 58
57 foreach my $cnSrcName (keys %srcConstraints) { 59 foreach my $cnSrcName (keys %srcConstraints) {
58 if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) { 60 if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) {
59 unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) { 61 unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) {
60 push @dropConstraints, 62 push @dropConstraints,
61 IMPL::SQL::Schema::Traits::AlterTableDropConstraint->new( $src->name, $cnSrcName ); 63 new IMPL::SQL::Schema::Traits::AlterTableDropConstraint( $src->name, $cnSrcName );
62 push @createConstraints, 64 push @createConstraints,
63 IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) ); 65 new IMPL::SQL::Schema::Traits::AlterTableAddConstraint( $dst->name, _Constraint2Traits($cnDst) );
64 } 66 }
65 } else { 67 } else {
66 push @dropConstraints, IMPL::SQL::Schema::Traits::AlterTableDropConstrait->new( $src->name, $cnSrcName ); 68 push @dropConstraints,new IMPL::SQL::Schema::Traits::AlterTableDropConstrait( $src->name, $cnSrcName );
67 } 69 }
68 } 70 }
69 71
70 foreach my $cnDst (values %dstConstraints) { 72 foreach my $cnDst (values %dstConstraints) {
71 push @createConstraints, 73 push @createConstraints,
79 my %dstColumnIndexes = map { 81 my %dstColumnIndexes = map {
80 my $col = $dst->GetColumnAt($_); 82 my $col = $dst->GetColumnAt($_);
81 ($col->name, { column => $col, index => $_ }) 83 ($col->name, { column => $col, index => $_ })
82 } 0 .. $dst->ColumnsCount-1; 84 } 0 .. $dst->ColumnsCount-1;
83 85
84 # get changed and
85
86 my @columns; 86 my @columns;
87 87
88 # remove old columns, mark for update changed columns
88 for( my $i=0; $i < $src->ColumnsCount; $i++) { 89 for( my $i=0; $i < $src->ColumnsCount; $i++) {
89 my $colSrc = $src->GetColumnAt($i); 90 my $colSrc = $src->GetColumnAt($i);
90 91
91 if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) { 92 if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) {
92 $infoDst->{update} = 1 unless $infoDst->{column}->SameValue($colSrc); 93 $infoDst->{prevColumn} = $colSrc;
93 push @columns,$infoDst; 94 push @columns,$infoDst;
94 } else { 95 } else {
95 push @deleteColumns, IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name); 96 push @deleteColumns,new IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name);
96 } 97 }
97 } 98 }
98 99
99 splice(@columns,$_->{index},0,$_) foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes ); 100 #insert new columns at specified positions
100 101 foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes ) {
101 for(my $i =0; $i< @columns; $i ++) { 102 splice(@columns,$_->{index},0,$_);
102 103 push @addColumns, new IMPL::SQL::Schema::Traits::AlterTableAddColumn($src->name, _Column2Traits( $_->{column}, position => $_->{index} ));
103 } 104 }
104 105
105 # determine constraints to be dropped, 106 # remember old indexes
106 # drop columns 107 for(my $i =0; $i< @columns; $i ++) {
107 # create columns 108 $columns[$i]->{prevIndex} = $i;
108 # update/reorder columns 109 }
109 # create constraints 110
111 # reorder columns
112 @columns = sort { $a->{index} <=> $b->{index} } @columns;
113
114 foreach my $info (@columns) {
115 if ($info->{prevColumn} && ( !$info->{column}->SameValue($info->{prevColumn}) or $info->{index}!= $info->{prevIndex} ) ) {
116 my $op = new IMPL::SQL::Schema::Traits::AlterTableChangeColumn($src->name,$info->{column}->name);
117
118 $op->position( $info->{index} ) unless $info->{prevIndex} == $info->{index};
119 $op->isNullable( $info->{column}->isNullable ) unless equals($info->{column}->isNullable,$info->{prevColumn}->isNullable);
120 $op->defaultValue( $info->{column}->defaultValue ) unless equals($info->{column}->defaultValue, $info->{prevColumn}->defaultValue);
121
122 my %diff = hashDiff($info->{prevColumn},$info->{column});
123 $op->options(\%diff) if %diff;
124
125 push @updateColumns, $op;
126 }
127 }
128
129 my @result = (@dropConstraints, @deleteColumns, @addColumns, @updateColumns, @createConstraints);
130
131 return @result;
110 } 132 }
111 133
112 sub _Column2Traits { 134 sub _Column2Traits {
113 my ($column) = @_; 135 my ($column,%options) = @_;
114 136
115 return new IMPL::SQL::Schema::Traits::Columns( 137 return new IMPL::SQL::Schema::Traits::Column(
116 $column->name, 138 $column->name,
117 $column->type, 139 $column->type,
118 $column->isNullable, 140 isNullable => $column->isNullable,
119 $column->defaultValue, 141 defaultValue => $column->defaultValue,
120 $column->tag 142 tag => $column->tag,
143 %options
121 ); 144 );
122 } 145 }
123 146
124 sub _Constraint2Traits { 147 sub _Constraint2Traits {
125 my ($constraint) = @_; 148 my ($constraint) = @_;
126 149
127 return new IMPL::SQL::Schema::Traits::Constraint( 150 my $map = {
151 typeof IMPL::SQL::Schema::Constraint::ForeignKey , typeof IMPL::SQL::Schema::Traits::ForeignKey,
152 typeof IMPL::SQL::Schema::Constraint::PrimaryKey , typeof IMPL::SQL::Schema::Traits::PrimaryKey,
153 typeof IMPL::SQL::Schema::Constraint::Unique , typeof IMPL::SQL::Schema::Traits::Unique,
154 typeof IMPL::SQL::Schema::Constraint::Index , typeof IMPL::SQL::Schema::Traits::Index
155 };
156
157 my $class = $map->{$constraint->typeof} or die new IMPL::Exception("Can't map the constraint",$constraint->typeof);
158
159 return $class->new(
128 $constraint->name, 160 $constraint->name,
129 [ map $_->name, $_->columns ] 161 [ map $_->name, $constraint->columns ]
130 ) 162 )
131 } 163 }
132 164
133 1; 165 1;