Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Topic/producer postgresql batch alter table #44

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions lib/SQL/Translator/Producer/PostgreSQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,72 @@ sub drop_table {
return $out;
}

sub batch_alter_table {
my ( $table, $diff_hash, $options ) = @_;
my $qt = $options->{quote_table_names} || '';
$generator->quote_chars([$qt]);

# as long as we're not renaming the table we don't need to be here
if ( @{$diff_hash->{rename_table}} == 0 ) {
return map {
if (@{ $diff_hash->{$_} || [] }) {
my $meth = __PACKAGE__->can($_) or die __PACKAGE__ . " cant $_";
map { $meth->( (ref $_ eq 'ARRAY' ? @$_ : $_), $options ) }
@{ $diff_hash->{$_} }
}
else { () }
} qw/alter_drop_constraint
alter_drop_index
drop_field
add_field
alter_field
rename_field
alter_create_index
alter_create_constraint
alter_table/;
}

# first we need to perform drops which are on old table
my @sql = map {
if (@{ $diff_hash->{$_} || [] }) {
my $meth = __PACKAGE__->can($_) or die __PACKAGE__ . " cant $_";
map { $meth->( (ref $_ eq 'ARRAY' ? @$_ : $_), $options ) }
@{ $diff_hash->{$_} }
}
else { () }
} qw/alter_drop_constraint
alter_drop_index
drop_field/;

# next comes the rename_table
my $old_table = $diff_hash->{rename_table}[0][0];
push @sql, rename_table( $old_table, $table, $options );

# for alter_field (and so also rename_field) we need to make sure old
# field has table name set to new table otherwise calling alter_field dies
$diff_hash->{alter_field} =
[map { $_->[0]->table($table) && $_ } @{$diff_hash->{alter_field}}];
$diff_hash->{rename_field} =
[map { $_->[0]->table($table) && $_ } @{$diff_hash->{rename_field}}];

# now add everything else
push @sql, map {
if (@{ $diff_hash->{$_} || [] }) {
my $meth = __PACKAGE__->can($_) or die __PACKAGE__ . " cant $_";
map { $meth->( (ref $_ eq 'ARRAY' ? @$_ : $_), $options ) }
@{ $diff_hash->{$_} }
}
else { () }
} qw/add_field
alter_field
rename_field
alter_create_index
alter_create_constraint
alter_table/;

return @sql;
}

1;

# -------------------------------------------------------------------
Expand Down
24 changes: 12 additions & 12 deletions t/30sqlt-new-diff-pgsql.t
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,21 @@ CREATE TABLE added (
id bigint
);

ALTER TABLE old_name RENAME TO new_name;

ALTER TABLE employee DROP CONSTRAINT FK5302D47D93FE702E;

ALTER TABLE person DROP CONSTRAINT UC_age_name;
ALTER TABLE employee DROP COLUMN job_title;

DROP INDEX u_name;
ALTER TABLE employee ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id)
REFERENCES person (person_id) DEFERRABLE;

ALTER TABLE employee DROP COLUMN job_title;
ALTER TABLE old_name RENAME TO new_name;

ALTER TABLE new_name ADD COLUMN new_field integer;

ALTER TABLE person DROP CONSTRAINT UC_age_name;

DROP INDEX u_name;

ALTER TABLE person ADD COLUMN is_rock_star smallint DEFAULT 1;

ALTER TABLE person ALTER COLUMN person_id TYPE serial;
Expand All @@ -85,9 +88,6 @@ ALTER TABLE person RENAME COLUMN description TO physical_description;

ALTER TABLE person ADD CONSTRAINT unique_name UNIQUE (name);

ALTER TABLE employee ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id)
REFERENCES person (person_id) DEFERRABLE;

ALTER TABLE person ADD CONSTRAINT UC_person_id UNIQUE (person_id);

ALTER TABLE person ADD CONSTRAINT UC_age_name UNIQUE (age, name);
Expand Down Expand Up @@ -118,14 +118,14 @@ CREATE TABLE added (
id bigint
);

ALTER TABLE old_name RENAME TO new_name;

ALTER TABLE person DROP CONSTRAINT UC_age_name;

ALTER TABLE employee DROP COLUMN job_title;

ALTER TABLE old_name RENAME TO new_name;

ALTER TABLE new_name ADD COLUMN new_field integer;

ALTER TABLE person DROP CONSTRAINT UC_age_name;

ALTER TABLE person ADD COLUMN is_rock_star smallint DEFAULT 1;

ALTER TABLE person ALTER COLUMN person_id TYPE serial;
Expand Down
71 changes: 71 additions & 0 deletions t/postgresql-rename-table-and-field.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env perl

use strict;
use warnings;

use Test::More;
use Test::SQL::Translator;
use SQL::Translator;
use SQL::Translator::Diff;

maybe_plan(10, 'DBD::Pg', 'Test::PostgreSQL');

my ( $pgsql, $dbh , $ddl, $ret );

no warnings "once";
$pgsql = Test::PostgreSQL->new() or die $Test::PostgreSQL::errstr;
$dbh = DBI->connect($pgsql->dsn,'','', { RaiseError => 1 }) or die $DBI::errstr;
use warnings "once";

my $source_ddl = <<DDL;
CREATE TABLE foo (
pk SERIAL PRIMARY KEY,
bar VARCHAR(10)
);
DDL

ok( $ret = $dbh->do($source_ddl), "create table" );

ok( $ret = $dbh->do(q| INSERT INTO foo (bar) VALUES ('buzz') |), "insert data" );

cmp_ok( $ret, '==', 1, "one row inserted" );

my $target_ddl = <<DDL;
CREATE TABLE fluff (
pk SERIAL PRIMARY KEY,
biff VARCHAR(10)
);
DDL

my $source_sqlt = SQL::Translator->new(
no_comments => 1,
parser => 'SQL::Translator::Parser::PostgreSQL',
)->translate(\$source_ddl);

my $target_sqlt = SQL::Translator->new(
no_comments => 1,
parser => 'SQL::Translator::Parser::PostgreSQL',
)->translate(\$target_ddl);

my $table = $target_sqlt->get_table('fluff');
$table->extra( renamed_from => 'foo' );
my $field = $table->get_field('biff');
$field->extra( renamed_from => 'bar' );

my @diff = SQL::Translator::Diff->new({
output_db => 'PostgreSQL',
source_schema => $source_sqlt,
target_schema => $target_sqlt,
})->compute_differences->produce_diff_sql;

foreach my $line (@diff) {
$line =~ s/\n//g;
next if $line =~ /^--/;
ok( $dbh->do($line), "$line" );
}

ok ( $ret = $dbh->selectall_arrayref(q(SELECT biff FROM fluff), { Slice => {} }), "query DB for data" );

cmp_ok( scalar(@$ret), '==', 1, "Got 1 row");

cmp_ok( $ret->[0]->{biff}, 'eq', 'buzz', "col biff has value buzz" );