=pod

=head1 NAME

DBIx::Migration - Seamless database schema up- and downgrades

=head1 SYNOPSIS

  my $m = DBIx::Migration->new(
    dsn => 'dbi:SQLite:~/Projects/myapp/db/myapp.db',
    dir => '~/Projects/myapp/db/migrations'
  );

  # Get current version from database
  my $version = $m->version;

  # Migrate database to version 1
  $m->migrate( 1 );

  # Migrate database to the latest version
  $m->migrate;

  # ~/Projects/myapp/db/migrations/schema_1_up.sql
  CREATE TABLE foo (
      id INTEGER PRIMARY KEY,
      bar TEXT
  );

  # ~/Projects/myapp/db/migrations/schema_1_down.sql
  DROP TABLE foo;

  # ~/Projects/myapp/db/migrations/schema_2_up.sql
  CREATE TABLE bar (
      id INTEGER PRIMARY KEY,
      baz TEXT
  );

  # ~/Projects/myapp/db/migrations/schema_2_down.sql
  DROP TABLE bar;

=head1 DESCRIPTION

This module provides seamless database schema up- and downgrades. The
implementation is based on migrations. A migration is a ".sql" script.
Although not mandatory the script name begins with a prefix like for example
"schema_". It follows a version number that is a positive integer. After an
underscore "_" the script name ends with the migration type that is either "up"
or "down". Migrations are stored in a directory and are applied in order to a
database. Usually the version number of the first migration is 1. The version
numbers of the other migrations have to be ascending without gaps.

During processing the content of each migration is read with the C<binmode> of
C<:raw> into a scalar. The content is split into sections using the default SQL
delimiter ";" (semicolon). Each section is executed independently. All related
sections are encapsulated in a database transaction.  If a migration embeds
stored logic containing one or more semicolons (a PostgreSQL trigger function
for example), the C<migrate()> method incorrectly splits the migration into
sections, causing an error. You can set a different delimiter to overcome this
problem. Add the C<dbix_migration_delimiter> annotation as an SQL comment to
the migration

  -- dbix_migration_delimiter: /
  ...

The annotation has to be specified in the first line. The delimiter has to be
a single printable ASCII character, excluding the space character. In the
previous example it is the "/" (slash) character.

=head1 METHODS

=over

=item $self->debug( $debug )

Enable/Disable debug messages.

=item $self->dir( $dir )

Get/Set directory that contains migrations.

=item $self->dsn( $dsn )

Get/Set dsn.

=item $self->dbh( $dbh )

Get/Set dbh.

=item $self->migrate( $version )

Migrate database to version. Returns true in case of success; otherwise false.
If called without the version argument the latest migration version will be
used.

=item $self->password( $password )

Get/Set database password.

=item $self->username( $username )

Get/Set database username.

=item $self->version

Get migration version from database. Will be undef if no migration has taken
place yet. The version is stored in the table B<dbix_migration>. The name of
this table may change in the future so don't rely on it.

=back

=head1 CAVEATS

After the C<dbh> was used for the first time changing the C<dsn>, C<password>,
or C<username> has no impact. The reason is the mutable (offering setter
methods) design of this module. Changing this will break the backwards
compatibility.

=head1 SEE ALSO

=over

=item * L<Liquibase endDelimiter|https://docs.liquibase.com/change-types/enddelimiter-sql.html>

=back

=head1 TODOS

=over

=item *

Make the C<DBIx::Migration> class immutable (get rid of setters). It is
unclear how to handle C<$dir>. This change would break the backwards
compatibility.

=item *

Implement proper logging. Printing debug information to stdout conflicts with
the stdout output of C<DBIx::Migration::CLI>.

=back

=head1 AUTHOR

Sebastian Riedel, <kraihx@gmail.com>

=head1 CONTRIBUTORS

Dan Sully, <dan+github@sully.org>

Marcus Ramberg, <marcus@nordaaker.com>

Steven Jenkin, <sjenkin@venda.com>

Sven Willenbuecher, <sven.willenbuecher@gmx.de>

=head1 COPYRIGHT

Copyright 2004-2005 Sebastian Riedel. All rights reserved.

This program is free software, you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
