Mercurial > pub > Impl
comparison Lib/IMPL/SQL/Schema/Traits/Diff.pm @ 194:4d0e1962161c
Replaced tabs with spaces
IMPL::Web::View - fixed document model, new features (control classes, document constructor parameters)
author | cin |
---|---|
date | Tue, 10 Apr 2012 20:08:29 +0400 |
parents | d1676be8afcc |
children | 77df11605d3a |
comparison
equal
deleted
inserted
replaced
193:8e8401c0aea4 | 194:4d0e1962161c |
---|---|
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 { |
10 schema_t => typeof IMPL::SQL::Schema # defining a constant is a good style to enable compile checks | 10 schema_t => typeof IMPL::SQL::Schema # defining a constant is a good style to enable compile checks |
11 }; | 11 }; |
12 | 12 |
13 sub Diff { | 13 sub Diff { |
14 my ($self,$src,$dst) = @_; | 14 my ($self,$src,$dst) = @_; |
15 | 15 |
16 die new IMPL::InvalidArgumentException( src => "A valid source schema is required") unless is($src,schema_t); | 16 die new IMPL::InvalidArgumentException( src => "A valid source schema is required") unless is($src,schema_t); |
17 die new IMPL::InvalidArgumentException( dst => "A valid desctination schema is requried" ) unless is($src,schema_t); | 17 die new IMPL::InvalidArgumentException( dst => "A valid desctination schema is requried" ) unless is($src,schema_t); |
18 | 18 |
19 my %dstTables = map { $_->name, $_ } $dst->GetTables; | 19 my %dstTables = map { $_->name, $_ } $dst->GetTables; |
20 | 20 |
21 my @operations; | 21 my @operations; |
22 | 22 |
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($srcTable->name); | 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 } | 34 } |
35 | 35 |
36 foreach my $tbl ( values %dstTables ) { | 36 foreach my $tbl ( values %dstTables ) { |
37 push @operations, new IMPL::SQL::Schema::Traits::CreateTable( | 37 push @operations, new IMPL::SQL::Schema::Traits::CreateTable( |
38 new IMPL::SQL::Schema::Traits::Table( | 38 new IMPL::SQL::Schema::Traits::Table( |
39 $tbl->name, | 39 $tbl->name, |
40 [ map _Column2Traits($_), @{$tbl->columns} ], | 40 [ map _Column2Traits($_), @{$tbl->columns} ], |
41 [ map _Constraint2Traits($_), $tbl->GetConstraints()], | 41 [ map _Constraint2Traits($_), $tbl->GetConstraints()], |
42 $tbl->{tag} | 42 $tbl->{tag} |
43 ) | 43 ) |
44 ) | 44 ) |
45 } | 45 } |
46 | 46 |
47 return \@operations; | 47 return \@operations; |
48 } | 48 } |
49 | 49 |
50 sub _DiffTables { | 50 sub _DiffTables { |
51 my ($self,$src,$dst) = @_; | 51 my ($self,$src,$dst) = @_; |
52 | 52 |
53 my @dropConstraints; | 53 my @dropConstraints; |
54 my @createConstraints; | 54 my @createConstraints; |
55 | 55 |
56 my %srcConstraints = map { $_->name, $_ } $src->GetConstraints(); | 56 my %srcConstraints = map { $_->name, $_ } $src->GetConstraints(); |
57 my %dstConstraints = map { $_->name, $_ } $dst->GetConstraints(); | 57 my %dstConstraints = map { $_->name, $_ } $dst->GetConstraints(); |
58 | 58 |
59 foreach my $cnSrcName (keys %srcConstraints) { | 59 foreach my $cnSrcName (keys %srcConstraints) { |
60 if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) { | 60 if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) { |
61 unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) { | 61 unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) { |
62 push @dropConstraints, | 62 push @dropConstraints, |
63 new IMPL::SQL::Schema::Traits::AlterTableDropConstraint( $src->name, $cnSrcName ); | 63 new IMPL::SQL::Schema::Traits::AlterTableDropConstraint( $src->name, $cnSrcName ); |
64 push @createConstraints, | 64 push @createConstraints, |
65 new IMPL::SQL::Schema::Traits::AlterTableAddConstraint( $dst->name, _Constraint2Traits($cnDst) ); | 65 new IMPL::SQL::Schema::Traits::AlterTableAddConstraint( $dst->name, _Constraint2Traits($cnDst) ); |
66 } | 66 } |
67 } else { | 67 } else { |
68 push @dropConstraints,new IMPL::SQL::Schema::Traits::AlterTableDropConstraint( $src->name, $cnSrcName ); | 68 push @dropConstraints,new IMPL::SQL::Schema::Traits::AlterTableDropConstraint( $src->name, $cnSrcName ); |
69 } | 69 } |
70 } | 70 } |
71 | 71 |
72 foreach my $cnDst (values %dstConstraints) { | 72 foreach my $cnDst (values %dstConstraints) { |
73 push @createConstraints, | 73 push @createConstraints, |
74 IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) ); | 74 IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) ); |
75 } | 75 } |
76 | 76 |
77 my @deleteColumns; | 77 my @deleteColumns; |
78 my @addColumns; | 78 my @addColumns; |
79 my @updateColumns; | 79 my @updateColumns; |
80 | 80 |
81 my %dstColumnIndexes = map { | 81 my %dstColumnIndexes = map { |
82 my $col = $dst->GetColumnAt($_); | 82 my $col = $dst->GetColumnAt($_); |
83 ($col->name, { column => $col, index => $_ }) | 83 ($col->name, { column => $col, index => $_ }) |
84 } 0 .. $dst->ColumnsCount-1; | 84 } 0 .. $dst->ColumnsCount-1; |
85 | 85 |
86 my @columns; | 86 my @columns; |
87 | 87 |
88 # remove old columns, mark for update changed columns | 88 # remove old columns, mark for update changed columns |
89 for( my $i=0; $i < $src->ColumnsCount; $i++) { | 89 for( my $i=0; $i < $src->ColumnsCount; $i++) { |
90 my $colSrc = $src->GetColumnAt($i); | 90 my $colSrc = $src->GetColumnAt($i); |
91 | 91 |
92 if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) { | 92 if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) { |
93 $infoDst->{prevColumn} = $colSrc; | 93 $infoDst->{prevColumn} = $colSrc; |
94 push @columns,$infoDst; | 94 push @columns,$infoDst; |
95 } else { | 95 } else { |
96 push @deleteColumns,new IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name); | 96 push @deleteColumns,new IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name); |
97 } | 97 } |
98 } | 98 } |
99 | 99 |
100 #insert new columns at specified positions | 100 #insert new columns at specified positions |
101 foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes ) { | 101 foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes ) { |
102 splice(@columns,$_->{index},0,$_); | 102 splice(@columns,$_->{index},0,$_); |
103 push @addColumns, new IMPL::SQL::Schema::Traits::AlterTableAddColumn($src->name, _Column2Traits( $_->{column}, position => $_->{index} )); | 103 push @addColumns, new IMPL::SQL::Schema::Traits::AlterTableAddColumn($src->name, _Column2Traits( $_->{column}, position => $_->{index} )); |
104 } | 104 } |
105 | 105 |
106 # remember old indexes | 106 # remember old indexes |
107 for(my $i =0; $i< @columns; $i ++) { | 107 for(my $i =0; $i< @columns; $i ++) { |
108 $columns[$i]->{prevIndex} = $i; | 108 $columns[$i]->{prevIndex} = $i; |
109 } | 109 } |
110 | 110 |
111 # reorder columns | 111 # reorder columns |
112 @columns = sort { $a->{index} <=> $b->{index} } @columns; | 112 @columns = sort { $a->{index} <=> $b->{index} } @columns; |
113 | 113 |
114 foreach my $info (@columns) { | 114 foreach my $info (@columns) { |
115 if ($info->{prevColumn} && ( !$info->{column}->SameValue($info->{prevColumn}) or $info->{index}!= $info->{prevIndex} ) ) { | 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); | 116 my $op = new IMPL::SQL::Schema::Traits::AlterTableChangeColumn($src->name,$info->{column}->name); |
117 | 117 |
118 $op->position( $info->{index} ) unless $info->{prevIndex} == $info->{index}; | 118 $op->position( $info->{index} ) unless $info->{prevIndex} == $info->{index}; |
119 $op->isNullable( $info->{column}->isNullable ) unless equals($info->{column}->isNullable,$info->{prevColumn}->isNullable); | 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); | 120 $op->defaultValue( $info->{column}->defaultValue ) unless equals($info->{column}->defaultValue, $info->{prevColumn}->defaultValue); |
121 | 121 |
122 my $diff = hashDiff($info->{prevColumn}->tag,$info->{column}->tag); | 122 my $diff = hashDiff($info->{prevColumn}->tag,$info->{column}->tag); |
123 $op->options($diff) if %$diff; | 123 $op->options($diff) if %$diff; |
124 | 124 |
125 push @updateColumns, $op; | 125 push @updateColumns, $op; |
126 } | 126 } |
127 } | 127 } |
128 | 128 |
129 my @result = (@dropConstraints, @deleteColumns, @addColumns, @updateColumns, @createConstraints); | 129 my @result = (@dropConstraints, @deleteColumns, @addColumns, @updateColumns, @createConstraints); |
130 | 130 |
131 return @result; | 131 return @result; |
132 } | 132 } |
133 | 133 |
134 sub _Column2Traits { | 134 sub _Column2Traits { |
135 my ($column,%options) = @_; | 135 my ($column,%options) = @_; |
136 | 136 |
137 return new IMPL::SQL::Schema::Traits::Column( | 137 return new IMPL::SQL::Schema::Traits::Column( |
138 $column->name, | 138 $column->name, |
139 $column->type, | 139 $column->type, |
140 isNullable => $column->isNullable, | 140 isNullable => $column->isNullable, |
141 defaultValue => $column->defaultValue, | 141 defaultValue => $column->defaultValue, |
142 tag => $column->tag, | 142 tag => $column->tag, |
143 %options | 143 %options |
144 ); | 144 ); |
145 } | 145 } |
146 | 146 |
147 sub _Constraint2Traits { | 147 sub _Constraint2Traits { |
148 my ($constraint) = @_; | 148 my ($constraint) = @_; |
149 | 149 |
150 my $map = { | 150 my $map = { |
151 typeof IMPL::SQL::Schema::Constraint::ForeignKey , typeof IMPL::SQL::Schema::Traits::ForeignKey, | 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, | 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, | 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 | 154 typeof IMPL::SQL::Schema::Constraint::Index , typeof IMPL::SQL::Schema::Traits::Index |
155 }; | 155 }; |
156 | 156 |
157 my $class = $map->{$constraint->typeof} or die new IMPL::Exception("Can't map the constraint",$constraint->typeof); | 157 my $class = $map->{$constraint->typeof} or die new IMPL::Exception("Can't map the constraint",$constraint->typeof); |
158 | 158 |
159 return $class->new( | 159 return $class->new( |
160 $constraint->name, | 160 $constraint->name, |
161 [ map $_->name, $constraint->columns ] | 161 [ map $_->name, $constraint->columns ] |
162 ) | 162 ) |
163 } | 163 } |
164 | 164 |
165 1; | 165 1; |