Demystifying
      DBIx::Class
                Jay Shirley
      <jshirley@coldhardcode.com>



http://our.coldhardcode.co...
Mystic?
Why are ORMs scary?
Why are ORMs scary?

• Enterprise-y
Why are ORMs scary?

• Enterprise-y
• Loss of control
Why are ORMs scary?

• Enterprise-y
• Loss of control
• History (Class::DBI)
Why are ORMs scary?

• Enterprise-y
• Loss of control
• History (Class::DBI)
 • (A triumph of multiple inheritance)
Retort.
Enterprise-y
Enterprise-y


• Enterprise = Java
Enterprise-y


• Enterprise = Java
• DBIx::Class is written in perl
Loss of Control
Loss of Control

• Still programmatic
Loss of Control

• Still programmatic
• Use SQL::Abstract rather than SQL
Loss of Control

• Still programmatic
• Use SQL::Abstract rather than SQL
• Same thing
Loss of Control

• Still programmatic
• Use SQL::Abstract rather than SQL
• Same thing
 • (except patches welcome)
Class::DBI
Class::DBI


  Sorry Schwern
Why DBIx::Class?

• I like it. You’ll see why.
• TIMTOWDI:
 • Rose::DB
 • Alzabo
Objects

• Relations are only a third of an ORM
Objects

• Relations are only a third of an ORM
• What’s an object?
Objects

• Relations are only a third of an ORM
• What’s an object?
 • Database columns
Objects

• Relations are only a third of an ORM
• What’s an object?
 • Database columns
 • Table
Objects

• Relations are only a third of an ORM
• What’s an object?
 • Database columns
 • Table
 • Indexes
A Use Case
Beer
Yes, Beer.
Or...

• Beer has many distributers
• Beer has many reviews
• Beer belongs to a brewer
Which means...
package Beer::Schema::Beer;

use base 'DBIx::Class';

__PACKAGE__->load_components( qw|Core| );

__PACKAGE_...
And indexes:


__PACKAGE__->add_unique_index(...);
That gives you:


• Deployable SQL (CREATE TABLE, etc)
• The foundation for relationships:
 • $beer->brewer   # DTRT
Managing Relations

• A beer is:
 • made by a brewer
 • distributed by distributers
 • reviewed by people
Simple Relationships

belongs_to is the opposite end of has_many
Simple Relationships

belongs_to is the opposite end of has_many
   has_one, might_have means just that
Simple Relationships

belongs_to is the opposite end of has_many
   has_one, might_have means just that
     many_to_many ...
Creating a relation

__PACKAGE__->belongs_to(
    ‘brewer’,                # Accessor

     ‘Beer::Schema::Brewer’, # Rela...
For simplicity...


Brewers, Distributors and Beers are all easy
All the same, except Beer has a brewer
(brewer_pk1)
Using it (Manager)


use Beer::Schema;
my $schema = Beer::Schema
    ->connect( $dsn );
$schema


# Fetch a result set
my $rs = $schema->resultset(‘Beer’);
Result Sets


# Everything is a result set.
$rs->count; # How many Beers?
Everything is a
       Result Set

$rs2 = $rs->search({
    name => ‘Stout’
});
$rs2->count; # It chains together.
Chained Result Sets
  are what make
   DBIC Great
Result Sets return
     Result Sets
$rs->search->search->search-
>search->search->search ->search-
>search->search->search...
Why?

$rs
      ->search({ $long_query })
      ->search({ $more_filters })
      ->search({ $even_more });
Actual Use:
sub active_members {
    # All profiles that have purchased a membership.
    my $query = $rs->search(
       ...
In SQL:

SELECT ... FROM table_profiles me LEFT JOIN profile_transaction profile_transactions ON
( profile_transactions.pr...
Now:

my $query = $schema->resultset(‘Profile’)->active_members;


$query->count; # How many?
$query->search({ first_name ...
Pretty.
Even More:
Managing your schema
Create Table
                     Statements
$schema->create_ddl_dir(

       [ 'SQLite', 'MySQL', ‘PostgreSQL’ ],

      ...
SQLite

CREATE TABLE beer (

  pk1 INTEGER PRIMARY KEY NOT NULL,

  name varchar(128) NOT NULL,

  brewer_pk1 integer(16) ...
DROP TABLE IF EXISTS `beer`;
                               MySQL
--

-- Table: `beer`

--

CREATE TABLE `beer` (

  `pk1`...
PostgreSQL
--

-- Table: beer

--

DROP TABLE beer CASCADE;

CREATE TABLE beer (

  pk1 bigserial NOT NULL,

  name charac...
Get a working database


$schema->deploy; # Yes, it is this simple.
And now for tests
Upcoming SlideShare
Loading in …5
×

Demystifying DBIx::Class

7,356 views

Published on

These are the slides to my talk I gave at the June 2008 talk at the Portland Perl Monger's Meeting.
The focus of the talk was on demystifying DBIx::Class, and is followed by the example located at http://our.coldhardcode.com/svn/misc/DBIC-Beer/

Published in: Economy & Finance, Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,356
On SlideShare
0
From Embeds
0
Number of Embeds
103
Actions
Shares
0
Downloads
121
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Demystifying DBIx::Class

  1. 1. Demystifying DBIx::Class Jay Shirley <jshirley@coldhardcode.com> http://our.coldhardcode.com/svn/DBIC-Beer
  2. 2. Mystic?
  3. 3. Why are ORMs scary?
  4. 4. Why are ORMs scary? • Enterprise-y
  5. 5. Why are ORMs scary? • Enterprise-y • Loss of control
  6. 6. Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI)
  7. 7. Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI) • (A triumph of multiple inheritance)
  8. 8. Retort.
  9. 9. Enterprise-y
  10. 10. Enterprise-y • Enterprise = Java
  11. 11. Enterprise-y • Enterprise = Java • DBIx::Class is written in perl
  12. 12. Loss of Control
  13. 13. Loss of Control • Still programmatic
  14. 14. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL
  15. 15. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing
  16. 16. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing • (except patches welcome)
  17. 17. Class::DBI
  18. 18. Class::DBI Sorry Schwern
  19. 19. Why DBIx::Class? • I like it. You’ll see why. • TIMTOWDI: • Rose::DB • Alzabo
  20. 20. Objects • Relations are only a third of an ORM
  21. 21. Objects • Relations are only a third of an ORM • What’s an object?
  22. 22. Objects • Relations are only a third of an ORM • What’s an object? • Database columns
  23. 23. Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table
  24. 24. Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table • Indexes
  25. 25. A Use Case
  26. 26. Beer
  27. 27. Yes, Beer.
  28. 28. Or... • Beer has many distributers • Beer has many reviews • Beer belongs to a brewer
  29. 29. Which means... package Beer::Schema::Beer; use base 'DBIx::Class'; __PACKAGE__->load_components( qw|Core| ); __PACKAGE__->table('beer'); __PACKAGE__->add_columns( 'pk1' => { data_type => 'integer', size => 16, is_nullable => 0, is_auto_increment => 1 }, 'name' => { data_type => 'varchar', size => 128, is_nullable => 0 }, 'brewer_pk1' => { data_type => 'integer', size => 16, is_nullable => 0, is_foreign_key => 1 }, ); __PACKAGE__->set_primary_key('pk1'); 1;
  30. 30. And indexes: __PACKAGE__->add_unique_index(...);
  31. 31. That gives you: • Deployable SQL (CREATE TABLE, etc) • The foundation for relationships: • $beer->brewer # DTRT
  32. 32. Managing Relations • A beer is: • made by a brewer • distributed by distributers • reviewed by people
  33. 33. Simple Relationships belongs_to is the opposite end of has_many
  34. 34. Simple Relationships belongs_to is the opposite end of has_many has_one, might_have means just that
  35. 35. Simple Relationships belongs_to is the opposite end of has_many has_one, might_have means just that many_to_many gets complicated
  36. 36. Creating a relation __PACKAGE__->belongs_to( ‘brewer’, # Accessor ‘Beer::Schema::Brewer’, # Related Class ‘brewer_pk1’ # My Column );
  37. 37. For simplicity... Brewers, Distributors and Beers are all easy All the same, except Beer has a brewer (brewer_pk1)
  38. 38. Using it (Manager) use Beer::Schema; my $schema = Beer::Schema ->connect( $dsn );
  39. 39. $schema # Fetch a result set my $rs = $schema->resultset(‘Beer’);
  40. 40. Result Sets # Everything is a result set. $rs->count; # How many Beers?
  41. 41. Everything is a Result Set $rs2 = $rs->search({ name => ‘Stout’ }); $rs2->count; # It chains together.
  42. 42. Chained Result Sets are what make DBIC Great
  43. 43. Result Sets return Result Sets $rs->search->search->search- >search->search->search ->search- >search->search->search->search- >search ->search->search->search- >search->search->search ->search- >search->search->search->search- >search ->search->search->search- >search->search->search ->search- >search->search->search->search- >search;
  44. 44. Why? $rs ->search({ $long_query }) ->search({ $more_filters }) ->search({ $even_more });
  45. 45. Actual Use: sub active_members { # All profiles that have purchased a membership. my $query = $rs->search( { 'purchase.saved_object_key' => 'membership', 'membership.expiration_date' => '>= NOW()' }, { join => { profile_transactions => { 'transaction' => { 'link_transaction_purchase' => { 'purchase' => 'membership' } } }, }, prefetch => [ 'state', 'country', { profile_transactions => { 'transaction' => { 'link_transaction_purchase' => { 'purchase' => 'membership' } } }, } ], group_by => [ qw/membership_id/ ] } ); }
  46. 46. In SQL: SELECT ... FROM table_profiles me LEFT JOIN profile_transaction profile_transactions ON ( profile_transactions.profile_id = me.profile_id ) JOIN nasa_transactions transaction ON ( transaction.transaction_id = profile_transactions.transaction_id ) LEFT JOIN link_trans_pp link_transaction_purchase ON ( link_transaction_purchase.transaction_id = transaction.transaction_id ) JOIN purchased_products purchase ON ( purchase.purchased_id = link_transaction_purchase.purchased_id ) JOIN nasa_membership membership ON ( membership.membership_id = purchase.saved_product_id ) JOIN state_lookup state ON ( state.state_lookup_id = me.state ) JOIN country_lookup country ON ( country.country_lookup_id = me.country_id ) WHERE ( membership.expiration_date >= NOW() AND purchase.saved_object_key = 'membership' )
  47. 47. Now: my $query = $schema->resultset(‘Profile’)->active_members; $query->count; # How many? $query->search({ first_name => ‘Bob’ }); # All matching members named Bob $query->search({ first_name => ‘Bob’ })->count; while ( my $profile = $query->next ) { $profile->cars; # Get all of this persons cars } # Clean, no ugly SQL
  48. 48. Pretty.
  49. 49. Even More: Managing your schema
  50. 50. Create Table Statements $schema->create_ddl_dir( [ 'SQLite', 'MySQL', ‘PostgreSQL’ ], $VERSION, quot;$destinationquot; );
  51. 51. SQLite CREATE TABLE beer ( pk1 INTEGER PRIMARY KEY NOT NULL, name varchar(128) NOT NULL, brewer_pk1 integer(16) NOT NULL );
  52. 52. DROP TABLE IF EXISTS `beer`; MySQL -- -- Table: `beer` -- CREATE TABLE `beer` ( `pk1` integer(16) NOT NULL auto_increment, `name` varchar(128) NOT NULL, `brewer_pk1` integer(16) NOT NULL, INDEX (`pk1`), INDEX (`brewer_pk1`), PRIMARY KEY (`pk1`), CONSTRAINT `beer_fk_brewer_pk1` FOREIGN KEY (`brewer_pk1`) REFERENCES `brewer` (`pk1`) ON DELETE CASCADE ON UPDATE CASCADE ) Type=InnoDB;
  53. 53. PostgreSQL -- -- Table: beer -- DROP TABLE beer CASCADE; CREATE TABLE beer ( pk1 bigserial NOT NULL, name character varying(128) NOT NULL, brewer_pk1 bigint NOT NULL, PRIMARY KEY (pk1) );
  54. 54. Get a working database $schema->deploy; # Yes, it is this simple.
  55. 55. And now for tests

×