Mercurial > pub > Impl
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; |