A massive amount of link fixes (just links, almost no rewording)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Manual / Features.pod
1 =head1 NAME
2
3 DBIx::Class::Manual::Features - A boatload of DBIx::Class features with links to respective documentation
4
5 =head1 META
6
7 =head2 Large Community
8
9 Currently there are 88 people listed as contributors to DBIC.  That ranges
10 from documentation help, to test help, to added features, to entire database
11 support.
12
13 =head2 Active Community
14
15 Currently (June 9, 2010) 6 active branches (committed to
16 in the last two weeks) in git.  Last release (0.08122)
17 had 14 new features, and 16 bug fixes.  Of course that
18 L<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
32 These are things that are in most other ORMs, but are still reasons to use
33 DBIC over raw SQL.
34
35 =head2 Cross DB
36
37 The 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
70 See 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
99 or
100
101  my $book = $book_rs->search({ title => 'A book title' }, { rows => 1 })->next;
102
103 or
104
105  my @books = $book_rs->search({ author => $author_id })->all;
106
107 or
108
109  while( my $book = $books_rs->next ) {
110    printf "Author of %s is %s\n", $book->title, $book->author->name;
111  }
112
113 See L<DBIx::Class::ResultSet/find>, L<DBIx::Class::ResultSet/search>, L<DBIx::Class::ResultSet/next>, and L<DBIx::Class::ResultSet/all>
114
115 B<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
131 See L<DBIx::Class::Row/update>
132
133 Will 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
145 See 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
174 =head2 OO Overridability
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
198 Need a method to get a user's gravatar URL?  Add a C<gravatar_url> method to the
199 Result 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
221 These things may be in other ORM's, but they are very specific, so doubtful
222
223 =head2 ->deploy
224
225 Create a database from your DBIx::Class schema.
226
227  my $schema = Frew::Schema->connect( $dsn, $user, $pass );
228
229  $schema->deploy
230
231 See L<DBIx::Class::Schema/deploy>.
232
233 See also: L<DBIx::Class::DeploymentHandler>
234
235 =head2 Schema::Loader
236
237 Create 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
257 See L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base/CONSTRUCTOR OPTIONS>.
258
259 =head2 Populate
260
261 Made for inserting lots of rows very quickly into database
262
263  $schema->populate([ Users =>
264     [qw( username password )],
265     [qw( frew     >=4char$ )],
266     [qw(      ...          )],
267     [qw(      ...          )],
268  );
269
270 See L<DBIx::Class::Schema/populate>
271
272 I use populate L<here|http://blog.afoolishmanifesto.com/archives/1255> to export our whole
273 (200M~) db to SQLite
274
275 =head2 Multicreate
276
277 Create an object and its 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
289 See 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
303 DBIx::Class helped pioneer fast MI in Perl 5 with Class::C3, so it is made to
304 allow 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
407 See 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
448 The SQL that this produces (with placeholders filled in for clarity's sake)
449 on 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
482 See: L<DBIx::Class::ResultSet/related_resultset>,
483 L<DBIx::Class::ResultSet/search_related>, and
484 L<DBIx::Class::ResultSet/get_column>.
485
486 =head2 bonus rel methods
487
488  my $book = $author->create_related(
489     books => {
490        title => 'Another Discworld book',
491     }
492  );
493
494  my $book2 = $pratchett->add_to_books({
495     title => 'MOAR Discworld book',
496  });
497
498 See L<DBIx::Class::Relationship::Base/create_related> and L<DBIx::Class::Relationship::Base/add_to_$rel>
499
500 Note that it automatically fills in foreign key for you
501
502 =head2 Excellent Transaction Support
503
504  $schema->txn_do(sub {
505     ...
506  });
507
508  $schema->txn_begin; # <-- low level
509  # ...
510  $schema->txn_commit;
511
512 See L<DBIx::Class::Schema/txn_do>, L<DBIx::Class::Schema/txn_begin>,
513 and L<DBIx::Class::Schema/txn_commit>.
514
515 =head2 InflateColumn
516
517  package Frew::Schema::Result::Book;
518
519  use strict;
520  use warnings;
521
522  use base 'DBIx::Class::Core';
523
524  use DateTime::Format::MySQL;
525
526  # Result code here
527
528  __PACKAGE__->load_components('InflateColumn');
529
530  __PACKAGE__->inflate_column(
531     date_published => {
532        inflate => sub { DateTime::Format::MySQL->parse_date( shift ) },
533        deflate => sub { shift->ymd },
534     },
535  );
536
537 See L<DBIx::Class::InflateColumn>, L<DBIx::Class::InflateColumn/inflate_column>, and
538 L<DBIx::Class::InflateColumn::DateTime>.
539
540 =head2 InflateColumn: deflation
541
542  $book->date_published(DateTime->now);
543  $book->update;
544
545 =head2 InflateColumn: inflation
546
547  say $book->date_published->month_abbr; # Nov
548
549 =head2 FilterColumn
550
551  package Frew::Schema::Result::Book;
552
553  use strict;
554  use warnings;
555
556  use base 'DBIx::Class::Core';
557
558  # Result code here
559
560  __PACKAGE__->load_components('FilterColumn');
561
562  __PACKAGE__->filter_column(
563     length => {
564        to_storage   => 'to_metric',
565        from_storage => 'to_imperial',
566     },
567  );
568
569  sub to_metric   { $_[1] * .305 }
570  sub to_imperial { $_[1] * 3.28 }
571
572 See L<DBIx::Class::FilterColumn> and L<DBIx::Class::FilterColumn/filter_column>
573
574 =head2 ResultSetColumn
575
576  my $rsc = $schema->resultset('Book')->get_column('price');
577  $rsc->first;
578  $rsc->all;
579  $rsc->min;
580  $rsc->max;
581  $rsc->sum;
582
583 See L<DBIx::Class::ResultSetColumn>
584
585 =head2 Aggregates
586
587  my @res = $rs->search(undef, {
588     select   => [
589        'price',
590        'genre',
591        { max => price },
592        { avg => price },
593     ],
594     as       => [
595        qw(price genre max_price avg_price)
596     ],
597     group_by => [qw(price genre)],
598  });
599  for (@res) {
600     say $_->price . ' ' . $_->genre;
601     say $_->get_column('max_price');
602     say $_->get_column('avg_price');
603  }
604
605 See L<DBIx::Class::ResultSet/select>, L<DBIx::Class::ResultSet/as>, and
606 L<DBIx::Class::ResultSet/group_by>
607
608 =over 1
609
610 =item Careful, get_column can basically mean B<three> things
611
612 =item private in which case you should use an accessor
613
614 =item public for what there is no accessor for
615
616 =item public for get resultset column (prev example)
617
618 =back
619
620 =head2 HRI
621
622  $rs->search(undef, {
623    result_class => 'DBIx::Class::ResultClass::HashRefInflator',
624  });
625
626 See L<DBIx::Class::ResultSet/result_class> and L<DBIx::Class::ResultClass::HashRefInflator>.
627
628 =over 1
629
630 =item Easy on memory
631
632 =item Mega fast
633
634 =item Great for quick debugging
635
636 =item Great for performance tuning (we went from 2m to < 3s)
637
638 =back
639
640 =head2 Subquery Support
641
642  my $inner_query = $schema->resultset('Artist')
643     ->search({
644      name => [ 'Billy Joel', 'Brittany Spears' ],
645  })->get_column('id')->as_query;
646
647  my $rs = $schema->resultset('CD')->search({
648      artist_id => { -in => $inner_query },
649  });
650
651 See L<DBIx::Class::Manual::Cookbook/Subqueries>
652
653 =head2 Bare SQL w/ Placeholders
654
655  $rs->update({
656     # !!! SQL INJECTION VECTOR
657     price => \"price + $inc", # DON'T DO THIS
658  });
659
660 Better:
661
662  $rs->update({
663     price => \['price + ?', [inc => $inc]],
664  });
665
666 See L<SQL::Abstract/Literal SQL with placeholders and bind values (subqueries)>
667