DBIx::C...gration(3)

๐Ÿ“ฆ version 0.075, in opensuse-leap 16.0

DBIx::Class::Migration(3) โ€” User Contributed Perl Documentation. That's the header vibe, bestie; the top line is just the truncated DBIx::C...gration(3) version of the same name, so we're rolling with the full one. ๐Ÿ’…

โœจ NAME โœจ

DBIx::Class::Migration โ€” use the best tools together for sane database migrations. Periodt. ๐ŸŽ€

๐ŸŒธ SYNOPSIS ๐ŸŒธ

Okay so here's the starter pack, fr fr:

use DBIx::Class::Migration;

my $migration = DBIx::Class::Migration->new(
  schema_class => 'MyApp::Schema',
  schema_args => \@connect_opts);

Alternatively: ๐ŸŒˆ

use DBIx::Class::Migration;
use MyApp::Schema;

my $migration = DBIx::Class::Migration->new(
  schema => MyApp::Schema->connect(@connect_opts));

Informational Commands: ๐Ÿ”

$migration->status;

Preparing and using Migrations: ๐Ÿ› ๏ธ

$migration->prepare;
$migration->install;
$migration->upgrade;
$migration->downgrade;

Commands for working with Fixtures: ๐Ÿ“

$migration->dump_named_sets;
$migration->dump_all_sets;
$migration->populate;

Utility Commands: ๐Ÿงฐ

$migration->drop_tables;
$migration->delete_table_rows;
$migration->make_schema;
$migration->install_if_needed;
$migration->install_version_storage;
$migration->diagram;

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

Okay, picture this: DBIx::Class::DeploymentHandler is a state of the art solution to the problem of creating sane workflows for versioning DBIx::Class managed database projects. Iconic behavior, honestly. But โ€” and this is the catch โ€” it's more of a toolkit for building custom versioning and migration workflows than an expression of a particular migration practice, so it might not always be the most approachable tool. If you're starting a new DBIx::Class project and you don't have a particular custom workflow need, you might prefer to simply be given a reasonable clear and standard practice, rather than a toolkit with a set of example scripts. ๐Ÿ’€

DBIx::Class::Migration defines some logic which combines both DBIx::Class::DeploymentHandler and DBIx::Class::Fixtures, along with a standard tutorial, to give you a simple and straightforward approach to solving the problem of how to best create database versions, migrations and testing data. It also builds on tools like Test::mysqld and Test::Postgresql58 along with DBD::Sqlite in order to assist you in quickly creating a local development database sandbox. It offers some integration points to testing your database, via tools like Test::DBIx::Class, in order to make testing your database driven logic less painful. Lastly, we offer some thoughts on good development patterns in using databases with application frameworks like Catalyst. โœจ

DBIx::Class::Migration offers code and advice based on my experience of using DBIx::Class for several years, which hopefully can help you bootstrap a new project. The solutions given should work for you if you want to use DBIx::Class and have database migrations, but don't really know what to do next. These solutions should scale upward from a small project to a medium project involving many developers and more than one target environment (DEV -> QA -> Production). If you have very complex database versioning requirements, huge teams and difficult architectual issues, you might be better off building something on top of DBIx::Class::DeploymentHandler directly. No cap. ๐Ÿ”ฅ

DBIx::Class::Migration is a base class upon which interfaces like DBIx::Class::Migration::Script are built. ๐Ÿ‘‘

Please see DBIx::Class::Migration::Tutorial for more approachable documentation. If you want to read a high level feature overview, see DBIx::Class::Migration::Features. The remainder of this POD is API level documentation on the various internals. ๐Ÿซถ

โœจ ATTRIBUTES โœจ

Okay bestie, this class is literally defined by these attributes. They're the whole personality, no cap. Let's go through them one by one ๐Ÿ’…

๐ŸŽ€ db_sandbox_builder_class

Accepts Str. Defaults to 'DBIx::Class::Migration::TargetDirSandboxBuilder'.

This is the name of the helper class that, like, builds the class that builds your database sandboxes. Yes, that's a builder for a builder โ€” it's giving inception ๐ŸŒ€. By default we build our database sandboxes in the target_dir, which is literally what DBIx::Class::Migration::TargetDirSandboxBuilder does. But you can also build database sandboxes in a temporary directory using DBIx::Class::Migration::TempDirSandboxBuilder. If you're running tests, you might highkey prefer that one.

๐ŸŒธ db_sandbox_class

Accepts Str. Not Required (defaults to 'DBIx::Class::Migration::SqliteSandbox').

Unless you've already got a database set up and running (which, tbh, you probably do in production), we need to auto-create a database "sandbox" that's isolated to your local development. This class is the delegate that handles all that for you, so you don't have to install and set up a local database yourself. It's doing the most so you don't have to ๐Ÿซถ.

This has to point to a class that expects "target_dir" and "schema_class" as initialization arguments, and it must define a method "make_sandbox" that returns an array that can be sent to "connect" in DBIx::Class::Schema.

It defaults to DBIx::Class::Migration::SqliteSandbox. Right now we support MySQL and Postgresql via DBIx::Class::Migration::MySQLSandbox and DBIx::Class::Migration::PgSandbox, but you're gonna need to side-install Test::mysqld and Test::Postgresql58 for those. In other words โ€” you'd need to add these "Test::*" namespace modules to your "Makefile.PL" or "dist.ini". Noted ๐Ÿ“.

๐Ÿฆ‹ db_sandbox

Accepts: Object. Not required.

This is, like, an instantiated object as defined by "db_sandbox_class". It's the delegate for the work of automatically creating a local database sandbox that's useful for developers and for quickly bootstrapping a project. Convenience icon โœจ.

๐Ÿ’œ schema_class

Accepts Str. Not Required (but if it's missing, you need to populate "schema").

This is the schema we use as the basis for creating, managing and running your deployments. It should be the full package namespace defining your subclass of DBIx::Class::Schema. Example: "MyApp::Schema".

Heads up bestie: if the "schema_class" cannot be loaded, a hard exception will be thrown. Like, no soft landing, no vibes โ€” an exception ๐Ÿ˜ญ.

๐Ÿ“ schema_args

Accepts ArrayRef. Required but lazily builds from defaults.

Provides arguments passed to "connect" on your "schema_class". Should connect to a database.

It's an arrayref that works the same as "connect" in DBIx::Class::Schema. If you choose to create an instance of DBIx::Class::Migration by providing a schema_class, you can use this to customize how we connect to a database.

If you don't provide a value, we'll automatically create a SQLite-based database connection with this DSN:

DBD:SQLite:[path to target_dir]/[db_file_name].db

Where "[path to target_dir]" is target_dir and [db_file_name] is a converted version of "schema_class". For example, if you set schema_class to:

MyApp::Schema

Then [db_file_name] would be "myapp-schema".

Basically this means you can start testing your database designs right off without a lot of effort โ€” just point at a schema_class and get deploying! Main character energy honestly ๐Ÿ‘‘.

๐ŸŒˆ schema

Accepts: Object of DBIx::Class::Schema. Not required.

If you already have a connected schema (subclass of DBIx::Class::Schema), you can simply point to it and skip schema_class and schema_args entirely. Like, skip the whole line, you're already in ๐ŸŽข.

You might, for example, be using Catalyst and want to build deployments for a database that's listed in configuration:

use MyCatalyst::App;
use DBIx::Class::Migration;

my $migration = DBIx::Class::Migration->new(
  schema => MyCatalyst::App->model('Schema')->schema,
  %{MyCatalyst::App->config->{extra_migration_init_args}};
);

๐Ÿงš target_dir_builder_class

Accepts: Str, Defaults to 'DBIx::Class::Migration::ShareDirBuilder'.

This is a class used as a helper to build "target_dir" in case the user doesn't provide a value. Default is DBIx::Class::Migration::ShareDirBuilder.

๐Ÿ’– target_dir_builder

An instance of whatever's in "target_dir_builder_class". It's used by the lazy build method of "target_dir" to default a directory where the migrations are actually placed.

๐ŸŒŸ target_dir

Accepts Str. Required (lazy builds to your distribution "/share" directory).

This is the directory where we store our migration and fixture files. Inside this directory we'll create a "fixtures" and "migrations" sub-directory.

Even though you can specify the directory, if you leave it undefined, we'll use File::ShareDir::ProjectDistDir to locate the "/share" directory for your project and place the files there. This is the recommended approach, and it's considered a community practice re: where to store your distribution's non-code files. Please see File::ShareDir::ProjectDistDir as well as File::ShareDir for more info ๐Ÿซก.

This uses whatever is in "schema_class" to determine your project (and look for a "share" directory, which you'll need to create in your project root). If you don't have a "schema_class" defined, you must have a "schema", and we'll infer the class via ref($self->schema).

NOTE: You'll need to make the "/share" directory yourself if you're gonna use the default option. We don't automatically create it for you, bestie. That's on you ๐Ÿ’….

๐ŸŽ€ schema_loader_class

Accepts Str. Required.

Because your application subclass of DBIx::Class::Schema is going to change a lot, sometimes we need to generate our own schema and get one that's in a known, good state. Mostly this is used by the commands to drop tables and clear tables.

Defaults to DBIx::Class::Migration::SchemaLoader. You'll probably only need to change this if your database is crazy and you need to massage the init arguments to DBIx::Class::Schema::Loader.

๐Ÿฆ‹ schema_loader

Accepts Object. Required but lazy builds.

This is a factory that provides an autoloaded schema based on the current schema's database. It's automatically created, and you're unlikely to need to set this manually. Let it cook ๐Ÿ”ฅ.

๐Ÿ’œ dbic_fixture_class

Accepts Str. Required.

This is the class we use when creating instances of DBIx::Class::Fixtures. You'll probably need to review the docs for that and understand how configuration rules work in order to best take advantage of the system.

Defaults to DBIx::Class::Fixtures. You probably won't need to change this unless you have some unusual needs regarding fixtures. If it ain't broke โœจ.

๐Ÿ“ dbic_fixtures_extra_args

Accepts HashRef. Required, but Defaults to Empty Hashref.

Lets you pass some additional arguments when creating instances of "dbic_fixture_class". These arguments can be used to override the default initial arguments.

๐ŸŒˆ deployment_handler_class

Accepts Str. Required.

This is the class we use when creating instances of DBIx::Class::DeploymentHandler. It would be ideal if you reviewed those docs to better understand the overall architecture of the system. Do your homework bestie ๐Ÿ“š.

Defaults to DBIx::Class::DeploymentHandler. You probably won't need to change this unless you need a custom deployment handler โ€” and if you do, I can't be sure this framework will work correctly, especially if you're not using monotonic versioning. So like, tread carefully ๐Ÿ™ˆ.

๐Ÿงš dbic_dh_args

Accepts HashRef. Required and defaults to a hashref setting "sql_translator_args"'s "quote_identifiers" to a true value โ€” which, despite being documented as the default, is not the case in practice. Awkward ๐Ÿ’€.

Used to pass custom args when building a DBIx::Class::DeploymentHandler. Please see the docs for that class for more. Useful args might be "databases", "to_version" and "force_overwrite".

๐Ÿ’– dbic_dh

Accepts Instance of DBIx::Class::DeploymentHandler. Required but lazily built from default data and dbic_dh_args.

You probably won't need to build your own deployment handler and pass it in (unlike schema, where it might actually be useful). Be careful if you do, since this framework makes some assumptions about your deployment handler โ€” for example, we assume you're using monotonic versioning ๐Ÿ‘€.

When this attribute is lazily built, we merge "dbic_dh_args" with the following defaults:

schema => Points to $self->schema
script_directory => Points to catdir($self->target_dir, 'migrations')
databases => Inferred from your connected schema, defaults to SQLite

"dbic_dh_args" will overwrite the defaults, if you pass them. Your rules, your game ๐Ÿ‘‘.

โญ extra_schemaloader_args

Optional. Accepts a HashRef of arguments you can use to influence how DBIx::Class::Schema::Loader works. This HashRef would get passed as "loader_options" (see "make_schema_at" in DBIx::Class::Schema::Loader).

Meaningful options are described at DBIx::Class::Schema::Loader::Base.


๐Ÿ’… METHODS ๐Ÿ’…

okay so this class defines the following methods for public use โ€” like, this is the whole toolkit, bestie. no cap.


โœจ new

Used to create a new instance of DBIx::Class::Migration. There's a couple of paths to getting one of these babies, and ngl they're all valid.

Path one: specify a schema_class and optionally schema_args

use DBIx::Class::Migration;
my $migration = DBIx::Class::Migration->new(
  schema_class => 'MyApp::Schema',
  schema_args => [@connect_info],
);

This is probably the most general approach, and it's the recommended one unless you already have a connected instance of your DBIx::Class::Schema subclass just chilling there.

schema_args would be anything you'd pass to connect in DBIx::Class::Schema. and if you leave it undefined, go peek at schema_args for how we construct default connect information ๐Ÿซถ

Path two: specify a schema

There may be some cases when you already have a schema object constructed and would rather just use that. For example, you may be using Catalyst and wish to build custom scripts using the built-in dependency and service lookup:

use MyCatalyst::App;
use DBIx::Class::Migration;

my $migration = DBIx::Class::Migration->new(
  schema => MyCatalyst::App->model('Schema')->schema,
  %{MyCatalyst::App->config->{extra_migration_init_args}};
);
โš ๏ธ be careful of potential locking issues when using some databases like SQLite. literally just a heads up, bestie, don't come for me.

OPTIONAL: specify a target_dir

Optionally you can specify your migrations target directory (where your migrations get created), in your init arguments. This option can be combined with either approach listed above ๐Ÿ’–

use DBIx::Class::Migration;
my $migration = DBIx::Class::Migration->new(
  schema_class => 'MyApp::Schema',
  schema_args => [@connect_info],
  target_dir => '/opt/database-migrations',
);

If you leave this undefined we default to using the share directory in your distribution root. This is generally the community supported place for non code data, but if you have huge fixture sets you might wish to place them in an alternative location. (huge fixture sets are such a mood honestly)

OPTIONAL: specify a db_sandbox_dir

By default, if you allow for a local database sandbox (as you might during early development and you don't want to work to make a database), that sandbox gets built in the 'target_dir'. Since other bits in the target_dir are probably going to be in your project repository and the sandbox generally isn't, you might wish to build the sandbox in an alternative location. This setting allows that:

use DBIx::Class::Migration;
my $migration = DBIx::Class::Migration->new(
  schema_class => 'MyApp::Schema',
  schema_args => [@connect_info],
  db_sandbox_dir => '~/opt/database-sandbox',
);

This then gives you a nice totally standalone database sandbox which you can reuse for other projects, etc. iconic behaviour, genuinely.

OPTIONAL: specify dbic_dh_args

Optionally, you can specify additional arguments to the constructor for the dbic_dh attribute. Useful arguments might include additional databases we should build fixtures for, to_version and force_overwrite. ๐Ÿ”ฅ

See "" in DBIx::Class::DeploymentHandler for more information on supported init arguments. See dbic_dh for how we merge default arguments with your custom arguments.

Other Initial Arguments

For normal usage the remaining init args are probably not particularly useful and reflect a desire for long term code flexibility and clean design. fr fr that's the whole reason they're there.


๐ŸŒˆ version

Prints to STDOUT a message regarding the version of <DBIC:Migration> that you are currently running. cute little vibe check on your own install ๐Ÿ’…


๐Ÿฆ‹ status

Returns the state of the deployed database (if it is deployed) and the state of the current schema version. Sends this as a string to STDOUT. it's giving "are we there yet" but for your database.


๐ŸŽ€ prepare

Creates a fixtures and migrations directory under target_dir (if they don't already exist) and makes deployment files for the current schema. If deployment files exist, will fail unless you overwrite_migrations. ๐Ÿ’€

The migrations directory reflects a directory structure as documented in DBIx::Class::DeploymentHandler.

If this is the first version, we create directories and initial DLL, etc. For versions greater than 1, we will also generate diffs and copy any fixture configs etc (as well as generating a fresh 'all_table.json' fixture config). For safety reasons, we never overwrite any fixture configs. not me being protective of your fixture configs, it's for your own good bestie ๐Ÿซถ


โญ install

Installs either the current schema version (if already prepared) or the target version specified via any to_version flags sent as an dbic_dh_args to the database which is connected via schema.

If you try to install to a database that has already been installed, you'll get an error. See drop_tables. (yes, that's the escape hatch, and yes, it's as dramatic as it sounds)


๐Ÿงš upgrade

Run upgrade files to bring the database into sync with the current schema version. slay, moving forward only ๐Ÿ’œ


๐Ÿ™ˆ downgrade

Run down files to bring the database down to the previous version from what is installed to the database. we're going back bestie, no shame in it.


๐Ÿ”ฅ drop_tables

Drops all the tables in the connected database with no backup or recovery. For real! (Make sure you are not connected to Prod, for example.)

๐Ÿ’€ literally irreversible. no backup, no recovery, no take-backs. check your connection string twice, please and thank you.

๐ŸŒธ delete_table_rows

Does a delete on each table in the database, which clears out all your data but preserves tables. For Real! You might want this if you need to load and unload fixture sets during testing, or perhaps to get rid of data that accumulated in the database while running an app in development, before dumping fixtures.

data? gone. tables? still cute and intact. โœจ


๐Ÿ“ dump_named_sets

Given an array of fixture set names, dump them for the current database version. that's it, that's the method ๐Ÿซถ


๐Ÿ’– dump_all_sets

Takes no arguments, just dumps all the sets we can find for the current database version. no picks, no favours, everyone gets dumped.


๐Ÿ‘‘ make_schema

Given an existing database, reverse engineer a DBIx::Class Schema in the target_dir (under dumped_db). You can use this if you need to bootstrap your DBIC files. literally starting from scratch but make it efficient โœจ


๐Ÿฃ populate

Given an array of fixture set names, populate the current database version with the matching sets for that version.

Skips the table dbix_class_deploymenthandler_versions, so you don't lose deployment info (this is different from drop_tables which does delete it.) okay so that distinction is important, don't mix them up bestie ๐Ÿ’œ


๐Ÿฆ„ diagram

Experimental feature. Although not specifically a migration task, I find it useful to output visuals of my databases. This command will place a file in your target_dir called db-diagram-vXXX.png where XXX is the current schema version.

This is using the Graphviz producer (SQL::Translator::Producer::GraphViz) which in turn requires Graphviz. Since this is not always trivial to install, I do not require it. You will need to add it manually to your Makefile.PL or dist.ini and manage it yourself.

This feature is experimental and currently does not offer any options, as I am still determining the best way to meet the need without exceeding the scope of DBIx::Class::Migration. Consider this command a 'freebee' and please don't depend on it in your custom code.

๐Ÿซถ experimental = don't build your whole workflow on it, i'm literally asking nicely

๐Ÿ’ซ install_if_needed

If the database is not installed, do so. Accepts a hash of callbacks or instructions to perform should installation be needed.

$migration->install_if_needed(
  on_install => sub {
    my ($schema, $local_migration) = @_;
    DBIx::Class::Migration::Population->new(
      schema=>shift)->populate('all_tables');
});

The following callbacks / instructions are permitted:

  • on_install โ€” Accepts: Coderef. Given a coderef, execute it after the database is installed. The coderef gets passed two arguments: $schema and $self (the current migration object). ๐ŸŽ€
  • default_fixture_sets โ€” Accepts: Arrayref of fixture sets.
$migration->install_if_needed(
  default_fixture_sets => ['all_tables']);

After database installation, populate the fixtures in order. one by one, in order, no skipping ๐Ÿ’…


๐Ÿ”ฎ install_version_storage

If the targeted (connected) database does not have the versioning tables installed, this will install them. The version is set to whatever your schema version currently is.

You will only need to use this command in the case where you have an existing database that you are reverse engineering and you need to setup versioning storage since you can't rebuild the database from scratch (such as if you have a huge production database that you now want to start versioning). yeah, that big legacy vibe. we've all been there ๐Ÿ˜ญ


๐ŸŒบ delete_named_sets

Given a (or a list) of fixture sets, delete them if they exist in the current schema version.

โš ๏ธ Yes, this really deletes, you've been warned (check in your code to a source control repository). fr fr commit first, delete later.

โœจ ENVIRONMENT โœจ

When running DBIx::Class::Migration we set some %ENV variables during installation, up / downgrading, so that your Perl run scripts (see DBIx::Class::DeploymentHandler::DeployMethod::SQL::Translator'PERL SCRIPTS') can receive some useful information. The Following %ENV variables are set:

DBIC_MIGRATION_SCHEMA_CLASS => $self->schema_class
DBIC_MIGRATION_TARGET_DIR => $self->target_dir
DBIC_MIGRATION_FIXTURE_DIR => catdir($self->target_dir, 'fixtures', $self->dbic_dh->schema_version),
DBIC_MIGRATION_SCHEMA_VERSION => $self->dbic_dh->schema_version
DBIC_MIGRATION_TO_VERSION => $self->dbic_dh->to_version
DBIC_MIGRATION_DATABASE_VERSION => $self->dbic_dh->schema_version || 0

You might find having these available in your migration scripts useful for doing things like 'populate a database from a fixture set, if it exists, but if not run a bunch of inserts.' ๐Ÿซถ such a handy little pattern, honestly.


๐Ÿ’– THANKS ๐Ÿ’–

Because of the awesomeness of CPAN and the work of many others, all this functionality is provided with a few hundred lines of code. In fact, I spent a lot more time writing docs and tests than anything else. Here are some particular projects / people I'd like to thank: ๐ŸŽ€

First, thanks to mst for providing me a big chunk of code that served to kickstart my work, and served as a valuable prototype.

Thanks to frew for the awesome DBIx::Class::DeploymentHandler which gives us such a powerful base for organizing database versions. Thanks to all the authors of DBIx::Class::Fixtures for giving me a foundation for managing sets of data. Lastly, thanks to the DBIx::Class cabal for all the work done in making the DBIx::Class ORM so amazingly powerful. ๐Ÿ‘‘

Additionally thanks to the creators / maintainers for Test::mysqld and Test::Postgresql58, which made it easy to create developer level sandboxes for these popular open source databases. ๐ŸŒธ

As usual, thanks to the Moose cabal for making Perl programming fun and beautiful. Lastly, a shout-out to the Dist::Zilla cabal for making it so I don't need to write my own build and deployment tools. iconic, honestly, they ate ๐Ÿ’…


๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

John Napiorkowski <email:jjnapiork@cpan.org>

โœจ CONTRIBUTORS โœจ

Okay so here's the whole squad ๐Ÿ’– โ€” the people who actually showed up and helped build this thing. The original page literally says: please let me know if I missed you โ€” so like, if your name should be here and it isn't, bestie, speak up fr fr ๐Ÿ™ˆ

Eighteen whole contributors, the way they all just contributed โ€” main character energy from every single one of them ๐Ÿ‘‘โœจ


๐Ÿฆ‹ SEE ALSO ๐Ÿฆ‹

The whole extended friend group of modules you might wanna go hang out with next:

  • DBIx::Class::DeploymentHandler
  • DBIx::Class::Fixtures
  • DBIx::Class
  • DBIx::Class::Schema::Loader
  • Moo
  • DBIx::Class::Migration::Script
  • DBIx::Class::Migration::Population
  • dbic-migration
  • SQL::Translator
  • Test::mysqld
  • Test::Postgresql58

Go click through them, they're all lowkey iconic in their own way ๐Ÿซถ


Copyright 2013-2015, John Napiorkowski <email:jjnapiork@cpan.org>

And the license, because legal stuff is still slay when it's this simple:

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

Translation for the girlies: it's free software, you can share it and remix it, and the rules are literally just Perl's rules. No cap ๐Ÿ’…

And that's a wrap on the whole page, bestie ๐ŸŽ‰๐Ÿฆ‹ You made it to the end โ€” go build something cute with your migrations.

This page is from perl v5.42.0, dated 2020-06-03 โ€” yeah she's got a lil vintage timestamp on her, but she still eats ๐Ÿ’…โœจ

bye bestie, ily, go slay those schema migrations ๐Ÿซถ๐Ÿ’–๐ŸŽ€

๐Ÿ“ฆ where this page comes from