Add missing ) before unless.
[dbsrgits/DBIx-Class.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
bade79c4 75When you only want selected columns from a table, you can use C<cols> to
76specify which ones you need:
faf62551 77
bade79c4 78 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 79 undef,
bade79c4 80 {
5e8b1b2a 81 columns => [qw/ name /]
bade79c4 82 }
83 );
faf62551 84
bade79c4 85 # Equivalent SQL:
86 # SELECT artist.name FROM artist
faf62551 87
bade79c4 88=head3 Using database functions or stored procedures
faf62551 89
bade79c4 90The combination of C<select> and C<as> can be used to return the result of a
91database function or stored procedure as a column value. You use C<select> to
92specify the source for your column value (e.g. a column name, function, or
93stored procedure name). You then use C<as> to set the column name you will use
94to access the returned value:
faf62551 95
bade79c4 96 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 97 undef,
bade79c4 98 {
99 select => [ 'name', { LENGTH => 'name' } ],
100 as => [qw/ name name_length /],
101 }
102 );
faf62551 103
bade79c4 104 # Equivalent SQL:
105 # SELECT name name, LENGTH( name ) name_length
106 # FROM artist
faf62551 107
108If your alias exists as a column in your base class (i.e. it was added with
bade79c4 109C<add_columns>), you just access it as normal. Our C<Artist> class has a C<name>
110column, so we just use the C<name> accessor:
faf62551 111
bade79c4 112 my $artist = $rs->first();
113 my $name = $artist->name();
faf62551 114
115If on the other hand the alias does not correspond to an existing column, you
bade79c4 116can get the value using the C<get_column> accessor:
faf62551 117
bade79c4 118 my $name_length = $artist->get_column('name_length');
faf62551 119
bade79c4 120If you don't like using C<get_column>, you can always create an accessor for
faf62551 121any of your aliases using either of these:
122
bade79c4 123 # Define accessor manually:
124 sub name_length { shift->get_column('name_length'); }
faf62551 125
bade79c4 126 # Or use DBIx::Class::AccessorGroup:
127 __PACKAGE__->mk_group_accessors('column' => 'name_length');
faf62551 128
bade79c4 129=head3 SELECT DISTINCT with multiple columns
faf62551 130
bade79c4 131 my $rs = $schema->resultset('Foo')->search(
5e8b1b2a 132 undef,
bade79c4 133 {
134 select => [
135 { distinct => [ $source->columns ] }
136 ],
137 as => [ $source->columns ]
138 }
139 );
faf62551 140
bade79c4 141=head3 SELECT COUNT(DISTINCT colname)
6607ee1b 142
bade79c4 143 my $rs = $schema->resultset('Foo')->search(
5e8b1b2a 144 undef,
bade79c4 145 {
146 select => [
147 { count => { distinct => 'colname' } }
148 ],
149 as => [ 'count' ]
150 }
151 );
6607ee1b 152
bade79c4 153=head3 Grouping results
154
155L<DBIx::Class> supports C<GROUP BY> as follows:
156
157 my $rs = $schema->resultset('Artist')->search(
5e8b1b2a 158 undef,
bade79c4 159 {
160 join => [qw/ cds /],
161 select => [ 'name', { count => 'cds.cdid' } ],
162 as => [qw/ name cd_count /],
163 group_by => [qw/ name /]
164 }
165 );
6607ee1b 166
bade79c4 167 # Equivalent SQL:
168 # SELECT name, COUNT( cds.cdid ) FROM artist me
169 # LEFT JOIN cd cds ON ( cds.artist = me.artistid )
170 # GROUP BY name
6607ee1b 171
74dc2edc 172=head3 Predefined searches
173
174You can write your own DBIx::Class::ResultSet class by inheriting from it
175and define often used searches as methods:
176
177 package My::DBIC::ResultSet::CD;
178 use strict;
179 use warnings;
180 use base 'DBIx::Class::ResultSet';
181
182 sub search_cds_ordered {
183 my ($self) = @_;
184
185 return $self->search(
186 {},
187 { order_by => 'name DESC' },
188 );
189 }
190
191 1;
192
193To use your resultset, first tell DBIx::Class to create an instance of it
194for you, in your My::DBIC::Schema::CD class:
195
196 __PACKAGE__->resultset_class('My::DBIC::ResultSet::CD');
197
198Then call your new method in your code:
199
200 my $ordered_cds = $schema->resultset('CD')->search_cds_ordered();
201
202
87980de7 203=head2 Using joins and prefetch
204
bade79c4 205You can use the C<join> attribute to allow searching on, or sorting your
206results by, one or more columns in a related table. To return all CDs matching
207a particular artist name:
ea6309e2 208
bade79c4 209 my $rs = $schema->resultset('CD')->search(
210 {
211 'artist.name' => 'Bob Marley'
212 },
213 {
214 join => [qw/artist/], # join the artist table
215 }
216 );
217
218 # Equivalent SQL:
219 # SELECT cd.* FROM cd
220 # JOIN artist ON cd.artist = artist.id
221 # WHERE artist.name = 'Bob Marley'
222
223If required, you can now sort on any column in the related tables by including
224it in your C<order_by> attribute:
225
226 my $rs = $schema->resultset('CD')->search(
227 {
228 'artist.name' => 'Bob Marley'
229 },
230 {
231 join => [qw/ artist /],
232 order_by => [qw/ artist.name /]
233 }
234 };
ea6309e2 235
bade79c4 236 # Equivalent SQL:
237 # SELECT cd.* FROM cd
238 # JOIN artist ON cd.artist = artist.id
239 # WHERE artist.name = 'Bob Marley'
240 # ORDER BY artist.name
ea6309e2 241
bade79c4 242Note that the C<join> attribute should only be used when you need to search or
243sort using columns in a related table. Joining related tables when you only
244need columns from the main table will make performance worse!
ea6309e2 245
bade79c4 246Now let's say you want to display a list of CDs, each with the name of the
247artist. The following will work fine:
ea6309e2 248
bade79c4 249 while (my $cd = $rs->next) {
250 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
251 }
ea6309e2 252
bade79c4 253There is a problem however. We have searched both the C<cd> and C<artist> tables
254in our main query, but we have only returned data from the C<cd> table. To get
255the artist name for any of the CD objects returned, L<DBIx::Class> will go back
256to the database:
ea6309e2 257
bade79c4 258 SELECT artist.* FROM artist WHERE artist.id = ?
ea6309e2 259
260A statement like the one above will run for each and every CD returned by our
261main query. Five CDs, five extra queries. A hundred CDs, one hundred extra
262queries!
263
bade79c4 264Thankfully, L<DBIx::Class> has a C<prefetch> attribute to solve this problem.
897342e4 265This allows you to fetch results from related tables in advance:
ea6309e2 266
bade79c4 267 my $rs = $schema->resultset('CD')->search(
268 {
269 'artist.name' => 'Bob Marley'
270 },
271 {
272 join => [qw/ artist /],
273 order_by => [qw/ artist.name /],
274 prefetch => [qw/ artist /] # return artist data too!
275 }
276 );
ea6309e2 277
bade79c4 278 # Equivalent SQL (note SELECT from both "cd" and "artist"):
279 # SELECT cd.*, artist.* FROM cd
280 # JOIN artist ON cd.artist = artist.id
281 # WHERE artist.name = 'Bob Marley'
282 # ORDER BY artist.name
ea6309e2 283
284The code to print the CD list remains the same:
285
bade79c4 286 while (my $cd = $rs->next) {
287 print "CD: " . $cd->title . ", Artist: " . $cd->artist->name;
288 }
ea6309e2 289
bade79c4 290L<DBIx::Class> has now prefetched all matching data from the C<artist> table,
ea6309e2 291so no additional SQL statements are executed. You now have a much more
292efficient query.
293
bade79c4 294Note that as of L<DBIx::Class> 0.04, C<prefetch> cannot be used with
295C<has_many> relationships. You will get an error along the lines of "No
296accessor for prefetched ..." if you try.
ea6309e2 297
bade79c4 298Also note that C<prefetch> should only be used when you know you will
ea6309e2 299definitely use data from a related table. Pre-fetching related tables when you
300only need columns from the main table will make performance worse!
301
bade79c4 302=head3 Multi-step joins
ea6309e2 303
304Sometimes you want to join more than one relationship deep. In this example,
bade79c4 305we want to find all C<Artist> objects who have C<CD>s whose C<LinerNotes>
306contain a specific string:
307
308 # Relationships defined elsewhere:
309 # Artist->has_many('cds' => 'CD', 'artist');
310 # CD->has_one('liner_notes' => 'LinerNotes', 'cd');
311
312 my $rs = $schema->resultset('Artist')->search(
313 {
314 'liner_notes.notes' => { 'like', '%some text%' },
315 },
316 {
317 join => {
318 'cds' => 'liner_notes'
319 }
320 }
321 );
ea6309e2 322
bade79c4 323 # Equivalent SQL:
324 # SELECT artist.* FROM artist
325 # JOIN ( cd ON artist.id = cd.artist )
326 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
327 # WHERE liner_notes.notes LIKE '%some text%'
ea6309e2 328
329Joins can be nested to an arbitrary level. So if we decide later that we
330want to reduce the number of Artists returned based on who wrote the liner
331notes:
332
bade79c4 333 # Relationship defined elsewhere:
334 # LinerNotes->belongs_to('author' => 'Person');
335
336 my $rs = $schema->resultset('Artist')->search(
337 {
338 'liner_notes.notes' => { 'like', '%some text%' },
339 'author.name' => 'A. Writer'
340 },
341 {
342 join => {
343 'cds' => {
344 'liner_notes' => 'author'
ea6309e2 345 }
bade79c4 346 }
347 }
348 );
ea6309e2 349
bade79c4 350 # Equivalent SQL:
351 # SELECT artist.* FROM artist
352 # JOIN ( cd ON artist.id = cd.artist )
353 # JOIN ( liner_notes ON cd.id = liner_notes.cd )
354 # JOIN ( author ON author.id = liner_notes.author )
355 # WHERE liner_notes.notes LIKE '%some text%'
356 # AND author.name = 'A. Writer'
87980de7 357
897342e4 358=head2 Multi-step prefetch
359
360From 0.04999_05 onwards, C<prefetch> can be nested more than one relationship
361deep using the same syntax as a multi-step join:
362
363 my $rs = $schema->resultset('Tag')->search(
5e8b1b2a 364 undef,
897342e4 365 {
366 prefetch => {
367 cd => 'artist'
368 }
369 }
370 );
371
372 # Equivalent SQL:
373 # SELECT tag.*, cd.*, artist.* FROM tag
374 # JOIN cd ON tag.cd = cd.cdid
375 # JOIN artist ON cd.artist = artist.artistid
376
377Now accessing our C<cd> and C<artist> relationships does not need additional
378SQL statements:
379
380 my $tag = $rs->first;
381 print $tag->cd->artist->name;
382
87980de7 383=head2 Transactions
384
385As of version 0.04001, there is improved transaction support in
181a28f4 386L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>. Here is an
387example of the recommended way to use it:
87980de7 388
181a28f4 389 my $genus = $schema->resultset('Genus')->find(12);
390
391 my $coderef1 = sub {
392 my ($schema, $genus, $code) = @_;
35d4fe78 393 $genus->add_to_species({ name => 'troglodyte' });
394 $genus->wings(2);
395 $genus->update;
880a1a0c 396 $schema->txn_do($code, $genus); # Can have a nested transaction
181a28f4 397 return $genus->species;
398 };
399
400 my $coderef2 = sub {
401 my ($genus) = @_;
402 $genus->extinct(1);
403 $genus->update;
35d4fe78 404 };
181a28f4 405
406 my $rs;
407 eval {
408 $rs = $schema->txn_do($coderef1, $schema, $genus, $coderef2);
409 };
410
411 if ($@) { # Transaction failed
412 die "the sky is falling!" #
413 if ($@ =~ /Rollback failed/); # Rollback failed
414
415 deal_with_failed_transaction();
35d4fe78 416 }
87980de7 417
181a28f4 418Nested transactions will work as expected. That is, only the outermost
419transaction will actually issue a commit to the $dbh, and a rollback
420at any level of any transaction will cause the entire nested
421transaction to fail. Support for savepoints and for true nested
40dbc108 422transactions (for databases that support them) will hopefully be added
423in the future.
ee38fa40 424
130c6439 425=head2 Many-to-many relationships
ee38fa40 426
ea6309e2 427This is straightforward using L<DBIx::Class::Relationship::ManyToMany>:
428
bade79c4 429 package My::DB;
430 # ... set up connection ...
431
432 package My::User;
433 use base 'My::DB';
434 __PACKAGE__->table('user');
435 __PACKAGE__->add_columns(qw/id name/);
436 __PACKAGE__->set_primary_key('id');
437 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'user');
438 __PACKAGE__->many_to_many('addresses' => 'user_address', 'address');
439
440 package My::UserAddress;
441 use base 'My::DB';
442 __PACKAGE__->table('user_address');
443 __PACKAGE__->add_columns(qw/user address/);
444 __PACKAGE__->set_primary_key(qw/user address/);
445 __PACKAGE__->belongs_to('user' => 'My::User');
446 __PACKAGE__->belongs_to('address' => 'My::Address');
447
448 package My::Address;
449 use base 'My::DB';
450 __PACKAGE__->table('address');
451 __PACKAGE__->add_columns(qw/id street town area_code country/);
452 __PACKAGE__->set_primary_key('id');
453 __PACKAGE__->has_many('user_address' => 'My::UserAddress', 'address');
454 __PACKAGE__->many_to_many('users' => 'user_address', 'user');
455
456 $rs = $user->addresses(); # get all addresses for a user
457 $rs = $address->users(); # get all users for an address
458
459=head2 Setting default values for a row
a00e1684 460
35d4fe78 461It's as simple as overriding the C<new> method. Note the use of
40dbc108 462C<next::method>.
a00e1684 463
35d4fe78 464 sub new {
465 my ( $class, $attrs ) = @_;
40dbc108 466
35d4fe78 467 $attrs->{foo} = 'bar' unless defined $attrs->{foo};
40dbc108 468
35d4fe78 469 $class->next::method($attrs);
470 }
a00e1684 471
25af00d7 472=head2 Stringification
473
40dbc108 474Employ the standard stringification technique by using the C<overload>
35d4fe78 475module. Replace C<foo> with the column/method of your choice.
25af00d7 476
35d4fe78 477 use overload '""' => 'foo', fallback => 1;
25af00d7 478
bade79c4 479=head2 Disconnecting cleanly
480
481If you find yourself quitting an app with Control-C a lot during
482development, you might like to put the following signal handler in
483your main database class to make sure it disconnects cleanly:
484
485 $SIG{INT} = sub {
6d1bf0a9 486 __PACKAGE__->storage->disconnect;
bade79c4 487 };
488
362500af 489=head2 Schema import/export
490
491This functionality requires you to have L<SQL::Translator> (also known as
492"SQL Fairy") installed.
493
494To create a DBIx::Class schema from an existing database:
495
496 sqlt --from DBI
497 --to DBIx::Class::File
498 --prefix "MySchema" > MySchema.pm
499
500To create a MySQL database from an existing L<DBIx::Class> schema, convert the
501schema to MySQL's dialect of SQL:
502
503 sqlt --from DBIx::Class --to MySQL --DBIx::Class "MySchema.pm" > Schema1.sql
504
505And import using the mysql client:
506
507 mysql -h "host" -D "database" -u "user" -p < Schema1.sql
508
b0a20454 509=head2 Easy migration from class-based to schema-based setup
510
511You want to start using the schema-based approach to L<DBIx::Class>
512(see L<SchemaIntro.pod>), but have an established class-based setup with lots
513of existing classes that you don't want to move by hand. Try this nifty script
514instead:
515
516 use MyDB;
517 use SQL::Translator;
518
519 my $schema = MyDB->schema_instance;
520
521 my $translator = SQL::Translator->new(
522 debug => $debug || 0,
523 trace => $trace || 0,
524 no_comments => $no_comments || 0,
525 show_warnings => $show_warnings || 0,
526 add_drop_table => $add_drop_table || 0,
527 validate => $validate || 0,
528 parser_args => {
529 'DBIx::Schema' => $schema,
c5f36986 530 },
b0a20454 531 producer_args => {
532 'prefix' => 'My::Schema',
c5f36986 533 },
b0a20454 534 );
535
536 $translator->parser('DBIx::Class');
537 $translator->producer('DBIx::Class::File');
538
539 my $output = $translator->translate(@args) or die
540 "Error: " . $translator->error;
541
542 print $output;
543
544You could use L<Module::Find> to search for all subclasses in the MyDB::*
880a1a0c 545namespace, which is currently left as an exercise for the reader.
b0a20454 546
362500af 547=head2 Schema versioning
548
549The following example shows simplistically how you might use DBIx::Class to
550deploy versioned schemas to your customers. The basic process is as follows:
551
da4779ad 552=over 4
553
554=item 1.
555
556Create a DBIx::Class schema
557
558=item 2.
559
560Save the schema
561
562=item 3.
563
564Deploy to customers
565
566=item 4.
567
568Modify schema to change functionality
569
570=item 5.
571
572Deploy update to customers
573
574=back
362500af 575
576=head3 Create a DBIx::Class schema
577
578This can either be done manually, or generated from an existing database as
579described under C<Schema import/export>.
580
581=head3 Save the schema
582
583Use C<sqlt> to transform your schema into an SQL script suitable for your
584customer's database. E.g. for MySQL:
585
586 sqlt --from DBIx::Class
587 --to MySQL
588 --DBIx::Class "MySchema.pm" > Schema1.mysql.sql
589
590If you need to target databases from multiple vendors, just generate an SQL
591script suitable for each. To support PostgreSQL too:
592
593 sqlt --from DBIx::Class
594 --to PostgreSQL
595 --DBIx::Class "MySchema.pm" > Schema1.pgsql.sql
596
597=head3 Deploy to customers
598
599There are several ways you could deploy your schema. These are probably
600beyond the scope of this recipe, but might include:
601
da4779ad 602=over 4
603
604=item 1.
605
606Require customer to apply manually using their RDBMS.
607
608=item 2.
609
610Package along with your app, making database dump/schema update/tests
362500af 611all part of your install.
612
da4779ad 613=back
614
362500af 615=head3 Modify the schema to change functionality
616
617As your application evolves, it may be necessary to modify your schema to
618change functionality. Once the changes are made to your schema in DBIx::Class,
619export the modified schema as before, taking care not to overwrite the original:
620
621 sqlt --from DBIx::Class
622 --to MySQL
623 --DBIx::Class "Anything.pm" > Schema2.mysql.sql
624
625Next, use sqlt-diff to create an SQL script that will update the customer's
626database schema:
627
628 sqlt-diff --to MySQL Schema1=MySQL Schema2=MySQL > SchemaUpdate.mysql.sql
629
630=head3 Deploy update to customers
631
632The schema update can be deployed to customers using the same method as before.
633
7be93b07 634=head2 Setting limit dialect for SQL::Abstract::Limit
635
636In some cases, SQL::Abstract::Limit cannot determine the dialect of the remote
637SQL-server by looking at the database-handle. This is a common problem when
638using the DBD::JDBC, since the DBD-driver only know that in has a Java-driver
639available, not which JDBC-driver the Java component has loaded.
640This specifically sets the limit_dialect to Microsoft SQL-server (Se more names
641in SQL::Abstract::Limit -documentation.
642
643 __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
644
645The JDBC-bridge is one way of getting access to a MSSQL-server from a platform
646that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
647
2437a1e3 648=head2 Setting quotes for the generated SQL.
649
650If the database contains columnames with spaces and/or reserved words, the
651SQL-query needs to be quoted. This is done using:
652
653 __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
654 __PACKAGE__->storage->sql_maker->name_sep('.');
655
656The first sets the quotesymbols. If the quote i "symmetric" as " or '
657
658 __PACKAGE__->storage->sql_maker->quote_char('"');
659
880a1a0c 660is enough. If the left quote differs form the right quote, the first
2437a1e3 661notation should be used. name_sep needs to be set to allow the
662SQL generator to put the quotes the correct place.
663
40dbc108 664=cut