A Tour of DBIx::Class::Helpers
Hello!
DBIx::Class is one of the most popular ORMs used in Perl and Catalyst development; it is remarkably flexible and useful. But there is a price for that flexibility: often things that are concise in other ORMs are complex in DBIx::Class.
DBIx::Class::Helpers aim at solving the complexity problem as succinctly as possible. As our good friend mst might say, they allow you to code less so you can get down to the pub earlier :-)
So without further ado, I will start with the first, most basic helper...
IgnoreWantarray
DBIx::Class::Helper::IgnoreWantarray has the longest name, but the
most basic functionality: it takes away the context sensitivity of $rs->search
. Why would a person ever want to do that? Well, in array
context, $rs->search
will return an array of your database. You
might not want that. I often write code like the following:
return $self->sort( $self->paginate( $self->schema->resultset('Parts') ) );
Unfortunately, this often means that instead of passing another
resultset to $self->sort
, I end up passing the database
instead. This confounds me and my coworkers enough that I'd rather
call $rs->all
if I need the actual results. IgnoreWantarray
makes search always return a resultset.
JoinTable
DBIx::Class::Helper::JoinTable was one of the first components in
the Helper suite. Its name should make its purpose obvious. Any time
you have a many-to-many relationship, you must have a table joining
those two sets of items. An example could be users and roles. Users
have many roles; roles have many users. The correct way to program
this relationship is with a join
table. DBIx::Class::Helper::JoinTable makes creating these tables
extremely easy. And because DBIx::Class allows us to call
add_columns
more than once, it's a cinch to add data other than the
relationship.
An example might be an award given from a school. We have a Student table, a School table, an Award table, and a Student_Award table. The Student_Award table should join Student and Award, but might as well contain the date the award was conferred and maybe some information about why the student received the award.
Random
DBIx::Class::Helper::Random exists to serve a fairly basic need: picking random rows from a given table. Currently it only returns a single row, but soon, hopefully, DBIx::Class will support the necessary machinations to return a resultset of random rows.
SubClass
DBIx::Class::Helper::SubClass is certainly the most complex of
these components, but I would argue it is the most important as
well. This component allows almost seamless subclassing of
DBIx::Class
ResultSources. It does things like __PACKAGE__->table( __PACKAGE__->table )
, which are annoying and
unsightly, as well as more complex things, like recreating
relationships based on the parent class.
At work I'd like to define a set of tables for authorization - users, roles, permissions, and join tables between them. I do not want to copy and paste this code to our many disparate projects. DBIx::Class::Helper::SubClass solves the problem nicely.
Another reason to use this helper is to define a table without certain columns (TEXT columns come to mind). Instead of redefining the table with the text columns in another place, you might use this helper to subclass the one without the text columns and add text columns to the child class.
VirtualView
DBIx::Class::Helper::VirtualView is the most conceptually complex of the Helper components. Its purpose is mostly to clean up data returned from a resultset. I won't go into all the gory details here. For an idea of how it works see the POD and tests.
Extensibility
In writing these components I've tried to make parts overrideable in
the spirit of DBIx::Class. For example, if you do not like that
join tables have an underscore between table names, you could subclass
DBIx::Class::Helper::JoinTable, override set_table
, and then use your
subclassed module to name your tables as you please.
Author
Arthur Axel "fREW" Schmidt <frioux@gmail.com>