NAME
    DBIx::Class::Schema::Versioned::Inline

SUMMARY
    Schema versioning for DBIx::Class with version information embedded
    inline in the schema definition.

WARNING
    This is BETA software so the usual caveats apply. This software might
    drown your kittens and perform other unusual or unexpected beahaviour.

VERSION
    Version 0.022

SYNOPSIS
     package MyApp::Schema;

     use base 'DBIx::Class::Schema::Versioned::Inline';

     our $FIRST_VERSION = '0.001';
     our $VERSION = '0.002';

     __PACKAGE__->load_namespaces;

     ...

     package MyApp::Schema::Result::Bar;

     use base 'DBIx::Class::Core';

     __PACKAGE__->table('bars');

     __PACKAGE__->add_columns(
        "bars_id" => {
            data_type => 'integer', is_auto_increment => 1
        },
        "age" => {
            data_type => "integer", is_nullable => 1
        },
        "height" => {
          data_type => "integer", is_nullable => 1,
          versioned => { since => '0.003' }
        },
        "weight" => {
          data_type => "integer", is_nullable => 1,
          versioned => { until => '0.3' }
        },
     );

     __PACKAGE__->set_primary_key('bars_id');

     __PACKAGE__->has_many(
        'foos', 'TestVersion::Schema::Result::Foo',
        'foos_id', { versioned => { until => '0.003' } },
     );

     __PACKAGE__->resultset_attributes( { versioned => { since => '0.002' } } );

     ...

     package MyApp::Schema::Result::Foo;

     use base 'DBIx::Class::Core';

     __PACKAGE__->table('foos');

     __PACKAGE__->add_columns(
        "foos_id" => {
            data_type => 'integer', is_auto_increment => 1
        },
        "age" => {
            data_type => "integer", is_nullable => 1,
            versioned => { since => '0.002' }
        },
        "height" => {
            data_type => "integer", is_nullable => 1,
            versioned => { until => '0.002' }
        },
        "width" => {
            data_type => "integer", is_nullable => 1,
            versioned => {
                since   => '0.002', renamed_from => 'height',
                changes => {
                    '0.0021' => { is_nullable => 0, default_value => 0 }
                },
            }
        },
        "bars_id" => {
            data_type => 'integer', is_foreign_key => 1, is_nullable => 0,
            versioned => { since => '0.002' }
        },
     );

     __PACKAGE__->set_primary_key('foos_id');

     __PACKAGE__->belongs_to(
        'bar',
        'TestVersion::Schema::Result::Bar',
        'bars_id',
        { versioned => { since => '0.002' } },
     );

     __PACKAGE__->resultset_attributes( { versioned => { until => '0.003' } } );

     ...

     package MyApp::Schema::Upgrade;

     use base 'DBIx::Class::Schema::Versioned::Inline::Upgrade';
     use DBIx::Class::Schema::Versioned::Inline::Upgrade qw/before after/;

     before '0.3.3' => sub {
         my $schema = shift;
         $schema->resultset('Foo')->update({ bar => '' });
     };

     after '0.3.3' => sub {
         my $schema = shift;
         # do something else
     };

DESCRIPTION
    This module extends DBIx::Class::Schema::Versioned using simple 'since'
    and 'until' tokens within result classes to specify the schema version
    at which classes and columns were introduced or removed. Column
    since/until definitions are included as part of 'versioned' info in
    add_column(s).

  since
    When a class is added to a schema at a specific schema version version
    then a 'since' attribute must be added to the class which returns the
    version at which the class was added. For example:

     __PACKAGE__->resultset_attributes({ versioned => { since => '0.002' }});

    It is not necessary to add this to the initial version of a class since
    any class without this atribute is assumed to have existed for ever.

    Using 'since' in a column or relationship definition denotes the version
    at which the column/relation was added. For example:

     __PACKAGE__->add_column(
        "age" => {
            data_type => "integer", is_nullable => 1,
            versioned => { since => '0.002' }
        }
     );

    For changes to column_info such as a change of data_type see "changes".

    Note: if the Result containing the column includes a class-level "since"
    then there is no need to add "since" markers for columns created at the
    same version.

    Relationships are handled in the same way as columns:

     __PACKAGE__->belongs_to(
        'bar',
        'MyApp::Schema::Result::Bar',
        'bars_id',
        { versioned => { since => '0.002' } },
     );

  until
    When used as a class attribute this should be the schema version at
    which the class is to be removed. The underlying database table will be
    removed when the schema is upgraded to this version. Example
    definitions:

     __PACKAGE__->resultset_attributes({ versioned => { until => '0.7' }});

     __PACKAGE__->add_column(
        "age" => {
            data_type => "integer", is_nullable => 1,
            versioned => { until => '0.5' }
        }
     );

    Using 'until' in a column or relationship definition will cause removal
    of the column/relation from the table when the schema is upgraded to
    this version.

  renamed_from
    This is always used alongside 'since' in the renamed class/column and
    there must also be a corresponding 'until' on the old class/column.

    NOTE: when renaming a class the 'renamed_from' value is the table name
    of the old class and NOT the class name.

    For example when renaming a class:

     package MyApp::Schema::Result::Foo;

     __PACKAGE__->table('foos');
     __PACKAGE__->resultset_attributes({ versioned => { until => '0.5 }});

     package MyApp::Schema::Result::Fooey;

     __PACKAGE__->table('fooeys');
     __PACKAGE__->resultset_attributes({
        versioned => { since => '0.5, renamed_from => 'foos' }
     });

    And when renaming a column:

     __PACKAGE__->add_columns(
        "height" => {
            data_type => "integer",
            versioned => { until => '0.002' }
        },
        "width" => {
            data_type => "integer", is_nullable => 0,
            versioned => { since => '0.002', renamed_from => 'height' }
        },
     );

    As can been seen in the example it is possible to modify column
    definitions at the same time as a rename but care should be taken to
    ensure that any data modification (such as ensuring there are no longer
    null values when is_nullable => 0 is introduced) must be handled via
    "Upgrade.pm".

    NOTE: if columns are renamed at the same version that a class/table is
    renamed (for example a renamed PK) then you MUST also add "renamed_from"
    to the column as otherwise data from that column will be lost. In this
    special situation adding "since" to the column is not required.

  changes
    Column definition changes are handled using the "changes" token. A
    hashref is created for each version where the column definition changes
    which details the new column definition in effect from that change
    revision. For example:

     __PACKAGE__->add_columns(
        "item_weight",
        {
            data_type => "integer", is_nullable => 1, default_value => 4,
            versioned => { until => '0.001 },
        },
        "weight",
        {
            data_type => "integer", is_nullable => 1,
            versioned => {
                since        => '0.002',
                renamed_from => 'item_weight',
                changes => {
                    '0.4' => {
                        data_type   => "numeric",
                        size        => [10,2],
                        is_nullable => 1,
                    }
                    '0.401' => {
                        data_type   => "numeric",
                        size        => [10,2],
                        is_nullable => 0,
                        default_value => "0.0",
                    }
                }
            }
        }
     );

    Note: the initial column definition should never be changed since that
    is the definition to be used from when the column is first created until
    the first change is effected.

  Upgrade.pm
    For details on how to apply data modifications that might be required
    during an upgrade see DBIx::Class::Schema::Versioned::Inline::Upgrade.

METHODS
    Many methods are inherited or overloaded from
    DBIx::Class::Schema::Versioned.

  connection
    Overloaded method. This checks the DBIC schema version against the DB
    version and uses the DB version if it exists or the schema version if
    the database is currently unversioned.

  deploy
    Inherited method. Same as "deploy" in DBIx::Class::Schema but also calls
    "install".

  install
    Inherited method. Call this to initialise a previously unversioned
    database.

  schema_first_version
    Returns the current schema class' $FIRST_VERSION in a normalised way.

    If the schema does not define $FIRST_VERSION then all resultsets must
    specify the version at which they were added using "since".

  ordered_schema_versions
    Overloaded method. Returns an ordered list of schema versions. This is
    then used to produce a set of steps to upgrade through to achieve the
    required schema version.

  upgrade
    Inherited method. Call this to attempt to upgrade your database from the
    version it is at to the version this DBIC schema is at. If they are the
    same it does nothing.

  upgrade_single_step
    Arguments: db_version - the version currently within the db
    Arguments: target_version - the version to upgrade to

    Overloaded method. Call this to attempt to upgrade your database from
    the *db_version* to the *target_version*. If they are the same it does
    nothing.

    All upgrade operations within this step are performed inside a single
    transaction so either all succeed or all fail. If successful the
    dbix_class_schema_versions table is updated with the *target_version*.

    This method may be called repeatedly by the "upgrade" method to upgrade
    through a series of updates.

  versioned_schema
    Arguments: version - the schema version we want to deploy

    Parse schema and remove classes, columns and relationships that are not
    valid for the requested version.

CANDY
    See DBIx::Class::Schema::Versioned::Inline::Candy.

CAVEATS
    Please anticipate API changes in this early state of development.

TODO
    *   Sequence renaming in Pg, MySQL (maybe?). Not required for SQLite.

    *   Index renaming for auto-created indexes for UCs, etc - Pg + others?

    *   Downgrades

    *   Schema validation

AUTHOR
    Peter Mottram (SysPete), "peter@sysnix.com"

CONTRIBUTORS
    Slaven Rezić (eserte) Stefan Hornburg (racke) Peter Rabbitson
    (ribasushi)

BUGS
    This is BETA software so bugs and missing features are expected.

    Please report any bugs or feature requests via the project's GitHub
    issue tracker:

    <https://github.com/Sysnix/dbix-class-schema-versioned-jiftyesque/issues
    >

    I will be notified, and then you'll automatically be notified of
    progress on your bug as I make changes.

SUPPORT
    You can find documentation for this module with the perldoc command.

        perldoc DBIx::Class::Schema::Versioned::Inline

    You can also look for information at:

    *   GitHub repository

        <https://github.com/Sysnix/dbix-class-schema-versioned-inline>

    *   AnnoCPAN: Annotated CPAN documentation

        <http://annocpan.org/dist/DBIx-Class-Schema-Versioned-Inline>

    *   CPAN Ratings

        <http://cpanratings.perl.org/d/DBIx-Class-Schema-Versioned-Inline>

    *   Search CPAN

        <http://search.cpan.org/dist/DBIx-Class-Schema-Versioned-Inline/>

ACKNOWLEDGEMENTS
    Thanks to Best Practical Solutions for the Jifty framework and
    Jifty::DBI which inspired this distribution. Many thanks to all of the
    DBIx::Class and SQL::Translator developers for those excellent
    distributions and especially to ribasushi and ilmari for all of their
    help and input.

LICENSE AND COPYRIGHT
    Copyright 2014 Peter Mottram (SysPete).

    This program is free software; you can redistribute it and/or modify it
    under the terms of either: the GNU General Public License as published
    by the Free Software Foundation; or the Artistic License.

    See http://dev.perl.org/licenses/ for more information.

