More descriptive error messages courtesy of Marc Espie
[dbsrgits/DBIx-Class-Historic.git] / lib / DBIx / Class / Manual / Cookbook.pod
CommitLineData
3b44ccc6 1=head1 NAME
9c82c181 2
40dbc108 3DBIx::Class::Manual::Cookbook - Miscellaneous recipes
ee38fa40 4
40dbc108 5=head1 RECIPES
2913b2d3 6
bade79c4 7=head2 Searching
faf62551 8
bade79c4 9=head3 Paged results
faf62551 10
bade79c4 11When you expect a large number of results, you can ask L<DBIx::Class> for a
12paged resultset, which will fetch only a small number of records at a time:
faf62551 13
bade79c4 14 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 15 undef,
bade79c4 16 {
17 page => 1, # page to return (defaults to 1)
18 rows => 10, # number of results per page
19 },
20 );
faf62551 21
bade79c4 22 return $rs->all(); # all records for page 1
faf62551 23
bade79c4 24The C<page> attribute does not have to be specified in your search:
25
26 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 27 undef,
bade79c4 28 {
29 rows => 10,
30 }
31 );
faf62551 32
bade79c4 33 return $rs->page(1); # DBIx::Class::ResultSet containing first 10 records
faf62551 34
35In either of the above cases, you can return a L<Data::Page> object for the
bade79c4 36resultset (suitable for use in e.g. a template) using the C<pager> method:
faf62551 37
bade79c4 38 return $rs->pager();
faf62551 39
bade79c4 40=head3 Complex WHERE clauses
2913b2d3 41
40dbc108 42Sometimes you need to formulate a query using specific operators:
43
ea6309e2 44 my @albums = $schema->resultset('Album')->search({
35d4fe78 45 artist => { 'like', '%Lamb%' },
46 title => { 'like', '%Fear of Fours%' },
47 });
40dbc108 48
49This results in something like the following C<WHERE> clause:
50
35d4fe78 51 WHERE artist LIKE '%Lamb%' AND title LIKE '%Fear of Fours%'
40dbc108 52
53Other queries might require slightly more complex logic:
54
ea6309e2 55 my @albums = $schema->resultset('Album')->search({
35d4fe78 56 -or => [
57 -and => [
58 artist => { 'like', '%Smashing Pumpkins%' },
59 title => 'Siamese Dream',
60 ],
61 artist => 'Starchildren',
62 ],
63 });
40dbc108 64
65This results in the following C<WHERE> clause:
66
35d4fe78 67 WHERE ( artist LIKE '%Smashing Pumpkins%' AND title = 'Siamese Dream' )
68 OR artist = 'Starchildren'
40dbc108 69
70For more information on generating complex queries, see
71L<SQL::Abstract/WHERE CLAUSES>.
ee38fa40 72
bade79c4 73=head3 Using specific columns
faf62551 74
324572ca 75When you only want specific columns from a table, you can use
76C<columns> to specify which ones you need. This is useful to avoid
77loading columns with large amounts of data that you aren't about to
78use anyway:
faf62551 79
bade79c4 80 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 81 undef,
bade79c4 82 {
5e8b1b2a 83 columns => [qw/ name /]
bade79c4 84 }
85 );
faf62551 86
bade79c4 87 # Equivalent SQL:
88 # SELECT artist.name FROM artist
faf62551 89
324572ca 90This is a shortcut for C<select> and C<as>, see below. C<columns>
91cannot be used together with C<select> and C<as>.
92
bade79c4 93=head3 Using database functions or stored procedures
faf62551 94
bade79c4 95The combination of C<select> and C<as> can be used to return the result of a
96database function or stored procedure as a column value. You use C<select> to
97specify the source for your column value (e.g. a column name, function, or
98stored procedure name). You then use C<as> to set the column name you will use
99to access the returned value:
faf62551 100
bade79c4 101 my $rs = $schema->resultset('Artist')->search(
324572ca 102 {},
bade79c4 103 {
104 select => [ 'name', { LENGTH => 'name' } ],
105 as => [qw/ name name_length /],
106 }
107 );
faf62551 108
bade79c4 109 # Equivalent SQL:
110 # SELECT name name, LENGTH( name ) name_length
111 # FROM artist
faf62551 112
324572ca 113If your alias exists as a column in your base class (i.e. it was added
114with C<add_columns>), you just access it as normal. Our C<Artist>
115class has a C<name> column, so we just use the C<name> accessor:
faf62551 116
bade79c4 117 my $artist = $rs->first();
118 my $name = $artist->name();
faf62551 119
120If on the other hand the alias does not correspond to an existing column, you
324572ca 121have to fetch the value using the C<get_column> accessor:
faf62551 122
bade79c4 123 my $name_length = $artist->get_column('name_length');
faf62551 124
bade79c4 125If you don't like using C<get_column>, you can always create an accessor for
faf62551 126any of your aliases using either of these:
127
bade79c4 128 # Define accessor manually:
129 sub name_length { shift->get_column('name_length'); }
faf62551 130
bade79c4 131 # Or use DBIx::Class::AccessorGroup:
132 __PACKAGE__->mk_group_accessors('column' => 'name_length');
faf62551 133
bade79c4 134=head3 SELECT DISTINCT with multiple columns
faf62551 135
bade79c4 136 my $rs = $schema->resultset('Foo')->search(
324572ca 137 {},
bade79c4 138 {
139 select => [
140 { distinct => [ $source->columns ] }
141 ],
142 as => [ $source->columns ]
143 }
144 );
faf62551 145
286f32b3 146 my $count = $rs->next->get_column('count');
147
bade79c4 148=head3 SELECT COUNT(DISTINCT colname)
6607ee1b 149
bade79c4 150 my $rs = $schema->resultset('Foo')->search(
324572ca 151 {},
bade79c4 152 {
153 select => [
154 { count => { distinct => 'colname' } }
155 ],
156 as => [ 'count' ]
157 }
158 );
6607ee1b 159
bade79c4 160=head3 Grouping results
161
162L<DBIx::Class> supports C<GROUP BY> as follows:
163
164 my $rs = $schema->resultset('Artist')->search(
324572ca 165 {},
bade79c4 166 {
167 join => [qw/ cds /],
168 select => [ 'name', { count => 'cds.cdid' } ],
169 as => [qw/ name cd_count /],
170 group_by => [qw/ name /]
171 }
172 );
6607ee1b 173
bade79c4 174 # Equivalent SQL:
175 # SELECT name, COUNT( cds.cdid ) FROM artist me
176 # LEFT JOIN cd cds ON ( cds.artist = me.artistid )
177 # GROUP BY name
6607ee1b 178
74dc2edc 179=head3 Predefined searches
180
324572ca 181You can write your own L<DBIx::Class::ResultSet> class by inheriting from it
74dc2edc 182and define often used searches as methods:
183
184 package My::DBIC::ResultSet::CD;
185 use strict;
186 use warnings;
187 use base 'DBIx::Class::ResultSet';
188
189 sub search_cds_ordered {
190 my ($self) = @_;
191
192 return $self->search(
193 {},
194 { order_by => 'name DESC' },
195 );
196 }
197
198 1;
199
200To use your resultset, first tell DBIx::Class to create an instance of it
201for you, in your My::DBIC::Schema::CD class:
202
203 __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
204
205Then call your new method in your code:
206
207 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
208
209
d6ed6a67 210=head3 Predefined searches without writing a ResultSet class
211
212Alternatively you can automatically generate a DBIx::Class::ResultSet
213class by using the ResultSetManager component and tagging your method
214as ResultSet:
215
216 __PACKAGE__->load_components(qw/ ResultSetManager Core /);
217
218 sub search_cds_ordered : ResultSet {
219 my ($self) = @_;
220 return $self->search(
221 {},
222 { order_by => 'name DESC' },
223 );
224 }
225
226Then call your method in the same way from your code:
227
228 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
229
87980de7 230=head2 Using joins and prefetch
231
bade79c4 232You can use the C<join> attribute to allow searching on, or sorting your
233results by, one or more columns in a related table. To return all CDs matching
234a particular artist name:
ea6309e2 235
bade79c4 236 my $rs = $schema->resultset('CD')->search(
237 {
238 'artist.name' => 'Bob Marley'
239 },
240 {
241 join => [qw/artist/], # join the artist table
242 }
243 );
244
245 # Equivalent SQL:
246 # SELECT cd.* FROM cd
247 # JOIN artist ON cd.artist = artist.id
248 # WHERE artist.name = 'Bob Marley'
249
250If required, you can now sort on any column in the related tables by including
251it in your C<order_by> attribute:
252
253 my $rs = $schema->resultset('CD')->search(
254 {
255 'artist.name' => 'Bob Marley'
256 },
257 {
258 join => [qw/ artist /],
259 order_by => [qw/ artist.name /]
260 }
261 };
ea6309e2 262
bade79c4 263 # Equivalent SQL:
264 # SELECT cd.* FROM cd
265 # JOIN artist ON cd.artist = artist.id
266 # WHERE artist.name = 'Bob Marley'
267 # ORDER BY artist.name
ea6309e2 268
bade79c4 269Note that the C<join> attribute should only be used when you need to search or
270sort using columns in a related table. Joining related tables when you only
271need columns from the main table will make performance worse!
ea6309e2 272
bade79c4 273Now let's say you want to display a list of CDs, each with the name of the
274artist. The following will work fine:
ea6309e2 275
bade79c4 276 while (my $cd = $rs->next) {
277 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
278 }
ea6309e2 279
bade79c4 280There is a problem however. We have searched both the C<cd> and C<artist> tables
281in our main query, but we have only returned data from the C<cd> table. To get
282the artist name for any of the CD objects returned, L<DBIx::Class> will go back
283to the database:
ea6309e2 284
bade79c4 285 SELECT artist.* FROM artist WHERE artist.id = ?
ea6309e2 286
287A statement like the one above will run for each and every CD returned by our
288main query. Five CDs, five extra queries. A hundred CDs, one hundred extra
289queries!
290
bade79c4 291Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem.
897342e4 292This allows you to fetch results from related tables in advance:
ea6309e2 293
bade79c4 294 my $rs = $schema->resultset('CD')->search(
295 {
296 'artist.name' => 'Bob Marley'
297 },
298 {
299 join => [qw/ artist /],
300 order_by => [qw/ artist.name /],
301 prefetch => [qw/ artist /] # return artist data too!
302 }
303 );
ea6309e2 304
bade79c4 305 # Equivalent SQL (note SELECT from both "cd" and "artist"):
306 # SELECT cd.*, artist.* FROM cd
307 # JOIN artist ON cd.artist = artist.id
308 # WHERE artist.name = 'Bob Marley'
309 # ORDER BY artist.name
ea6309e2 310
311The code to print the CD list remains the same:
312
bade79c4 313 while (my $cd = $rs->next) {
314 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
315 }
ea6309e2 316
bade79c4 317L<DBIx::Class> has now prefetched all matching data from the C<artist> table,
ea6309e2 318so no additional SQL statements are executed. You now have a much more
319efficient query.
320
77d6b403 321Note that as of L<DBIx::Class> 0.05999_01, C<prefetch> I<can> be used with
322C<has_many> relationships.
ea6309e2 323
bade79c4 324Also note that C<prefetch> should only be used when you know you will
ea6309e2 325definitely use data from a related table. Pre-fetching related tables when you
326only need columns from the main table will make performance worse!
327
bade79c4 328=head3 Multi-step joins
ea6309e2 329
330Sometimes you want to join more than one relationship deep. In this example,
bade79c4 331we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes>
332contain a specific string:
333
334 # Relationships defined elsewhere:
335 # Artist->has_many('cds' => 'CD', 'artist');
336 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
337
338 my $rs = $schema->resultset('Artist')->search(
339 {
340 'liner_notes.notes' => { 'like', '%some text%' },
341 },
342 {
343 join => {
344 'cds' => 'liner_notes'
345 }
346 }
347 );
ea6309e2 348
bade79c4 349 # Equivalent SQL:
350 # SELECT artist.* FROM artist
351 # JOIN ( cd ON artist.id = cd.artist )
352 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
353 # WHERE liner_notes.notes LIKE '%some text%'
ea6309e2 354
355Joins can be nested to an arbitrary level. So if we decide later that we
356want to reduce the number of Artists returned based on who wrote the liner
357notes:
358
bade79c4 359 # Relationship defined elsewhere:
360 # LinerNotes->belongs_to('author' => 'Person');
361
362 my $rs = $schema->resultset('Artist')->search(
363 {
364 'liner_notes.notes' => { 'like', '%some text%' },
365 'author.name' => 'A. Writer'
366 },
367 {
368 join => {
369 'cds' => {
370 'liner_notes' => 'author'
ea6309e2 371 }
bade79c4 372 }
373 }
374 );
ea6309e2 375
bade79c4 376 # Equivalent SQL:
377 # SELECT artist.* FROM artist
378 # JOIN ( cd ON artist.id = cd.artist )
379 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
380 # JOIN ( author ON author.id = liner_notes.author )
381 # WHERE liner_notes.notes LIKE '%some text%'
382 # AND author.name = 'A. Writer'
87980de7 383
897342e4 384=head2 Multi-step prefetch
385
386From 0.04999_05 onwards, C<prefetch> can be nested more than one relationship
387deep using the same syntax as a multi-step join:
388
389 my $rs = $schema->resultset('Tag')->search(
ac2803ef 390 {},
897342e4 391 {
392 prefetch => {
393 cd => 'artist'
394 }
395 }
396 );
397
398 # Equivalent SQL:
399 # SELECT tag.*, cd.*, artist.* FROM tag
400 # JOIN cd ON tag.cd = cd.cdid
401 # JOIN artist ON cd.artist = artist.artistid
402
403Now accessing our C<cd> and C<artist> relationships does not need additional
404SQL statements:
405
406 my $tag = $rs->first;
407 print $tag->cd->artist->name;
408
ac2803ef 409=head2 Columns of data
410
411If you want to find the sum of a particular column there are several
412ways, the obvious one is to use search:
413
414 my $rs = $schema->resultset('Items')->search(
415 {},
416 {
417 select => [ { sum => 'Cost' } ],
418 as => [ 'total_cost' ],
419 }
420 );
421 my $tc = $rs->first->get_column('total_cost');
422
423Or, you can use the L<DBIx::Class::ResultSetColumn>, which gets
424returned when you ask the C<ResultSet> for a column using
425C<get_column>:
426
427 my $cost = $schema->resultset('Items')->get_column('Cost');
428 my $tc = $cost->sum;
429
430With this you can also do:
431
432 my $minvalue = $cost->min;
433 my $maxvalue = $cost->max;
434
435Or just iterate through the values of this column only:
436
437 while ( my $c = $cost->next ) {
438 print $c;
439 }
440
441 foreach my $c ($cost->all) {
442 print $c;
443 }
444
709353af 445C<ResultSetColumn> only has a limited number of built-in functions, if
446you need one that it doesn't have, then you can use the C<func> method
447instead:
448
449 my $avg = $cost->func('AVERAGE');
450
451This will cause the following SQL statement to be run:
452
453 SELECT AVERAGE(Cost) FROM Items me
454
455Which will of course only work if your database supports this function.
ac2803ef 456See L<DBIx::Class::ResultSetColumn> for more documentation.
457
acee4e4d 458=head2 Using relationships
459
460=head3 Create a new row in a related table
461
462 my $book->create_related('author', { name => 'Fred'});
463
464=head3 Search in a related table
465
466Only searches for books named 'Titanic' by the author in $author.
467
468 my $author->search_related('books', { name => 'Titanic' });
469
470=head3 Delete data in a related table
471
472Deletes only the book named Titanic by the author in $author.
473
474 my $author->delete_related('books', { name => 'Titanic' });
475
f8bad769 476=head3 Ordering a relationship result set
477
478If you always want a relation to be ordered, you can specify this when you
479create the relationship.
480
481To order C<< $book->pages >> by descending page_number.
482
483 Book->has_many('pages' => 'Page', 'book', { order_by => \'page_number DESC'} );
484
485
486
87980de7 487=head2 Transactions
488
489As of version 0.04001, there is improved transaction support in
181a28f4 490L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>. Here is an
491example of the recommended way to use it:
87980de7 492
181a28f4 493 my $genus = $schema->resultset('Genus')->find(12);
494
70634260 495 my $coderef2 = sub {
496 $genus->extinct(1);
497 $genus->update;
498 };
499
181a28f4 500 my $coderef1 = sub {
35d4fe78 501 $genus->add_to_species({ name => 'troglodyte' });
502 $genus->wings(2);
503 $genus->update;
70634260 504 $schema->txn_do($coderef2); # Can have a nested transaction
181a28f4 505 return $genus->species;
506 };
507
181a28f4 508 my $rs;
509 eval {
70634260 510 $rs = $schema->txn_do($coderef1);
181a28f4 511 };
512
513 if ($@) { # Transaction failed
514 die "the sky is falling!" #
515 if ($@ =~ /Rollback failed/); # Rollback failed
516
517 deal_with_failed_transaction();
35d4fe78 518 }
87980de7 519
181a28f4 520Nested transactions will work as expected. That is, only the outermost
521transaction will actually issue a commit to the $dbh, and a rollback
522at any level of any transaction will cause the entire nested
523transaction to fail. Support for savepoints and for true nested
40dbc108 524transactions (for databases that support them) will hopefully be added
525in the future.
ee38fa40 526
130c6439 527=head2 Many-to-many relationships
ee38fa40 528
ea6309e2 529This is straightforward using L<DBIx::Class::Relationship::ManyToMany>:
530
bade79c4 531 package My::DB;
532 # ... set up connection ...
533
534 package My::User;
535 use base 'My::DB';
536 __PACKAGE__->table('user');
537 __PACKAGE__->add_columns(qw/id name/);
538 __PACKAGE__->set_primary_key('id');
539 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
540 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
541
542 package My::UserAddress;
543 use base 'My::DB';
544 __PACKAGE__->table('user_address');
545 __PACKAGE__->add_columns(qw/user address/);
546 __PACKAGE__->set_primary_key(qw/user address/);
547 __PACKAGE__->belongs_to('user' => 'My::User');
548 __PACKAGE__->belongs_to('address' => 'My::Address');
549
550 package My::Address;
551 use base 'My::DB';
552 __PACKAGE__->table('address');
553 __PACKAGE__->add_columns(qw/id street town area_code country/);
554 __PACKAGE__->set_primary_key('id');
555 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
556 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
557
558 $rs = $user->addresses(); # get all addresses for a user
559 $rs = $address->users(); # get all users for an address
560
561=head2 Setting default values for a row
a00e1684 562
35d4fe78 563It's as simple as overriding the C<new> method. Note the use of
40dbc108 564C<next::method>.
a00e1684 565
35d4fe78 566 sub new {
567 my ( $class, $attrs ) = @_;
40dbc108 568
35d4fe78 569 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
40dbc108 570
35d4fe78 571 $class->next::method($attrs);
572 }
a00e1684 573
4a3c6354 574For more information about C<next::method>, look in the L<Class::C3>
575documentation. See also L<DBIx::Class::Manual::Component> for more
576ways to write your own base classes to do this.
577
578People looking for ways to do "triggers" with DBIx::Class are probably
579just looking for this.
580
25af00d7 581=head2 Stringification
582
40dbc108 583Employ the standard stringification technique by using the C<overload>
462bb847 584module.
585
586To make an object stringify itself as a single column, use something
587like this (replace C<foo> with the column/method of your choice):
25af00d7 588
35d4fe78 589 use overload '""' => 'foo', fallback => 1;
25af00d7 590
462bb847 591For more complex stringification, you can use an anonymous subroutine:
592
593 use overload '""' => sub { $_[0]->name . ", " .
594 $_[0]->address }, fallback => 1;
595
324572ca 596=head3 Stringification Example
462bb847 597
598Suppose we have two tables: C<Product> and C<Category>. The table
599specifications are:
600
601 Product(id, Description, category)
602 Category(id, Description)
603
604C<category> is a foreign key into the Category table.
605
606If you have a Product object C<$obj> and write something like
607
608 print $obj->category
609
610things will not work as expected.
611
612To obtain, for example, the category description, you should add this
613method to the class defining the Category table:
614
615 use overload "" => sub {
616 my $self = shift;
617
618 return $self->Description;
77713550 619 }, fallback => 1;
462bb847 620
bade79c4 621=head2 Disconnecting cleanly
622
623If you find yourself quitting an app with Control-C a lot during
624development, you might like to put the following signal handler in
625your main database class to make sure it disconnects cleanly:
626
627 $SIG{INT} = sub {
6d1bf0a9 628 __PACKAGE__->storage->disconnect;
bade79c4 629 };
630
362500af 631=head2 Schema import/export
632
633This functionality requires you to have L<SQL::Translator> (also known as
634"SQL Fairy") installed.
635
636To create a DBIx::Class schema from an existing database:
637
638 sqlt --from DBI
639 --to DBIx::Class::File
640 --prefix "MySchema" > MySchema.pm
641
642To create a MySQL database from an existing L<DBIx::Class> schema, convert the
643schema to MySQL's dialect of SQL:
644
54c30987 645 sqlt --from SQL::Translator::Parser::DBIx::Class
646 --to MySQL
647 --DBIx::Class "MySchema.pm" > Schema1.sql
362500af 648
649And import using the mysql client:
650
651 mysql -h "host" -D "database" -u "user" -p < Schema1.sql
652
b0a20454 653=head2 Easy migration from class-based to schema-based setup
654
655You want to start using the schema-based approach to L<DBIx::Class>
656(see L<SchemaIntro.pod>), but have an established class-based setup with lots
657of existing classes that you don't want to move by hand. Try this nifty script
658instead:
659
660 use MyDB;
661 use SQL::Translator;
662
663 my $schema = MyDB->schema_instance;
664
665 my $translator = SQL::Translator->new(
666 debug => $debug || 0,
667 trace => $trace || 0,
668 no_comments => $no_comments || 0,
669 show_warnings => $show_warnings || 0,
670 add_drop_table => $add_drop_table || 0,
671 validate => $validate || 0,
672 parser_args => {
673 'DBIx::Schema' => $schema,
c5f36986 674 },
b0a20454 675 producer_args => {
676 'prefix' => 'My::Schema',
c5f36986 677 },
b0a20454 678 );
679
d240abac 680 $translator->parser('SQL::Translator::Parser::DBIx::Class');
681 $translator->producer('SQL::Translator::Producer::DBIx::Class::File');
b0a20454 682
683 my $output = $translator->translate(@args) or die
684 "Error: " . $translator->error;
685
686 print $output;
687
688You could use L<Module::Find> to search for all subclasses in the MyDB::*
880a1a0c 689namespace, which is currently left as an exercise for the reader.
b0a20454 690
362500af 691=head2 Schema versioning
692
693The following example shows simplistically how you might use DBIx::Class to
694deploy versioned schemas to your customers. The basic process is as follows:
695
da4779ad 696=over 4
697
698=item 1.
699
700Create a DBIx::Class schema
701
702=item 2.
703
704Save the schema
705
706=item 3.
707
708Deploy to customers
709
710=item 4.
711
712Modify schema to change functionality
713
714=item 5.
715
716Deploy update to customers
717
718=back
362500af 719
720=head3 Create a DBIx::Class schema
721
722This can either be done manually, or generated from an existing database as
723described under C<Schema import/export>.
724
725=head3 Save the schema
726
727Use C<sqlt> to transform your schema into an SQL script suitable for your
728customer's database. E.g. for MySQL:
729
54c30987 730 sqlt --from SQL::Translator::Parser::DBIx::Class
362500af 731 --to MySQL
732 --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
733
734If you need to target databases from multiple vendors, just generate an SQL
735script suitable for each. To support PostgreSQL too:
736
54c30987 737 sqlt --from SQL::Translator::DBIx::Class
362500af 738 --to PostgreSQL
739 --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
740
741=head3 Deploy to customers
742
743There are several ways you could deploy your schema. These are probably
744beyond the scope of this recipe, but might include:
745
da4779ad 746=over 4
747
748=item 1.
749
750Require customer to apply manually using their RDBMS.
751
752=item 2.
753
754Package along with your app, making database dump/schema update/tests
362500af 755all part of your install.
756
da4779ad 757=back
758
362500af 759=head3 Modify the schema to change functionality
760
761As your application evolves, it may be necessary to modify your schema to
762change functionality. Once the changes are made to your schema in DBIx::Class,
763export the modified schema as before, taking care not to overwrite the original:
764
54c30987 765 sqlt --from SQL::Translator::DBIx::Class
362500af 766 --to MySQL
767 --DBIx::Class "Anything.pm" > Schema2.mysql.sql
768
769Next, use sqlt-diff to create an SQL script that will update the customer's
770database schema:
771
772 sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
773
774=head3 Deploy update to customers
775
776The schema update can be deployed to customers using the same method as before.
777
7be93b07 778=head2 Setting limit dialect for SQL::Abstract::Limit
779
324572ca 780In some cases, SQL::Abstract::Limit cannot determine the dialect of
781the remote SQL server by looking at the database handle. This is a
782common problem when using the DBD::JDBC, since the DBD-driver only
783know that in has a Java-driver available, not which JDBC driver the
784Java component has loaded. This specifically sets the limit_dialect
785to Microsoft SQL-server (See more names in SQL::Abstract::Limit
786-documentation.
7be93b07 787
788 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
789
324572ca 790The JDBC bridge is one way of getting access to a MSSQL server from a platform
7be93b07 791that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
792
324572ca 793=head2 Setting quoting for the generated SQL.
2437a1e3 794
324572ca 795If the database contains column names with spaces and/or reserved words, they
796need to be quoted in the SQL queries. This is done using:
2437a1e3 797
798 __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
799 __PACKAGE__->storage->sql_maker->name_sep('.');
800
324572ca 801The first sets the quote characters. Either a pair of matching
802brackets, or a C<"> or C<'>:
2437a1e3 803
804 __PACKAGE__->storage->sql_maker->quote_char('"');
805
324572ca 806Check the documentation of your database for the correct quote
807characters to use. C<name_sep> needs to be set to allow the SQL
808generator to put the quotes the correct place.
2437a1e3 809
086b93a2 810=head2 Overloading methods
811
812L<DBIx::Class> uses the L<Class::C3> package, which provides for redispatch of
813method calls. You have to use calls to C<next::method> to overload methods.
814More information on using L<Class::C3> with L<DBIx::Class> can be found in
815L<DBIx::Class::Manual::Component>.
816
817=head3 Changing one field whenever another changes
818
819For example, say that you have three columns, C<id>, C<number>, and
820C<squared>. You would like to make changes to C<number> and have
821C<squared> be automagically set to the value of C<number> squared.
822You can accomplish this by overriding C<store_column>:
823
824 sub store_column {
825 my ( $self, $name, $value ) = @_;
826 if ($name eq 'number') {
827 $self->squared($value * $value);
828 }
829 $self->next::method($name, $value);
830 }
831
832Note that the hard work is done by the call to C<next::method>, which
324572ca 833redispatches your call to store_column in the superclass(es).
086b93a2 834
835=head3 Automatically creating related objects
836
324572ca 837You might have a class C<Artist> which has many C<CD>s. Further, if you
086b93a2 838want to create a C<CD> object every time you insert an C<Artist> object.
ccbebdbc 839You can accomplish this by overriding C<insert> on your objects:
086b93a2 840
841 sub insert {
ccbebdbc 842 my ( $self, @args ) = @_;
843 $self->next::method(@args);
086b93a2 844 $self->cds->new({})->fill_from_artist($self)->insert;
845 return $self;
846 }
847
848where C<fill_from_artist> is a method you specify in C<CD> which sets
849values in C<CD> based on the data in the C<Artist> object you pass in.
850
1def3451 851=head2 Debugging DBIx::Class objects with Data::Dumper
852
853L<Data::Dumper> can be a very useful tool for debugging, but sometimes it can
854be hard to find the pertinent data in all the data it can generate.
855Specifically, if one naively tries to use it like so,
856
857 use Data::Dumper;
858
859 my $cd = $schema->resultset('CD')->find(1);
860 print Dumper($cd);
861
862several pages worth of data from the CD object's schema and result source will
863be dumped to the screen. Since usually one is only interested in a few column
864values of the object, this is not very helpful.
865
866Luckily, it is possible to modify the data before L<Data::Dumper> outputs
867it. Simply define a hook that L<Data::Dumper> will call on the object before
868dumping it. For example,
869
870 package My::DB::CD;
871
872 sub _dumper_hook {
99fb1058 873 $_[0] = bless {
874 %{ $_[0] },
1def3451 875 result_source => undef,
99fb1058 876 }, ref($_[0]);
1def3451 877 }
878
879 [...]
880
881 use Data::Dumper;
882
22139027 883 local $Data::Dumper::Freezer = '_dumper_hook';
1def3451 884
885 my $cd = $schema->resultset('CD')->find(1);
886 print Dumper($cd);
887 # dumps $cd without its ResultSource
888
889If the structure of your schema is such that there is a common base class for
890all your table classes, simply put a method similar to C<_dumper_hook> in the
891base class and set C<$Data::Dumper::Freezer> to its name and L<Data::Dumper>
892will automagically clean up your data before printing it. See
893L<Data::Dumper/EXAMPLES> for more information.
894
1def3451 895=head2 Retrieving a row object's Schema
896
324572ca 897It is possible to get a Schema object from a row object like so:
1def3451 898
899 my $schema = $cd->result_source->schema;
324572ca 900 # use the schema as normal:
901 my $artist_rs = $schema->resultset('Artist');
1def3451 902
903This can be useful when you don't want to pass around a Schema object to every
904method.
905
4c248161 906=head2 Profiling
907
908When you enable L<DBIx::Class::Storage::DBI>'s debugging it prints the SQL
909executed as well as notifications of query completion and transaction
910begin/commit. If you'd like to profile the SQL you can subclass the
911L<DBIx::Class::Storage::Statistics> class and write your own profiling
912mechanism:
913
914 package My::Profiler;
915 use strict;
916
917 use base 'DBIx::Class::Storage::Statistics';
918
919 use Time::HiRes qw(time);
920
921 my $start;
922
923 sub query_start {
924 my $self = shift();
925 my $sql = shift();
926 my $params = @_;
927
928 print "Executing $sql: ".join(', ', @params)."\n";
929 $start = time();
930 }
931
932 sub query_end {
933 my $self = shift();
934 my $sql = shift();
935 my @params = @_;
936
937 printf("Execution took %0.4f seconds.\n", time() - $start);
938 $start = undef;
939 }
940
941 1;
942
943You can then install that class as the debugging object:
944
945 __PACKAGE__->storage()->debugobj(new My::Profiler());
946 __PACKAGE__->storage()->debug(1);
947
948A more complicated example might involve storing each execution of SQL in an
949array:
950
951 sub query_end {
952 my $self = shift();
953 my $sql = shift();
954 my @params = @_;
955
956 my $elapsed = time() - $start;
957 push(@{ $calls{$sql} }, {
958 params => \@params,
959 elapsed => $elapsed
960 });
961 }
962
963You could then create average, high and low execution times for an SQL
964statement and dig down to see if certain parameters cause aberrant behavior.
965
e8e9e5c7 966=head2 Getting the value of the primary key for the last database insert
967
74413b83 968AKA getting last_insert_id
969
e8e9e5c7 970If you are using PK::Auto, this is straightforward:
971
74413b83 972 my $foo = $rs->create(\%blah);
e8e9e5c7 973 # do more stuff
974 my $id = $foo->id; # foo->my_primary_key_field will also work.
975
976If you are not using autoincrementing primary keys, this will probably
977not work, but then you already know the value of the last primary key anyway.
978
824f4422 979=head2 Dynamic Sub-classing DBIx::Class proxy classes
980(AKA multi-class object inflation from one table)
981
324572ca 982L<DBIx::Class> classes are proxy classes, therefore some different
983techniques need to be employed for more than basic subclassing. In
984this example we have a single user table that carries a boolean bit
985for admin. We would like like to give the admin users
986objects(L<DBIx::Class::Row>) the same methods as a regular user but
987also special admin only methods. It doesn't make sense to create two
988seperate proxy-class files for this. We would be copying all the user
989methods into the Admin class. There is a cleaner way to accomplish
990this.
991
c6d147b6 992Overriding the C<inflate_result> method within the User proxy-class
324572ca 993gives us the effect we want. This method is called by
994L<DBIx::Class::ResultSet> when inflating a result from storage. So we
995grab the object being returned, inspect the values we are looking for,
996bless it if it's an admin object, and then return it. See the example
997below:
824f4422 998
999B<Schema Definition>
1000
1001 package DB::Schema;
1002
1003 use base qw/DBIx::Class::Schema/;
1004
1005 __PACKAGE__->load_classes(qw/User/);
1006
1007
1008B<Proxy-Class definitions>
1009
1010 package DB::Schema::User;
1011
1012 use strict;
1013 use warnings;
1014 use base qw/DBIx::Class/;
1015
1016 ### Defined what our admin class is for ensure_class_loaded
1017 my $admin_class = __PACKAGE__ . '::Admin';
1018
324572ca 1019 __PACKAGE__->load_components(qw/Core/);
824f4422 1020
1021 __PACKAGE__->table('users');
1022
1023 __PACKAGE__->add_columns(qw/user_id email password
1024 firstname lastname active
1025 admin/);
1026
1027 __PACKAGE__->set_primary_key('user_id');
1028
1029 sub inflate_result {
1030 my $self = shift;
1031 my $ret = $self->next::method(@_);
1032 if( $ret->admin ) {### If this is an admin rebless for extra functions
1033 $self->ensure_class_loaded( $admin_class );
1034 bless $ret, $admin_class;
1035 }
1036 return $ret;
1037 }
1038
1039 sub hello {
1040 print "I am a regular user.\n";
1041 return ;
1042 }
1043
1044
1045 package DB::Schema::User::Admin;
1046
1047 use strict;
1048 use warnings;
1049 use base qw/DB::Schema::User/;
1050
1051 sub hello
1052 {
1053 print "I am an admin.\n";
1054 return;
1055 }
1056
1057 sub do_admin_stuff
1058 {
1059 print "I am doing admin stuff\n";
1060 return ;
1061 }
1062
1063B<Test File> test.pl
1064
1065 use warnings;
1066 use strict;
1067 use DB::Schema;
1068
1069 my $user_data = { email => 'someguy@place.com',
1070 password => 'pass1',
1071 admin => 0 };
1072
1073 my $admin_data = { email => 'someadmin@adminplace.com',
1074 password => 'pass2',
1075 admin => 1 };
1076
1077 my $schema = DB::Schema->connection('dbi:Pg:dbname=test');
1078
1079 $schema->resultset('User')->create( $user_data );
1080 $schema->resultset('User')->create( $admin_data );
1081
1082 ### Now we search for them
1083 my $user = $schema->resultset('User')->single( $user_data );
1084 my $admin = $schema->resultset('User')->single( $admin_data );
1085
1086 print ref $user, "\n";
1087 print ref $admin, "\n";
1088
1089 print $user->password , "\n"; # pass1
1090 print $admin->password , "\n";# pass2; inherited from User
1091 print $user->hello , "\n";# I am a regular user.
1092 print $admin->hello, "\n";# I am an admin.
1093
1094 ### The statement below will NOT print
1095 print "I can do admin stuff\n" if $user->can('do_admin_stuff');
1096 ### The statement below will print
1097 print "I can do admin stuff\n" if $admin->can('do_admin_stuff');
1098
fe5cf259 1099=head2 Skip object creation for faster results
1100
1101DBIx::Class is not built for speed, it's built for convenience and
1102ease of use, but sometimes you just need to get the data, and skip the
1103fancy objects. Luckily this is also fairly easy using
1104C<inflate_result>:
1105
1106 # Define a class which just returns the results as a hashref:
1107 package My::HashRefInflator;
1108
1109 ## $me is the hashref of cols/data from the immediate resultsource
1110 ## $prefetch is a deep hashref of all the data from the prefetched
1111 ## related sources.
1112
1113 sub mk_hash {
1114 my ($me, $rest) = @_;
1115
1116 return { %$me,
4bbcc5ed 1117 map { ($_ => mk_hash(@{$rest->{$_}})) } keys %$rest
fe5cf259 1118 };
1119 }
1120
1121 sub inflate_result {
1122 my ($self, $source, $me, $prefetch) = @_;
1123 return mk_hash($me, $prefetch);
1124 }
1125
1126 # Change the object inflation to a hashref for just this resultset:
1127 $rs->result_class('My::HashRefInflator');
1128
1129 my $datahashref = $rs->next;
4bbcc5ed 1130 foreach my $col (keys %$datahashref) {
a4482862 1131 if(!ref($datahashref->{$col})) {
fe5cf259 1132 # It's a plain value
1133 }
1134 elsif(ref($datahashref->{$col} eq 'HASH')) {
1135 # It's a related value in a hashref
1136 }
1137 }
1138
9e4c2514 1139=head2 Want to know if find_or_create found or created a row?
1140
1141Just use C<find_or_new> instead, then check C<in_storage>:
fe5cf259 1142
9e4c2514 1143 my $obj = $rs->find_or_new({ blah => 'blarg' });
1144 unless ($obj->in_storage) {
1145 $obj->insert;
1146 # do whatever else you wanted if it was a new row
1147 }
1148
1149=cut