demystifying dbix::class

55
Demystifying DBIx::Class Jay Shirley <[email protected] > http://our.coldhardcode.com/svn/DBIC-Beer

Upload: jay-shirley

Post on 29-Nov-2014

9.641 views

Category:

Economy & Finance


1 download

DESCRIPTION

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/

TRANSCRIPT

Page 2: Demystifying DBIx::Class

Mystic?

Page 3: Demystifying DBIx::Class

Why are ORMs scary?

Page 4: Demystifying DBIx::Class

Why are ORMs scary?

• Enterprise-y

Page 5: Demystifying DBIx::Class

Why are ORMs scary?

• Enterprise-y

• Loss of control

Page 6: Demystifying DBIx::Class

Why are ORMs scary?

• Enterprise-y

• Loss of control

• History (Class::DBI)

Page 7: Demystifying DBIx::Class

Why are ORMs scary?

• Enterprise-y

• Loss of control

• History (Class::DBI)

• (A triumph of multiple inheritance)

Page 8: Demystifying DBIx::Class

Retort.

Page 9: Demystifying DBIx::Class

Enterprise-y

Page 10: Demystifying DBIx::Class

Enterprise-y

• Enterprise = Java

Page 11: Demystifying DBIx::Class

Enterprise-y

• Enterprise = Java

• DBIx::Class is written in perl

Page 12: Demystifying DBIx::Class

Loss of Control

Page 13: Demystifying DBIx::Class

Loss of Control

• Still programmatic

Page 14: Demystifying DBIx::Class

Loss of Control

• Still programmatic

• Use SQL::Abstract rather than SQL

Page 15: Demystifying DBIx::Class

Loss of Control

• Still programmatic

• Use SQL::Abstract rather than SQL

• Same thing

Page 16: Demystifying DBIx::Class

Loss of Control

• Still programmatic

• Use SQL::Abstract rather than SQL

• Same thing

• (except patches welcome)

Page 17: Demystifying DBIx::Class

Class::DBI

Page 18: Demystifying DBIx::Class

Class::DBI

Sorry Schwern

Page 19: Demystifying DBIx::Class

Why DBIx::Class?

• I like it. You’ll see why.

• TIMTOWDI:

• Rose::DB

• Alzabo

Page 20: Demystifying DBIx::Class

Objects

• Relations are only a third of an ORM

Page 21: Demystifying DBIx::Class

Objects

• Relations are only a third of an ORM

• What’s an object?

Page 22: Demystifying DBIx::Class

Objects

• Relations are only a third of an ORM

• What’s an object?

• Database columns

Page 23: Demystifying DBIx::Class

Objects

• Relations are only a third of an ORM

• What’s an object?

• Database columns

• Table

Page 24: Demystifying DBIx::Class

Objects

• Relations are only a third of an ORM

• What’s an object?

• Database columns

• Table

• Indexes

Page 25: Demystifying DBIx::Class

A Use Case

Page 26: Demystifying DBIx::Class

Beer

Page 27: Demystifying DBIx::Class

Yes, Beer.

Page 28: Demystifying DBIx::Class

Or...

• Beer has many distributers

• Beer has many reviews

• Beer belongs to a brewer

Page 29: Demystifying DBIx::Class

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;

Page 30: Demystifying DBIx::Class

And indexes:

__PACKAGE__->add_unique_index(...);

Page 31: Demystifying DBIx::Class

That gives you:

• Deployable SQL (CREATE TABLE, etc)

• The foundation for relationships:

•$beer->brewer # DTRT

Page 32: Demystifying DBIx::Class

Managing Relations

• A beer is:

• made by a brewer

• distributed by distributers

• reviewed by people

Page 33: Demystifying DBIx::Class

Simple Relationships

belongs_to is the opposite end of has_many

Page 34: Demystifying DBIx::Class

Simple Relationships

belongs_to is the opposite end of has_many

has_one, might_have means just that

Page 35: Demystifying DBIx::Class

Simple Relationships

belongs_to is the opposite end of has_many

has_one, might_have means just that

many_to_many gets complicated

Page 36: Demystifying DBIx::Class

Creating a relation

__PACKAGE__->belongs_to( ‘brewer’, # Accessor

‘Beer::Schema::Brewer’, # Related Class

‘brewer_pk1’ # My Column);

Page 37: Demystifying DBIx::Class

For simplicity...

Brewers, Distributors and Beers are all easy

All the same, except Beer has a brewer (brewer_pk1)

Page 38: Demystifying DBIx::Class

Using it (Manager)

use Beer::Schema;

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

Page 39: Demystifying DBIx::Class

$schema

# Fetch a result set

my $rs = $schema->resultset(‘Beer’);

Page 40: Demystifying DBIx::Class

Result Sets

# Everything is a result set.

$rs->count; # How many Beers?

Page 41: Demystifying DBIx::Class

Everything is aResult Set

$rs2 = $rs->search({ name => ‘Stout’ }); $rs2->count; # It chains together.

Page 42: Demystifying DBIx::Class

Chained Result Setsare what makeDBIC Great

Page 43: Demystifying DBIx::Class

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;

Page 44: Demystifying DBIx::Class

Why?

$rs ->search({ $long_query }) ->search({ $more_filters }) ->search({ $even_more });

Page 45: Demystifying DBIx::Class

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/ ] } );}

Page 46: Demystifying DBIx::Class

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' )

Page 47: Demystifying DBIx::Class

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

Page 48: Demystifying DBIx::Class

Pretty.

Page 49: Demystifying DBIx::Class

Even More:Managing your schema

Page 50: Demystifying DBIx::Class

Create Table Statements

$schema->create_ddl_dir(

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

$VERSION,

"$destination"

);

Page 51: Demystifying DBIx::Class

SQLite

CREATE TABLE beer (

pk1 INTEGER PRIMARY KEY NOT NULL,

name varchar(128) NOT NULL,

brewer_pk1 integer(16) NOT NULL

);

Page 52: Demystifying DBIx::Class

MySQLDROP TABLE IF EXISTS `beer`;

--

-- 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;

Page 53: Demystifying DBIx::Class

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)

);

Page 54: Demystifying DBIx::Class

Get a working database

$schema->deploy; # Yes, it is this simple.

Page 55: Demystifying DBIx::Class

And now for tests