165
|
1 package IMPL::SQL::Schema::Traits::Diff;
|
|
2 use strict;
|
|
3 use warnings;
|
|
4 use IMPL::lang;
|
|
5
|
|
6 use IMPL::SQL::Schema();
|
|
7 use IMPL::SQL::Schema::Traits();
|
|
8
|
|
9 use constant {
|
|
10 schema_t => typeof IMPL::SQL::Schema # defining a constant is a good style to enable compile checks
|
|
11 };
|
|
12
|
|
13 sub Diff {
|
|
14 my ($self,$src,$dst) = @_;
|
|
15
|
|
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);
|
|
18
|
|
19 my %dstTables = map { $_->name, $_ } $dst->GetTables;
|
|
20
|
|
21 my @operations;
|
|
22
|
|
23 foreach my $srcTable ( $src->GetTables) {
|
|
24 my $dstTable = delete $dstTables{$srcTable->name};
|
|
25
|
|
26 if (not $dstTable) {
|
167
|
27 # if a source table doesn't have a corresponding destination table, it should be deleted
|
165
|
28 push @operations, new IMPL::SQL::Schema::Traits::DropTable()
|
|
29 } else {
|
167
|
30 # a source table needs to be updated
|
|
31 push @operations, $self->_DiffTables($srcTable,$dstTable);
|
|
32 }
|
|
33
|
|
34 foreach my $tbl ( values %dstTables ) {
|
|
35 push @operations, new IMPL::SQL::Schema::Traits::CreateTable(
|
|
36 new IMPL::SQL::Schema::Traits::Table(
|
|
37 $tbl->name,
|
|
38 [ map _Column2Traits($_), $tbl->columns ],
|
|
39 [ map _Constraint2Traits($_), $tbl->constraints],
|
|
40 $tbl->{tag}
|
|
41 )
|
|
42 )
|
165
|
43 }
|
|
44
|
|
45 }
|
|
46 }
|
|
47
|
167
|
48 sub _DiffTables {
|
|
49 my ($self,$src,$dst) = @_;
|
|
50
|
|
51 my @dropConstraints;
|
|
52 my @createConstraints;
|
|
53
|
|
54 my %srcConstraints = map { $_->name, $_ } $src->GetConstraints();
|
|
55 my %dstConstraints = map { $_->name, $_ } $dst->GetConstraints();
|
|
56
|
|
57 foreach my $cnSrcName (keys %srcConstraints) {
|
|
58 if ( my $cnDst = delete $dstConstraints{$cnSrcName} ) {
|
|
59 unless ( $srcConstraints{$cnSrcName}->SameValue($cnDst) ) {
|
|
60 push @dropConstraints,
|
|
61 IMPL::SQL::Schema::Traits::AlterTableDropConstraint->new( $src->name, $cnSrcName );
|
|
62 push @createConstraints,
|
|
63 IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) );
|
|
64 }
|
|
65 } else {
|
|
66 push @dropConstraints, IMPL::SQL::Schema::Traits::AlterTableDropConstrait->new( $src->name, $cnSrcName );
|
|
67 }
|
|
68 }
|
|
69
|
|
70 foreach my $cnDst (values %dstConstraints) {
|
|
71 push @createConstraints,
|
|
72 IMPL::SQL::Schema::Traits::AlterTableAddConstraint->new( $dst->name, _Constraint2Traits($cnDst) );
|
|
73 }
|
|
74
|
|
75 my @deleteColumns;
|
|
76 my @addColumns;
|
|
77 my @updateColumns;
|
|
78
|
|
79 my %dstColumnIndexes = map {
|
|
80 my $col = $dst->GetColumnAt($_);
|
|
81 ($col->name, { column => $col, index => $_ })
|
|
82 } 0 .. $dst->ColumnsCount-1;
|
|
83
|
|
84 # get changed and
|
|
85
|
|
86 my @columns;
|
|
87
|
|
88 for( my $i=0; $i < $src->ColumnsCount; $i++) {
|
|
89 my $colSrc = $src->GetColumnAt($i);
|
|
90
|
|
91 if ( my $infoDst = delete $dstColumnIndexes{$colSrc->name} ) {
|
|
92 $infoDst->{update} = 1 unless $infoDst->{column}->SameValue($colSrc);
|
|
93 push @columns,$infoDst;
|
|
94 } else {
|
|
95 push @deleteColumns, IMPL::SQL::Schema::Traits::AlterTableDropColumn($src->name,$colSrc->name);
|
|
96 }
|
|
97 }
|
|
98
|
|
99 splice(@columns,$_->{index},0,$_) foreach ( sort { $a->{index} <=> $b->{index} } values %dstColumnIndexes );
|
|
100
|
|
101 for(my $i =0; $i< @columns; $i ++) {
|
|
102
|
|
103 }
|
|
104
|
|
105 # determine constraints to be dropped,
|
|
106 # drop columns
|
|
107 # create columns
|
|
108 # update/reorder columns
|
|
109 # create constraints
|
|
110 }
|
|
111
|
|
112 sub _Column2Traits {
|
|
113 my ($column) = @_;
|
|
114
|
|
115 return new IMPL::SQL::Schema::Traits::Columns(
|
|
116 $column->name,
|
|
117 $column->type,
|
|
118 $column->isNullable,
|
|
119 $column->defaultValue,
|
|
120 $column->tag
|
|
121 );
|
|
122 }
|
|
123
|
|
124 sub _Constraint2Traits {
|
|
125 my ($constraint) = @_;
|
|
126
|
|
127 return new IMPL::SQL::Schema::Traits::Constraint(
|
|
128 $constraint->name,
|
|
129 [ map $_->name, $_->columns ]
|
|
130 )
|
|
131 }
|
|
132
|
165
|
133 1; |