Drop DBI requirement down to 1.57
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Manual / Features.pod
CommitLineData
9ba33dac 1=head1 NAME
2
3DBIx::Class::Manual::Features - A boatload of DBIx::Class features with links to respective documentation
4
5=head1 META
6
7=head2 Large Community
8
9Currently there are 88 people listed as contributors to DBIC. That ranges
10from documentation help, to test help, to added features, to entire database
11support.
12
13=head2 Active Community
14
f165eda8 15Currently (June 9, 2010) 6 active branches (committed to
9ba33dac 16in the last two weeks) in git. Last release (0.08122)
17had 14 new features, and 16 bug fixes. Of course that
18L<ebbs and flows|http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git;a=blob;f=Changes>.)
19
20=head2 Responsive Community
21
22=over 1
23
24=item I needed MSSQL order-by support; the community helped me add support
25
26=item generally very welcoming of people willing to help
27
28=back
29
30=head1 General ORM
31
32These are things that are in most other ORMs, but are still reasons to use
33DBIC over raw SQL.
34
35=head2 Cross DB
36
37The vast majority of code should run on all databases without needing tweaking
38
39=head2 Basic CRUD
40
41=over 1
42
43=item C - Create
44
45=item R - Retrieve
46
47=item U - Update
48
49=item D - Delete
50
51=back
52
53=head2 SQL: Create
54
55 my $sth = $dbh->prepare('
56 INSERT INTO books
57 (title, author_id)
58 values (?,?)
59 ');
60
61 $sth->execute( 'A book title', $author_id );
62
63=head2 DBIC: Create
64
65 my $book = $book_rs->create({
66 title => 'A book title',
67 author_id => $author_id,
68 });
69
70See L<DBIx::Class::ResultSet/create>
71
72=over 1
73
74=item No need to pair placeholders and values
75
76=item Automatically gets autoincremented id for you
77
78=item Transparently uses INSERT ... RETURNING for databases that support it
79
80=back
81
82=head2 SQL: Read
83
84 my $sth = $dbh->prepare('
85 SELECT title,
86 authors.name as author_name
87 FROM books, authors
88 WHERE books.author = authors.id
89 ');
90
91 while ( my $book = $sth->fetchrow_hashref ) {
92 say "Author of $book->{title} is $book->{author_name}";
93 }
94
95=head2 DBIC: Read
96
97 my $book = $book_rs->find($book_id);
98
99or
100
101 my $book = $book_rs->search({ title => 'A book title' }, { rows => 1 })->next;
102
103or
104
105 my @books = $book_rs->search({ author => $author_id })->all;
106
107or
108
109 while( my $book = $books_rs->next ) {
110 printf "Author of %s is %s\n", $book->title, $book->author->name;
111 }
112
113See L<DBIx::Class::ResultSet/find>, L<DBIx::Class::ResultSet/search>, L<DBIx::Class::ResultSet/next>, and L<DBIx::Class::ResultSet/all>
114
115B<TMTOWTDI!>
116
117=head2 SQL: Update
118
119 my $update = $dbh->prepare('
120 UPDATE books
121 SET title = ?
122 WHERE id = ?
123 ');
124
125 $update->execute( 'New title', $book_id );
126
127=head2 DBIC: Update
128
129 $book->update({ title => 'New title' });
130
131See L<DBIx::Class::Row/update>
132
133Will not update unless value changes
134
135=head2 SQL: Delete
136
137 my $delete = $dbh->prepare('DELETE FROM books WHERE id = ?');
138
139 $delete->execute($book_id);
140
141=head2 DBIC: Delete
142
143 $book->delete
144
145See L<DBIx::Class::Row/delete>
146
147=head2 SQL: Search
148
149 my $sth = $dbh->prepare('
150 SELECT title,
151 authors.name as author_name
152 FROM books
153 WHERE books.name LIKE "%monte cristo%" AND
154 books.topic = "jailbreak"
155 ');
156
157=head2 DBIC: Search
158
159 my $book = $book_rs->search({
160 'me.name' => { -like => '%monte cristo%' },
161 'me.topic' => 'jailbreak',
162 })->next;
163
164=over 1
165
166=item See L<SQL::Abstract>, L<DBIx::Class::ResultSet/next>, and L<DBIx::Class::ResultSet/search>
167
168=item (kinda) introspectible
169
170=item Prettier than SQL
171
172=back
173
4d1e63f4 174=head2 OO Overridability
9ba33dac 175
176=over 1
177
178=item Override new if you want to do validation
179
180=item Override delete if you want to disable deletion
181
182=item and on and on
183
184=back
185
186=head2 Convenience Methods
187
188=over 1
189
190=item L<DBIx::Class::ResultSet/find_or_create>
191
192=item L<DBIx::Class::ResultSet/update_or_create>
193
194=back
195
196=head2 Non-column methods
197
198Need a method to get a user's gravatar URL? Add a C<gravatar_url> method to the
199Result class
200
201=head2 RELATIONSHIPS
202
203=over 1
204
205=item L<DBIx::Class::Relationship/belongs_to>
206
207=item L<DBIx::Class::Relationship/has_many>
208
209=item L<DBIx::Class::Relationship/might_have>
210
211=item L<DBIx::Class::Relationship/has_one>
212
213=item L<DBIx::Class::Relationship/many_to_many>
214
215=item SET AND FORGET
216
217=back
218
219=head1 DBIx::Class Specific Features
220
221These things may be in other ORM's, but they are very specific, so doubtful
222
223=head2 ->deploy
224
225Create a database from your DBIx::Class schema.
226
227 my $schema = Frew::Schema->connect( $dsn, $user, $pass );
228
229 $schema->deploy
230
231See L<DBIx::Class::Schema/deploy>.
232
233See also: L<DBIx::Class::DeploymentHandler>
234
235=head2 Schema::Loader
236
237Create a DBIx::Class schema from your database.
238
239 package Frew::Schema;
240
241 use strict;
242 use warnings;
243
244 use base 'DBIx::Class::Schema::Loader';
245
246 __PACKAGE__->loader_options({
247 naming => 'v7',
248 debug => $ENV{DBIC_TRACE},
249 });
250
251 1;
252
253 # elsewhere...
254
255 my $schema = Frew::Schema->connect( $dsn, $user, $pass );
256
257See L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base/CONSTRUCTOR_OPTIONS>.
258
259=head2 Populate
260
261Made for inserting lots of rows very quicky into database
262
263 $schema->populate([ Users =>
264 [qw( username password )],
265 [qw( frew >=4char$ )],
266 [qw( ... )],
267 [qw( ... )],
268 );
269
270See L<DBIx::Class::Schema/populate>
271
272I use populate L<here|http://blog.afoolishmanifesto.com/archives/1255> to export our whole
273(200M~) db to SQLite
274
275=head2 Multicreate
276
277Create an object and it's related objects all at once
278
279 $schema->resultset('Author')->create({
280 name => 'Stephen King',
281 books => [{ title => 'The Dark Tower' }],
282 address => {
283 street => '123 Turtle Back Lane',
284 state => { abbreviation => 'ME' },
285 city => { name => 'Lowell' },
286 },
287 });
288
289See L<DBIx::Class::ResultSet/create>
290
291=over 1
292
293=item books is a has_many
294
295=item address is a belongs_to which in turn belongs to state and city each
296
297=item for this to work right state and city must mark abbreviation and name as unique
298
299=back
300
301=head2 Extensible
302
303DBIx::Class helped pioneer fast MI in Perl 5 with Class::C3, so it is made to
304allow extensions to nearly every part of it.
305
306=head2 Extensibility example: DBIx::Class::Helpers
307
308=over 1
309
310=item L<DBIx::Class::Helper::ResultSet::IgnoreWantarray>
311
312=item L<DBIx::Class::Helper::ResultSet::Random>
313
314=item L<DBIx::Class::Helper::ResultSet::SetOperations>
315
316=item L<DBIx::Class::Helper::Row::JoinTable>
317
318=item L<DBIx::Class::Helper::Row::NumifyGet>
319
320=item L<DBIx::Class::Helper::Row::SubClass>
321
322=item L<DBIx::Class::Helper::Row::ToJSON>
323
324=item L<DBIx::Class::Helper::Row::StorageValues>
325
326=item L<DBIx::Class::Helper::Row::OnColumnChange>
327
328=back
329
330=head2 Extensibility example: DBIx::Class::TimeStamp
331
332=over 1
333
334=item See L<DBIx::Class::TimeStamp>
335
336=item Cross DB
337
338=item set_on_create
339
340=item set_on_update
341
342=back
343
344=head2 Extensibility example: Kioku
345
346=over 1
347
348=item See L<DBIx::Class::Schema::KiokuDB>
349
350=item Kioku is the new hotness
351
352=item Mix RDBMS with Object DB
353
354=back
355
356=head2 Result vs ResultSet
357
358=over 1
359
360=item Result == Row
361
362=item ResultSet == Query Plan
363
364=over 1
365
366=item Internal Join Optimizer for all DB's (!!!)
367
368=back
369
370=item (less important but...)
371
372=item ResultSource == Queryable collection of rows (Table, View, etc)
373
374=item Storage == Database
375
376=item Schema == associates a set of ResultSources with a Storage
377
378=back
379
380=head2 ResultSet methods
381
382 package MyApp::Schema::ResultSet::Book;
383
384 use strict;
385 use warnings;
386
387 use base 'DBIx::Class::ResultSet';
388
389 sub good {
390 my $self = shift;
391 $self->search({
392 $self->current_source_alias . '.rating' => { '>=' => 4 }
393 })
394 };
395
396 sub cheap {
397 my $self = shift;
398 $self->search({
399 $self->current_source_alias . '.price' => { '<=' => 5}
400 })
401 };
402
403 # ...
404
405 1;
406
407See L<DBIx::Class::Manual::Cookbook/Predefined searches>
408
409=over 1
410
411=item All searches should be ResultSet methods
412
413=item Name has obvious meaning
414
415=item L<DBIx::Class::ResultSet/current_source_alias> helps things to work no matter what
416
417=back
418
419=head2 ResultSet method in Action
420
421 $schema->resultset('Book')->good
422
423=head2 ResultSet Chaining
424
425 $schema->resultset('Book')
426 ->good
427 ->cheap
428 ->recent
429
430=head2 search_related
431
432 my $score = $schema->resultset('User')
433 ->search({'me.userid' => 'frew'})
434 ->related_resultset('access')
435 ->related_resultset('mgmt')
436 ->related_resultset('orders')
437 ->telephone
438 ->search_related( shops => {
439 'shops.datecompleted' => {
440 -between => ['2009-10-01','2009-10-08']
441 }
442 })->completed
443 ->related_resultset('rpt_score')
444 ->search(undef, { rows => 1})
445 ->get_column('raw_scores')
446 ->next;
447
448The SQL that this produces (with placeholders filled in for clarity's sake)
449on our system (Microsoft SQL) is:
450
451 SELECT raw_scores
452 FROM (
453 SELECT raw_scores, ROW_NUMBER() OVER (
454 ORDER BY (
455 SELECT (1)
456 )
457 ) AS rno__row__index
458 FROM (
459 SELECT rpt_score.raw_scores
460 FROM users me
461 JOIN access access
462 ON access.userid = me.userid
463 JOIN mgmt mgmt
464 ON mgmt.mgmtid = access.mgmtid
465 JOIN [order] orders
466 ON orders.mgmtid = mgmt.mgmtid
467 JOIN shop shops
468 ON shops.orderno = orders.orderno
469 JOIN rpt_scores rpt_score
470 ON rpt_score.shopno = shops.shopno
471 WHERE (
472 datecompleted IS NOT NULL AND
473 (
474 (shops.datecompleted BETWEEN '2009-10-01' AND '2009-10-08') AND
475 (type = '1' AND me.userid = 'frew')
476 )
477 )
478 ) rpt_score
479 ) rpt_score
480 WHERE rno__row__index BETWEEN 1 AND 1
481
482See: L<DBIx::Class::ResultSet/related_resultset>, L<DBIx::ClassResultSet/search_related>, and L<DBIx::Class::ResultSet/get_column>.
483
484=head2 bonus rel methods
485
486 my $book = $author->create_related(
487 books => {
488 title => 'Another Discworld book',
489 }
490 );
491
492 my $book2 = $pratchett->add_to_books({
493 title => 'MOAR Discworld book',
494 });
495
496See L<DBIx::Class::Relationship::Base/create_related> and L<DBIx::Class::Relationship::Base/add_to_$rel>
497
f165eda8 498Note that it automatically fills in foreign key for you
9ba33dac 499
500=head2 Excellent Transaction Support
501
502 $schema->txn_do(sub {
503 ...
504 });
505
506 $schema->txn_begin; # <-- low level
507 # ...
508 $schema->txn_commit;
509
510See L<DBIx::Class::Schema/txn_do>, L<DBIx::Class::Schema/txn_begin>,
511and L<DBIx::Class::Schema/txn_commit>.
512
513=head2 InflateColumn
514
515 package Frew::Schema::Result::Book;
516
517 use strict;
518 use warnings;
519
520 use base 'DBIx::Class::Core';
521
522 use DateTime::Format::MySQL;
523
524 # Result code here
525
526 __PACKAGE__->load_components('InflateColumn');
527
528 __PACKAGE__->inflate_column(
529 date_published => {
530 inflate => sub { DateTime::Format::MySQL->parse_date( shift ) },
531 deflate => sub { shift->ymd },
532 },
533 );
534
535See L<DBIx::Class::InflateColumn>, L<DBIx::Class::InflateColumn/inflate_column>, and
536L<DBIx::Class::InflateColumn::DateTime>.
537
538=head2 InflateColumn: deflation
539
540 $book->date_published(DateTime->now);
541 $book->update;
542
543=head2 InflateColumn: inflation
544
545 say $book->date_published->month_abbr; # Nov
546
547=head2 FilterColumn
548
549 package Frew::Schema::Result::Book;
550
551 use strict;
552 use warnings;
553
554 use base 'DBIx::Class::Core';
555
556 # Result code here
557
558 __PACKAGE__->load_components('FilterColumn');
559
560 __PACKAGE__->filter_column(
561 length => {
562 to_storage => 'to_metric',
563 from_storage => 'to_imperial',
564 },
565 );
566
567 sub to_metric { $_[1] * .305 }
568 sub to_imperial { $_[1] * 3.28 }
569
570See L<DBIx::Class::FilterColumn> and L<DBIx::Class::FilterColumn/filter_column>
571
572=head2 ResultSetColumn
573
574 my $rsc = $schema->resultset('Book')->get_column('price');
575 $rsc->first;
576 $rsc->all;
577 $rsc->min;
578 $rsc->max;
579 $rsc->sum;
580
581See L<DBIx::Class::ResultSetColumn>
582
583=head2 Aggregates
584
585 my @res = $rs->search(undef, {
586 select => [
587 'price',
588 'genre',
589 { max => price },
590 { avg => price },
591 ],
592 as => [
593 qw(price genre max_price avg_price)
594 ],
595 group_by => [qw(price genre)],
596 });
597 for (@res) {
598 say $_->price . ' ' . $_->genre;
599 say $_->get_column('max_price');
a9e8284f 600 say $_->get_column('avg_price');
9ba33dac 601 }
602
603See L<DBIx::Class::ResultSet/select>, L<DBIx::Class::ResultSet/as>, and
604L<DBIx::Class::ResultSet/group_by>
605
606=over 1
607
608=item Careful, get_column can basicaly mean B<three> things
609
610=item private in which case you should use an accessor
611
612=item public for what there is no accessor for
613
614=item public for get resultset column (prev example)
615
616=back
617
618=head2 HRI
619
620 $rs->search(undef, {
621 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
622 });
623
624See L<DBIx::Class::ResultSet/result_class> and L<DBIx::Class::ResultClass::HashRefInflator>.
625
626=over 1
627
628=item Easy on memory
629
630=item Mega fast
631
632=item Great for quick debugging
633
634=item Great for performance tuning (we went from 2m to < 3s)
635
636=back
637
638=head2 Subquery Support
639
640 my $inner_query = $schema->resultset('Artist')
641 ->search({
642 name => [ 'Billy Joel', 'Brittany Spears' ],
643 })->get_column('id')->as_query;
644
645 my $rs = $schema->resultset('CD')->search({
646 artist_id => { -in => $inner_query },
647 });
648
f165eda8 649See L<DBIx::Class::Manual::Cookbook/Subqueries>
9ba33dac 650
651=head2 Bare SQL w/ Placeholders
652
653 $rs->update({
654 # !!! SQL INJECTION VECTOR
655 price => \"price + $inc", # DON'T DO THIS
656 });
657
658Better:
659
660 $rs->update({
661 price => \['price + ?', [inc => $inc]],
662 });
663
f165eda8 664See L<SQL::Abstract/Literal_SQL_with_placeholders_and_bind_values_(subqueries)>
9ba33dac 665