makes search_related on extended rels without the optimized version work. involves...
[dbsrgits/DBIx-Class-Historic.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 (commited 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 Overidability
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 quicky 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 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
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>, 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
496 See L<DBIx::Class::Relationship::Base/create_related> and L<DBIx::Class::Relationship::Base/add_to_$rel>
497
498 Note that it automaticaly fills in foreign key for you
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
510 See L<DBIx::Class::Schema/txn_do>, L<DBIx::Class::Schema/txn_begin>,
511 and 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
535 See L<DBIx::Class::InflateColumn>, L<DBIx::Class::InflateColumn/inflate_column>, and
536 L<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
570 See 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
581 See 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');
600     say $_->get_column('avg_price');
601  }
602
603 See L<DBIx::Class::ResultSet/select>, L<DBIx::Class::ResultSet/as>, and
604 L<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
624 See 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
649 See L<DBIx::Class::Manual::Cookbook#Subqueries>
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
658 Better:
659
660  $rs->update({
661     price => \['price + ?', [inc => $inc]],
662  });
663
664 See L<SQL::Abstract#Literal_SQL_with_placeholders_and_bind_values_(subqueries)>
665