Your SlideShare is downloading. ×
Demystifying DBIx::Class
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Demystifying DBIx::Class

6,430
views

Published on

These are the slides to my talk I gave at the June 2008 talk at the Portland Perl Monger's Meeting. …

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
6,430
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
113
Comments
0
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Demystifying DBIx::Class Jay Shirley <jshirley@coldhardcode.com> http://our.coldhardcode.com/svn/DBIC-Beer
  • 2. Mystic?
  • 3. Why are ORMs scary?
  • 4. Why are ORMs scary? • Enterprise-y
  • 5. Why are ORMs scary? • Enterprise-y • Loss of control
  • 6. Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI)
  • 7. Why are ORMs scary? • Enterprise-y • Loss of control • History (Class::DBI) • (A triumph of multiple inheritance)
  • 8. Retort.
  • 9. Enterprise-y
  • 10. Enterprise-y • Enterprise = Java
  • 11. Enterprise-y • Enterprise = Java • DBIx::Class is written in perl
  • 12. Loss of Control
  • 13. Loss of Control • Still programmatic
  • 14. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL
  • 15. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing
  • 16. Loss of Control • Still programmatic • Use SQL::Abstract rather than SQL • Same thing • (except patches welcome)
  • 17. Class::DBI
  • 18. Class::DBI Sorry Schwern
  • 19. Why DBIx::Class? • I like it. You’ll see why. • TIMTOWDI: • Rose::DB • Alzabo
  • 20. Objects • Relations are only a third of an ORM
  • 21. Objects • Relations are only a third of an ORM • What’s an object?
  • 22. Objects • Relations are only a third of an ORM • What’s an object? • Database columns
  • 23. Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table
  • 24. Objects • Relations are only a third of an ORM • What’s an object? • Database columns • Table • Indexes
  • 25. A Use Case
  • 26. Beer
  • 27. Yes, Beer.
  • 28. Or... • Beer has many distributers • Beer has many reviews • Beer belongs to a brewer
  • 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. And indexes: __PACKAGE__->add_unique_index(...);
  • 31. That gives you: • Deployable SQL (CREATE TABLE, etc) • The foundation for relationships: • $beer->brewer # DTRT
  • 32. Managing Relations • A beer is: • made by a brewer • distributed by distributers • reviewed by people
  • 33. Simple Relationships belongs_to is the opposite end of has_many
  • 34. Simple Relationships belongs_to is the opposite end of has_many has_one, might_have means just that
  • 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. Creating a relation __PACKAGE__->belongs_to( ‘brewer’, # Accessor ‘Beer::Schema::Brewer’, # Related Class ‘brewer_pk1’ # My Column );
  • 37. For simplicity... Brewers, Distributors and Beers are all easy All the same, except Beer has a brewer (brewer_pk1)
  • 38. Using it (Manager) use Beer::Schema; my $schema = Beer::Schema ->connect( $dsn );
  • 39. $schema # Fetch a result set my $rs = $schema->resultset(‘Beer’);
  • 40. Result Sets # Everything is a result set. $rs->count; # How many Beers?
  • 41. Everything is a Result Set $rs2 = $rs->search({ name => ‘Stout’ }); $rs2->count; # It chains together.
  • 42. Chained Result Sets are what make DBIC Great
  • 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. Why? $rs ->search({ $long_query }) ->search({ $more_filters }) ->search({ $even_more });
  • 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. 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. 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. Pretty.
  • 49. Even More: Managing your schema
  • 50. Create Table Statements $schema->create_ddl_dir( [ 'SQLite', 'MySQL', ‘PostgreSQL’ ], $VERSION, quot;$destinationquot; );
  • 51. SQLite CREATE TABLE beer ( pk1 INTEGER PRIMARY KEY NOT NULL, name varchar(128) NOT NULL, brewer_pk1 integer(16) NOT NULL );
  • 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. 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. Get a working database $schema->deploy; # Yes, it is this simple.
  • 55. And now for tests