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;