DBIx::C...l::Intro(3)

✨ NAME ✨

DBIx::Class::DeploymentHandler::Manual::Intro β€” literally the intro to DBIx::Class::DeploymentHandler, bestie πŸ’–


πŸ’… Why is DBIx::Class::DeploymentHandler worth using?

okay so the most obvious reasons? it can run multiple SQL scripts AND Perl scripts, which is a whole vibe that DBIx::Class::Schema::Versioned simply cannot give you, because that one only allows a single SQL script. πŸ™ˆ

also it's extremely extensible, and it was a golden opportunity for a break from backwards compatibility, so some genuinely regrettable decisions just… got avoided. slay πŸŽ€


🌸 Sample database

Follow DBIx::Class::Manual::Intro except for the parts setting up the database. Once you're done, you should have these files:

MyDatabase/
|-- Main
|   |-- Result
|   |   |-- Artist.pm
|   |   |-- Cd.pm
|   |   `-- Track.pm
|   `-- ResultSet
`-- Main.pm

Add a line like this in your MyDatabase::Main file:

our $VERSION = 1;

or, if you're on a newer Perl, you can use the prettier syntax:

package MyDatabase::Main 1;

So by default, DBIx::Class::DeploymentHandler only uses integers for versions, which makes versioning so much simpler for figuring out what version is next (or previous). periodt. ✨

But heads up: if you're using decimal numbers for versioning, you'll need to create a separate DeploymentHandler class, as per DBIx::Class::DeploymentHandler::Cookbook::CustomResultSource, and set the VersionHandler class_name from Monotonic to ExplicitVersions or DatabaseToSchemaVersions β€” because those two handle version numbers as strings instead of integers. iykyk πŸ’œ


πŸ¦‹ install.pl

Our first script, install.pl, reads our schema file and creates the tables in the database. iconic behavior fr fr.

#!/usr/bin/env perl

use strict;
use warnings;
use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
use Getopt::Long;
use FindBin;
use lib "$FindBin::Bin/../lib";
use MyDatabase::Main;

my $force_overwrite = 0;

unless ( GetOptions( 'force_overwrite!' => \$force_overwrite ) ) {
    die "Invalid options";
}

my $schema = MyDatabase::Main->connect('dbi:SQLite:mydb.db');

my $dh = DH->new(
    {
        schema              => $schema,
        script_directory    => "$FindBin::Bin/../dbicdh",
        databases           => 'SQLite',
        sql_translator_args => { add_drop_table => 0 },
        force_overwrite     => $force_overwrite,
    }
);

$dh->prepare_install;
$dh->install;

🧚 dbicdh - Our migration scripts

Running install.pl should create the following:

dbicdh/
|-- SQLite
|   `-- deploy
|       `-- 1
|           `-- 001-auto.sql
`-- _source
    `-- deploy
        `-- 1
            `-- 001-auto.yml

You may wish to turn on debug logging before running this script by setting the environment variable DBICDH_TRACE to 1. πŸ‘‘

⭐ 001-auto.sql

DBIx::Class::DeploymentHandler automatically generates SQL from our schema that is suitable for SQLite

🌈 001-auto.yml

This contains all of the raw information about our schema that is then translated into the sql.

πŸ’– Population

To truly take advantage of all DBIx::Class::DeploymentHandler offers, you should probably be using it for population. To do that, all you need to do is create a file called dbicdh/_common/deploy/1/create_artists.pl:

sub {
   my $schema = shift;
   $schema->resultset('Artist')->populate([
      ['artistid', 'name'],
      [1,          'Marillion'],
      [2,          'The Moutain Goats'],
      [3,          'Ladyhawke'],
   ]);
};

πŸ”₯ Upgrading

Add a line to MyDatabase/Main/Result/Cd.pm below

__PACKAGE__->add_columns(qw/ cdid artist title /);

with

__PACKAGE__->add_column(isbn => { is_nullable => 1 });
Aside, and this one matters: it must be nullable or have a default β€” otherwise the upgrade will fail for logical reasons. To be clear, if you add a column to a database and it is not nullable and has no default, what will the existing rows contain for that column? 😭 nothing. there's no answer. that's the problem.

Now you need to modify the schema version in your MyDatabase::Main file to tell DBIx::Class::DeploymentHandler the new schema version number. And you'll want to remember that earlier advice about integer version numbers. πŸ‘‘

our $VERSION = 2;

So here's our next script, upgrade.pl:

#!/usr/bin/env perl
use strict;
use warnings;
use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
use FindBin;
use lib "$FindBin::Bin/../lib";
use MyDatabase::Main;
my $schema = MyDatabase::Main->connect('dbi:SQLite:mydb');

my $dh = DH->new({
   schema              => $schema,
   script_directory    => "$FindBin::Bin/../dbicdh",
   databases           => 'SQLite',
   sql_translator_args => { add_drop_table => 0 },
});

$dh->prepare_deploy;
$dh->prepare_upgrade({ from_version => 1, to_version => 2});
$dh->upgrade;

Our script directory now looks like:

dbicdh/
|-- SQLite
|   |-- deploy
|   |   |-- 1
|   |   |   `-- 001-auto.sql
|   |   `-- 2
|   |       `-- 001-auto.sql
|   `-- upgrade
|       `-- 1-2
|           `-- 001-auto.sql
`-- _source
    `-- deploy
        |-- 1
        |   `-- 001-auto.yml
        `-- 2
            `-- 001-auto.yml

The new deploy/001-auto.sql and deploy/001-auto.yml files are the state of the db as at that version. But the upgrade/1-2/001-auto.sql file is the most interesting one β€” it's what gets your database from version 1 to 2. main character energy tbh. πŸ’…

And again, you can create a Perl file like we did previously with the deploy stage. 🫢


πŸ‘‘ AUTHOR

Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>


This software is copyright (c) 2025 by Arthur Axel "fREW" Schmidt.

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


and that's the whole page bestie!! this was DBIx::Class::DeploymentHandler::Manual::Intro, served up in the User Contributed Perl Documentation, from perl v5.42.0, dated 2026-01-17. go forth and migrate responsibly πŸ’–βœ¨

πŸ“¦ where this page comes from