Introduction to DBIx::Class

Portland, OR

April 14, 2010

What is DBIx::Class?

What is DBIx::Class?

see the manual: http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class/Manual.pod

What it looks like

package My::Schema;

__PACKAGE__->load_namespaces;

package My::Schema::Result::Foo;

__PACKAGE__->table('foo');
__PACKAGE__->add_columns(qw( foo_id bar baz ));
__PACKAGE__->has_many('bars' => 'My::Schema::Result::Bar');
# also belongs_to  many_to_many

package My::Schema::Result::Bar;

__PACKAGE__->table('bar');
# and so on

Basic Usage

continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
my $orgs_rs = $schema->resultset('Organism');
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
my $orgs_rs = $schema->resultset('Organism');
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
my $orgs_rs = $schema->resultset('Organism');
my $chickeny_things = $orgs_rs->search({ genus => 'Gallus' });
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
my $orgs_rs = $schema->resultset('Organism');
my $chickeny_things = $orgs_rs->search({ genus => 'Gallus' });
continued...

Basic Usage

my $schema = My::Schema->connect( 'dbi:Pg:...', $user, $pass );
my $orgs_rs = $schema->resultset('Organism');
my $chickeny_things = $orgs_rs->search({ genus => 'Gallus' });
my $chicken = $chickeny_things->first;     #< actual query is run

Basic Usage

continued...

Basic Usage

continued...

Basic Usage

my $wombat = $orgs_rs->find( 232432 );
continued...

Basic Usage

my $wombat = $orgs_rs->find( 232432 );
say $wombat->genus.' '.$wombat->species; #< print 'Vombatus ursinus' or something

# or search in list context returns all resulting rows
my @all_nightshades = $orgs_rs->search({ genus => 'Solanum' });

Basic Usage

continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
$orgs_rs>create({ genus => 'Mus', species => 'musculus' })
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
$orgs_rs>create({ genus => 'Mus', species => 'musculus' })
# or piecewise
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
$orgs_rs>create({ genus => 'Mus', species => 'musculus' })
# or piecewise
my $new = $orgs_rs->new;
$new->genus('Mus');  $new->species('musculus');
$new->insert;
continued...

Basic Usage

my $chickeny_things = $ck_rs->search({ genus => 'Gallus' });
my @chr = $chickeny_things->chromosomes;  #< query is run here
my @genes = $chicken->chromosomes->features->search({ type => 'gene' });
$orgs_rs>create({ genus => 'Mus', species => 'musculus' })
# or piecewise
my $new = $orgs_rs->new;
$new->genus('Mus');  $new->species('musculus');
$new->insert;
$chicken->chromosomes->features->search({ type => 'gene' })->delete;

When not to use DBIC

continued...

When not to use DBIC

continued...

When not to use DBIC

strengths/weaknesses ...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

continued...

Strengths and Weaknesses

Chainable ResultSets

my $styx_tracks =
     $music_schema->resultset('Artist')
                  ->search({ name => 'Styx' })
                  ->albums
                  ->tracks;

SELECT ...
  FROM artist
  JOIN albums ON ...
  JOIN tracks ON ...
  WHERE artist.name = 'Styx'

Lazy Querying

# fetch all
my @tracks = $styx_tracks->all;

# or iterate
while( my $track = $styx_tracks->next ) { ... }

Custom SQL

package My::Schema::SummarizedFrobs;
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
__PACKAGE__->result_source_instance->view_definition(<<'');
   SELECT omg_so_much_stuff
   UNION
   SELECT ( SELECT blah blah blah FROM blah ),
          ( blah blah blah ),
   WHERE blah blah blah
   UNION
      blah blah blah

__PACKAGE__->add_column( <cols in your view> )

Custom SQL

$schema->resultSet('Sequence::Feature')
       ->search({
            'me.feature_id' =>
              \[ "IN( select feature_id from clone_feature where clone_id = ?)",
                 [ dummy => $self->clone_id ],
               ],
            },
            { rows => 10,
              order_by => [qw[ me.name me.type_id ]],
              having
            });

Prefetching

# query will get the wombat organism, and also prefetch *all its
# chromosomes and features on those chromosomes*
my $rs = $schema->resultset('Organism')->search(
 { genus => 'Vombatus', species => 'ursinus' },
 { prefetch => { chromosomes => features => } },
);

(in a real biological DB this would probably blow your memory)

Extensions

continued...

Extensions

continued...

Extensions

continued...

Extensions

Thread-Safe / Fork-Safe

Non-linear Join

# get features via the potato organism, also joining in the cvterms table
my $potato_bacs =
     $schema->resultset('Organism')
            ->search({ species => 'Solanum tuberosum' })
            ->search_related( 'features',
                             { 'type.name' => 'BAC_clone'},
                             { 'join' => 'type' },
                           );

Non-linear Join

# the equivalent bare SQL
my $potato_bacs = $dbh->selectall_arrayref( <<EOS, undef, 'Solanum tuberosum', 'BAC_clone');
SELECT features.feature_id
     , features.dbxref_id
     , features.organism_id
     , features.name
     , features.uniquename
     , features.residues
     , features.seqlen
     , features.md5checksum
     , features.type_id
     , features.is_analysis
     , features.is_obsolete
     , features.timeaccessioned
     , features.timelastmodified
FROM organism me
LEFT JOIN feature features
       ON features.organism_id = me.organism_id
JOIN cvterm type
       ON type.cvterm_id = features.type_id
WHERE species = ? AND type.name = ?
EOS

Convenient Loading of Relationships

$chado->resultset( 'Cv::Cv' )
      ->find_or_create({ name => 'My Fake Ontology' })
      ->create_related(  'cvterm',
                         { name => 'MyFakeTerm' });

makes the SQL:

SELECT me.cv_id
     , me.name
     , me.definition
FROM cv me
WHERE ( me.name = 'my fake ontology' )

INSERT INTO cv ( name )
        VALUES ( 'my fake ontology' )
     RETURNING cv_id

INSERT INTO cvterm ( cv_id,  name        )
            VALUES ( ?,     'MyFakeTerm' )

Transactions

$schema->txn_do(sub {

    $schema->resultset('Cv::Cv')
           ->find_or_create({ name => 'My Fake Ontology' })
           ->create_related( 'cvterm', { name => 'MyFakeTerm' } );

});

The Real Advantages of DBIC

The Real Advantages of DBIC

The Real Advantages of DBIC

The Real Advantages of DBIC

continued...

The Real Advantages of DBIC

That's All