The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

DBIx::Migration::Classes - Class-based migration for relational databases.

SYNOPSIS

Migration program:

  use DBIx::Migration::Classes;
  my $migrator = DBIx::Migration::Classes->new(namespaces => ['MyApp::Changes'], dbname => 'myapp');
  $migrator->migrate('HEAD');

To create a new migration, just create a new class in one of the namespaces that you tell the migrator to look in, e.g.:

libpath/MyApp/Changes/MyChangeTwo.pm:

  package MyApp::Changes::MyChangeTwo;
  use base qw(DBIx::Migration::Classes::Change);

  sub after { "MyApp::Changes::MyChangeOne" }
  sub perform {
    my ($self) = @_;
    $self->add_column('new_column', 'varchar(42)', -null => 1, -primary_key => 1);
    $self->create_table('new_table');
    return 1;
  }
  1;

DESCRIPTION

When writing database powered applications it is often nessessary to adapt the database structure, e.g. add a table, change a column type etc.

Suppose a developer works on a feature, creates a new database field, and from then on the codebase relies on that column to exist. His/her fellow programmers get his revised codebase, but they still have an old database, which is lacking this very column.

This module makes it possible to encapsulate a bunch of (structural) changes to a database into a "changeclass". These changeclasses are collected by this module and applied to a database. The database can now be seen as having an attached "version" and can be rolled back and forth to any desired state (regarding the structure, but hopefully in the future the data as well).

Some definitions

Change

A change is a simple transformation of a database, e.g. "add column x of type y" or "drop table z".

Unchange

An unchange (pardon the word) is the reverse transformation to a given change. DBIx::Migration::Classes will automatically create an unchange for any given change, so anything that can be changed in the database can be reversed. Details on what kind of changes are possible, see below.

Changeclass

A changeclass encapsulates a bunch of ordered changes under a globally unique name. A changeclass contains also the name of the changeclass that is coming directly before itself. Given a bunch of changeclasses, it is easy to bring them into an order that represents the "history" (and "future") of the database. Each changeclass is a subclass of DBIx::Migration::Classes::Change.

DBVersion (Database Version)

A dbversion is the name of the last applied changeclass in a database. This information is stored directly inside the database in a meta table. A database can only have one dbversion at a given time. The special dbversion "NONE" marks the point when no changeclasses have been applied.

Migration

A migration is the application of all the changes from an ordered list of changeclasses to a database. A migration always starts at the current dbversion of the database and ends at another given dbversion.

Features of DBIx::Migration::Classes

Having defined all the words in the previous section, we can now easily define the features of this module. DBIx::Migration::Classes lets the programmer...

  • ...define changeclasses with changes.

  • ...migrate a database from dbversion A to dbversion B.

  • ...do all this either from Perl or using a commandline utility (useful in build scripts or post-update hooks in version control systems).

new( %options )

This creates a new migrator instance. The following options are available:

  • namespaces => Arrayref of Perl namespaces (mandatory)

    The namespaces given via the "namespaces"-option are used to find all changes that exists. Each change is a subclass of DBIx::Migration::Classes::Change, see below.

    dbname => Database name (mandatory)
    dbuser => Database username (optional, defaults to "root")
    dbpassword => Database password (optional, defaults to "")
    dbhost => Database host (optional, defaults to "localhost")
    dbengine => Database engine (optional, defaults to "mysql")

migrate( "changeclass classname" )

This method migrates the database from its current state to the given changeclass (including).

The special string "NONE" defines the state when NO changeclass is applied. Roll back the database to its initial state:

  $migrator->migrate('NONE');

The special string "HEAD" defines the state when ALL available changeclasses are applied. Migrate the database to the most current available state:

  $migrator->migrate('HEAD');

If anything goes wrong, the method will return 0, else 1. In case of an error, the error message can be retrieved via errstr().

  $migrator->migrate('HEAD')
    or die "failed to migrate: ".$migrator->errstr()."\n";

errstr()

This method returns the error message of the last error occured, or the empty string in case of no error.

  print "last error: ".$migrator->errstr()."\n";

state()

This method returns the name of the change that was executed last on the given DBI database handle. The change name is the package name of the DBIx::Migration::Classes::Change based change class.

  print "last applied changeclass in db: ".$migrator->state()."\n";

changes()

This method returns a list of changes that were executed on the given DBI database handle in the order they were executed.

  my @changes = $migrator->changes();
  print "applied changes: ".join(', ', @changes)."\n";

EXPORT

None by default.

SEE ALSO

None.

AUTHOR

Tom Kirchner, <tom@tomkirchner.com>

COPYRIGHT AND LICENSE

Copyright (C) 2011 by Tom Kirchner

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.9 or, at your option, any later version of Perl 5 you may have available.