Use Mojo::Pg for migrations

This commit is contained in:
Daniel Friesel 2019-04-22 12:30:05 +02:00
parent 2aece36803
commit c65232904f

View file

@ -8,35 +8,22 @@ has description => 'Initialize or upgrade database layout';
has usage => sub { shift->extract_usage }; has usage => sub { shift->extract_usage };
sub get_schema_version { sub get_schema_version {
my ($dbh) = @_; my ($db) = @_;
my $version;
# We do not want DBD to print an SQL error if schema_version does not eval {
# exist, as this is not an error in this case. Setting $dbh->{PrintError} = $version = $db->select( 'schema_version', ['version'] )->hash->{version};
# 0 would disable error printing for all subsequent SQL operations, however, };
# we only want to disable it for this specific query. Hence we use a if ($@) {
# prepared statement and only disable error printing only there. # If it failed, the version table does not exist -> run setup first.
my $sth = $dbh->prepare(qq{select version from schema_version});
$sth->{PrintError} = 0;
my $success = $sth->execute;
if ( not defined $success ) {
return undef; return undef;
} }
return $version;
my $rows = $sth->fetchall_arrayref;
if ( @{$rows} == 1 ) {
return $rows->[0][0];
}
else {
printf( "Found multiple schema versions: %s", @{$rows} );
exit(1);
}
} }
sub initialize_db { sub initialize_db {
my ($dbh) = @_; my ($db) = @_;
return $dbh->do( $db->query(
qq{ qq{
create table schema_version ( create table schema_version (
version integer primary key version integer primary key
@ -93,8 +80,8 @@ my @migrations = (
# v0 -> v1 # v0 -> v1
sub { sub {
my ($dbh) = @_; my ($db) = @_;
return $dbh->do( $db->query(
qq{ qq{
alter table user_actions alter table user_actions
add column edited smallint; add column edited smallint;
@ -113,8 +100,8 @@ my @migrations = (
# v1 -> v2 # v1 -> v2
sub { sub {
my ($dbh) = @_; my ($db) = @_;
return $dbh->do( $db->query(
qq{ qq{
update user_actions set edited = 0; update user_actions set edited = 0;
alter table user_actions alter table user_actions
@ -129,8 +116,8 @@ my @migrations = (
# reported for routes covering stations without GPS coordinates. Ensure # reported for routes covering stations without GPS coordinates. Ensure
# all caches are rebuilt. # all caches are rebuilt.
sub { sub {
my ($dbh) = @_; my ($db) = @_;
return $dbh->do( $db->query(
qq{ qq{
truncate journey_stats; truncate journey_stats;
update schema_version set version = 3; update schema_version set version = 3;
@ -140,57 +127,73 @@ my @migrations = (
); );
sub setup_db { sub setup_db {
my ($dbh) = @_; my ($db) = @_;
$dbh->begin_work; my $tx = $db->begin;
if ( initialize_db($dbh) ) { eval {
$dbh->commit; initialize_db($db);
} $tx->commit;
else { };
$dbh->rollback; if ($@) {
printf( "Database initialization was not successful: %s", say "Database initialization failed: $@";
$DBI::errstr ); exit(1);
} }
} }
sub migrate_db { sub migrate_db {
my ($dbh) = @_; my ($db) = @_;
$dbh->begin_work; my $tx = $db->begin;
my $schema_version = get_schema_version($dbh);
my $schema_version = get_schema_version($db);
say "Found travelynx schema v${schema_version}"; say "Found travelynx schema v${schema_version}";
if ( $schema_version == @migrations ) { if ( $schema_version == @migrations ) {
say "Database layout is up-to-date"; say "Database layout is up-to-date";
} }
eval {
for my $i ( $schema_version .. $#migrations ) { for my $i ( $schema_version .. $#migrations ) {
printf( "Updating to v%d ...\n", $i + 1 ); printf( "Updating to v%d ...\n", $i + 1 );
if ( not $migrations[$i]($dbh) ) { $migrations[$i]($db);
say "Aborting migration; rollback to v${schema_version}"; }
$dbh->rollback; };
if ($@) {
say STDERR "Migration failed: $@";
say STDERR "Rolling back to v${schema_version}";
exit(1); exit(1);
} }
if ( get_schema_version($db) == @migrations ) {
$tx->commit;
} }
if ( get_schema_version($dbh) == @migrations ) { else {
$dbh->commit; printf STDERR (
"Database schema mismatch after migrations: Expected %d, got %d\n",
scalar @migrations,
get_schema_version($db)
);
say STDERR "Rolling back to v${schema_version}";
exit(1);
} }
} }
sub run { sub run {
my ( $self, $command ) = @_; my ( $self, $command ) = @_;
my $dbh = $self->app->dbh; my $db = $self->app->pg->db;
if ( not defined $dbh ) { #if ( not defined $dbh ) {
printf( "Can't connect to the database: %s\n", $DBI::errstr ); # printf( "Can't connect to the database: %s\n", $DBI::errstr );
exit(1); # exit(1);
} #}
if ( $command eq 'migrate' ) { if ( $command eq 'migrate' ) {
if ( not defined get_schema_version($dbh) ) { if ( not defined get_schema_version($db) ) {
setup_db($dbh); setup_db($db);
} }
migrate_db($dbh); migrate_db($db);
} }
elsif ( $command eq 'has-current-schema' ) { elsif ( $command eq 'has-current-schema' ) {
if ( get_schema_version($dbh) == @migrations ) { if ( get_schema_version($db) == @migrations ) {
say "yes"; say "yes";
} }
else { else {