autoinc is nice
[dbsrgits/dbix-class-introduction-presentation.git] / slideshow.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
4 <html xmlns="http://www.w3.org/1999/xhtml">
5
6 <head>
7 <title>DBIx::Class (aka DBIC)</title>
8 <!-- metadata -->
9 <meta name="contributor" content="youcan[64]netzgesta[46]de" />
10 <meta name="publisher" content="s5.netzgesta.de" />
11 <meta name="description" content="S5 1.3 is a very flexible and lightweight slide show system available for anyone to use (including transitions and scalable fonts and images)" />
12 <meta name="keywords" content="S5, version 1.3, slide show, presentation-mode, projection-mode, powerpoint-like, scala-like, keynote-like, incremental display, scalable fonts, scalable images, transitions, notes, osf, xoxo, css, javascript, xhtml, public domain" />
13
14 <meta name="generator" content="S5" />
15 <meta name="version" content="1" />
16 <meta name="subject" content="DBIx::Class" />
17 <meta name="author" content="See first slide" />
18 <meta name="company" content="N/A" />
19 <meta name="robots" content="index, follow" />
20 <meta name="revisit-after" content="7 days" />
21 <!-- meta additionally -->
22 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
23 <meta http-equiv="Content-Script-Type" content="text/javascript" />
24 <meta http-equiv="Content-Style-Type" content="text/css" /><!-- configuration parameters -->
25 <meta name="defaultView" content="slideshow" />
26 <meta name="controlVis" content="hidden" />
27 <!-- configuration transition extension -->
28 <meta name="tranSitions" content="true" />
29 <meta name="fadeDuration" content="500" />
30 <meta name="incrDuration" content="250" />
31 <!-- configuration autoplay extension -->
32 <meta name="autoMatic" content="false" />
33 <meta name="playLoop" content="true" />
34 <meta name="playDelay" content="10" />
35 <!-- configuration audio extension -->
36 <meta name="audioSupport" content="false" />
37 <meta name="audioVolume" content="0" />
38 <meta name="audioError" content="false" />
39 <!-- configuration audio debug -->
40 <meta name="audioDebug" content="false" />
41 <!-- style sheet links -->
42 <link rel="stylesheet" href="ui/scala_utf/slides.css" type="text/css" media="projection" id="slideProj" />
43 <link rel="stylesheet" href="ui/scala_utf/outline.css" type="text/css" media="screen" id="outlineStyle" />
44 <link rel="stylesheet" href="ui/scala_utf/print.css" type="text/css" media="print" id="slidePrint" />
45 <link rel="stylesheet" href="ui/scala_utf/opera.css" type="text/css" media="projection" id="operaFix" />
46 <!-- embedded styles -->
47 <style type="text/css" media="all">
48 .imgcon {width: 100%; margin: 0 auto; padding: 0; text-align: center;}
49 #anim {width: 33%; height: 320px; position: relative;}
50 #anim img {position: absolute; top: 0px; left: 0px;}
51 .red {color: red;}
52 .grey {color: gray;}
53 </style>
54 <!-- S5 JS -->
55 <script src="ui/scala_utf/slides.js" type="text/javascript"></script>
56 </head>
57 <body>
58
59 <div class="layout">
60    <div id="controls"><!-- DO NOT EDIT --></div>
61    <div id="currentSlide"><!-- DO NOT EDIT --></div>
62    <div id="header"></div>
63    <div id="footer">
64       <h1>DBIx::Class Introduction</h1>
65       <h2>YAPC::NA 2010</h2>
66    </div>
67 </div>
68
69 <div class="presentation">
70
71    <div class="slide">
72       <h1>DBIX::Class (aka DBIC)</h1>
73       <h3>for (advanced) beginners</h3>
74    </div>
75
76    <div class="slide">
77       <h1>Authors</h1>
78       <h4>Originally Leo Lapworth @ LPW 2009</h4>
79       <h4>Amiri Barksdale</h4>
80       <h4>Justin D. Hunter</h4>
81       <h4>Arthur Axel "fREW" Schmidt</h4>
82    </div>
83
84    <div class="slide">
85       <h1>What's up guys?</h1>
86       <div class="notes">
87          <ul>
88             <li>How many people have used any ORM?<ul>
89                <li>In Perl?<ul>
90                   <li>DBIC?</li>
91                   <li>Class::DBI?</li>
92                   <li>Rose::DB?</li>
93                   <li>Fey?</li>
94                   <li>Others?</li>
95                </ul></li>
96                <li>AR?</li>
97                <li>DataMapper?</li>
98                <li>(N)Hibernate?</li>
99             </ul></li>
100          </ul>
101       </div>
102    </div>
103
104    <div class="slide">
105       <h1>Purpose</h1>
106       <p>The purpose of this talk is to show you as many features of
107       DBIx::Class in 40 minutes so that when you need to do something with
108       it later you will know what's possible</p>
109    </div>
110
111    <div class="slide">
112       <h1>DBIx::Class?</h1>
113       <ul>
114          <li>ORM (object relational mapper)</li>
115          <li>SQL &lt;-&gt; OO (using objects instead of SQL)</li>
116          <li>There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)</li>
117       </ul>
118    </div>
119
120    <div class="slide">
121       <h1>Meta</h1>
122       <p>These are reasons that are not technical or inherent to
123       the code of DBIC, but are totally awesome things about it.</p>
124    </div>
125
126    <div class="slide">
127       <h1>Large Community</h1>
128       <p>Currently there are 88 people listed as contributors to DBIC.  That
129       ranges from documentation help, to test help, to added features,
130       to entire database support.</p>
131    </div>
132
133    <div class="slide">
134       <h1>Active Community</h1>
135       <p>Currently (June 9, 2010) 6 active branches (commited to in the last two weeks) in git.  Last release (0.08122) had 14 new features, and 16 bug fixes.  Of course that <a href="http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits/DBIx-Class.git;a=blob;f=Changes">ebbs and flows</a>.</p>
136    </div>
137
138    <div class="slide">
139       <h1>Responsive Community</h1>
140       <ul class="incremental">
141          <li>needed MSSQL Order by support, they helped me add support</li>
142          <li>generally very welcoming of people willing to help</li>
143       </ul>
144    </div>
145
146    <div class="slide">
147       <h1>General ORM</h1>
148       <p>These are things that are in most other ORMs, but are still reasons
149       to use DBIC over raw SQL.</p>
150    </div>
151
152    <div class="slide">
153       <h1>Cross DB</h1>
154       <p>The vast majority of code should run on all databases without needing tweaking</p>
155    </div>
156
157    <div class="slide">
158       <h1>Basic CRUD</h1>
159       <ul class="incremental">
160          <li><strong>C</strong> - Create</li>
161          <li><strong>R</strong> - Read</li>
162          <li><strong>U</strong> - Update</li>
163          <li><strong>D</strong> - Delete</li>
164       </ul>
165    </div>
166
167    <div class="slide">
168       <h1>SQL: Create</h1>
169 <pre>my $sth = $dbh-&gt;prepare('
170    INSERT INTO books
171    (title, author_id)
172    values (?,?)
173 ');
174
175 $sth-&gt;execute(
176   'A book title', $author_id
177 );</pre>
178    </div>
179
180    <div class="slide">
181       <h1>DBIC: Create</h1>
182 <pre>my $book = $book_rs-&gt;create({
183    title     =&gt; 'A book title',
184    author_id =&gt; $author_id,
185 });</pre>
186       <ul class="incremental">
187          <li>No need to pair placeholders and values</li>
188          <li>Automatically gets autoincremented id for you</li>
189       </ul>
190    </div>
191
192    <div class="slide">
193       <h1>SQL: Read</h1>
194 <pre>my $sth = $dbh-&gt;prepare('
195    SELECT title,
196    authors.name as author_name
197    FROM books, authors
198    WHERE books.author = authors.id
199 ');</pre>
200    </div>
201
202    <div class="slide">
203       <h1>SQL: Read</h1>
204 <pre>while( my $book = $sth-&gt;fetchrow_hashref() ) {
205   print 'Author of '
206      . $book-&gt;{title}
207      . ' is '
208      . $book-&gt;{author_name}
209      . "\n";
210 }</pre>
211    </div>
212
213    <div class="slide">
214       <h1>DBIC: Read</h1>
215 <pre>my $book = $book_rs-&gt;find($book_id);
216
217 my $book = $book_rs-&gt;search({
218    title =&gt; 'A book title',
219 }, { rows =&gt; 1 })-&gt;single;
220
221 my @books = $book_rs-&gt;search({
222    author =&gt; $author_id,
223 })-&gt;all;</pre>
224       <ul class="incremental">
225          <li>TMTOWTDI</li>
226       </ul>
227    </div>
228
229    <div class="slide">
230       <h1>DBIC: Read</h1>
231 <pre>while( my $book = $books_rs-&gt;next ) {
232  print 'Author of '
233     . $book-&gt;title
234     . ' is '
235     . $book-&gt;author-&gt;name
236     . "\n";
237 }</pre>
238    </div>
239
240    <div class="slide">
241       <h1>SQL: Update</h1>
242 <pre>my $update = $dbh-&gt;prepare('
243    UPDATE books
244    SET title = ?
245    WHERE id = ?
246 ');
247
248 $update-&gt;execute(
249   'New title',<strong>$book_id</strong>
250 );</pre>
251    </div>
252
253    <div class="slide">
254       <h1>DBIC: Update</h1>
255 <pre>$book-&gt;update({
256   title =&gt; 'New title',
257 });</pre>
258    </div>
259
260    <div class="slide">
261       <h1>SQL: Delete</h1>
262 <pre>my $delete = $dbh-&gt;prepare('
263    DELETE FROM books
264    WHERE id = ?
265 ');
266
267 $delete-&gt;execute(<strong>$book_id</strong>);</pre>
268    </div>
269
270    <div class="slide">
271       <h1>DBIC: Delete</h1>
272 <pre>$book-&gt;delete;</pre>
273    </div>
274
275    <div class="slide">
276       <h1>OO Overidability</h1>
277       <ul class="incremental">
278          <li>Override new if you want to do validation</li>
279          <li>Override delete if you want to disable deletion</li>
280          <li>and on and on</li>
281       </ul>
282       <div class="notes">
283          <p>I got yelled at about this before by people, so
284          we don't get EVERYTHING from OO, but we do get a lot
285          so :-P</p>
286       </div>
287    </div>
288
289    <div class="slide">
290       <h1>Convenience Methods</h1>
291       <ul class="incremental">
292          <li>find_or_create</li>
293          <li>create_or_update</li>
294       </ul>
295    </div>
296
297    <div class="slide">
298       <h1>Non-column methods</h1>
299       <p>Need a method to get a user's gravatar URL?  Add a
300       gravatar_url method to their Result class</p>
301    </div>
302
303    <div class="slide">
304       <h1>RELATIONSHIPS</h1>
305       <ul class="incremental">
306          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#belongs_to">belongs_to</a></li>
307          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#has_many">has_many</a></li>
308          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#might_have">might_have</a></li>
309          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#has_one">has_one</a></li>
310          <li><a href="http://search.cpan.org/perldoc?DBIx::Class::Relationship#many_to_many">many_to_many</a> (technically not a relationship)</li>
311          <li>SET AND FORGET</li>
312       </ul>
313    </div>
314
315    <div class="slide">
316       <h1>DBIx::Class Specific Features</h1>
317       <p>These things may be in other ORM's, but they are very specific, so doubtful</p>
318    </div>
319
320    <div class="slide">
321       <h1>-&gt;deploy</h1>
322       <p>Perl -&gt; DB</p>
323 <pre>my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
324 $schema-&gt;deploy
325 </pre>
326 <p>See also: <a href="http://search.cpan.org/perldoc?DBIx::Class::DeploymentHandler">DBIx::Class::DeploymentHandler</a></p>
327    </div>
328
329    <div class="slide">
330       <h1>Schema::Loader</h1>
331       <p>DB -&gt; Perl</p>
332 <pre>package Foo::Schema;
333 use strict; use warnings;
334 use base 'DBIx::Class::Schema::Loader';
335 __PACKAGE__-&gt;loader_options({
336    naming =&gt; 'v7',
337    debug  =&gt; $ENV{DBIC_TRACE},
338 });
339 1;
340
341 # elsewhere...
342
343 my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
344 </pre>
345    </div>
346
347    <div class="slide">
348       <h1>Populate</h1>
349       <p>Made for inserting lots of rows very quicky into database</p>
350 <pre>$schema-&gt;populate([ Users =&gt;
351    [qw( username password )],
352    [qw( frew &gt;=4char$  )],
353    [qw(      ...          )],
354    [qw(      ...          )],
355 );
356 </pre>
357       <ul class="incremental">
358          <li>I use this to <a href="http://blog.afoolishmanifesto.com/archives/1255">export our whole (200M~) db to SQLite</a></li>
359       </ul>
360    </div>
361
362    <div class="slide">
363       <h1>Multicreate</h1>
364       <p>Create an object and all of it's related objects all at once</p>
365 <pre>$schema-&gt;resultset('Author')-&gt;create({
366    name =&gt; 'Stephen King',
367    books =&gt; [{ title =&gt; 'The Dark Tower' }],
368    address =&gt; {
369       street =&gt; '123 Turtle Back Lane',
370       state  =&gt; { abbreviation =&gt; 'ME' },
371       city   =&gt; { name =&gt; 'Lowell' },
372    },
373 });
374 </pre>
375       <div class="notes">
376          <ul>
377             <li>books is a has_many</li>
378             <li>address is a belongs_to which in turn belongs to state and city each</li>
379             <li>for this to work right state and city must mark abbreviation and name as unique</li>
380          </ul>
381       </div>
382    </div>
383
384    <div class="slide">
385       <h1>Extensible</h1>
386       <p>DBIx::Class helped pioneer fast MI in Perl 5 with Class::C3, so it is made
387       to allow extensions to nearly every part of it.</p>
388    </div>
389
390    <div class="slide">
391       <h1>Extensible: DBIC::Helpers</h1>
392       <ul class="incremental">
393          <li>DBIx::Class::Helper::ResultSet::IgnoreWantarray</li>
394          <li>DBIx::Class::Helper::ResultSet::Random</li>
395          <li>DBIx::Class::Helper::ResultSet::SetOperations</li>
396          <li>DBIx::Class::Helper::Row::JoinTable</li>
397          <li>DBIx::Class::Helper::Row::NumifyGet</li>
398          <li>DBIx::Class::Helper::Row::SubClass</li>
399          <li>DBIx::Class::Helper::Row::ToJSON</li>
400       </ul>
401    </div>
402
403    <div class="slide">
404       <h1>Extensible: DBIC::TimeStamp</h1>
405       <ul class="incremental">
406          <li>Cross DB</li>
407          <li>set_on_create</li>
408          <li>set_on_update</li>
409       </ul>
410    </div>
411
412    <div class="slide">
413       <h1>Extensible: DBIx::Class::Schema::KiokuDB</h1>
414       <ul class="incremental">
415          <li>Kioku is the new hotness</li>
416          <li>Mix RDBMS with Object DB</li>
417          <li>beta ( == sexy )</li>
418       </ul>
419    </div>
420
421    <div class="slide">
422       <h1>SQL::Abstract</h1>
423 <pre>my $resultset = $book_rs-&gt;search({
424    name =&gt; { -like =&gt; "%$nick%" },
425 });</pre>
426       <ul class="incremental">
427          <li>(kinda) introspectible</li>
428          <li>Prettier than SQL</li>
429       </ul>
430    </div>
431
432    <div class="slide">
433       <h1>Result vs ResultSet</h1>
434          <ul class="incremental">
435             <li>Result == Row</li>
436             <li>ResultSet == Query</li>
437             <li>(less important but...)</li>
438             <li>ResultSource == Table</li>
439             <li>Storage == Database</li>
440          </ul>
441    </div>
442
443    <div class="slide">
444       <h1>ResultSet methods</h1>
445 <pre>package MyApp::Schema::ResultSet::Book;
446 use base 'DBIx::Class::ResultSet';
447 sub good {
448    $_[0]-&gt;search({
449       rating =&gt; { '&gt;=' =&gt; 4 },
450    })
451 };
452 sub cheap {
453    $_[0]-&gt;search({
454       price =&gt; { '&lt;=' =&gt; 5}
455    })
456 };
457 # ...
458 1;
459       </pre>
460       <ul class="incremental">
461          <li>All searches should be ResultSet methods</li>
462          <li>Name has obvious meaning</li>
463       </ul>
464    </div>
465
466    <div class="slide">
467       <h1>ResultSet method in Action</h1>
468       <pre>$schema-&gt;resultset('Book')-&gt;good</pre>
469    </div>
470
471    <div class="slide">
472       <h1>ResultSet Chaining</h1>
473 <pre>$schema-&gt;resultset('Book')
474    -&gt;good
475    -&gt;cheap
476    -&gt;recent
477 </pre>
478    </div>
479
480    <div class="slide">
481       <h1>search_related</h1>
482       <pre>*get example from work*</pre>
483    </div>
484
485    <div class="slide">
486       <h1>bonus rel methods</h1>
487 <pre>my $book = $author-&gt;create_related(
488   <strong>books</strong> =&gt; {
489    title =&gt; 'Another Discworld book',
490 });
491
492 my $book2 = $pratchett-&gt;add_to_<strong>books</strong>({
493    title =&gt; 'MOAR Discworld book',
494 });</pre>
495       <ul class="incremental">
496          <li>Automaticaly fills in foreign key for you</li>
497       </ul>
498    </div>
499
500    <div class="slide">
501       <h1>Excellent Transaction Support</h1>
502 <pre>$schema-&gt;txn_do(sub {
503    ...
504 });
505
506 my $guard = $schema-&gt;txn_scope_guard;
507 # ...
508 $guard-&gt;commit;
509
510 $schema-&gt;txn_begin; # &lt;-- low level
511 # ...
512 $schema-&gt;txn_commit;
513 </pre>
514    </div>
515
516    <div class="slide">
517       <h1>InflateColumn</h1>
518 <pre>package Foo::Schema::Result::Book;
519 use base 'DBIx::Class::Core';
520 # Result code here
521 __PACKAGE__-&gt;load_components('InflateColumn');
522 use DateTime::Format::MySQL;
523 __PACKAGE__-&gt;<strong>inflate_column</strong>(
524    <strong>date_published</strong> =&gt; {
525       inflate =&gt; sub { DateTime::Format::MySQL-&gt;parse_date(shift) },
526       deflate =&gt; sub { shift-&gt;ymd},
527    },
528 );
529 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
530    </div>
531
532    <div class="slide">
533       <h1>InflateColumn: deflation</h1>
534 <pre>$book-&gt;date_published(DateTime-&gt;now);
535 $book-&gt;update;</pre>
536    </div>
537
538    <div class="slide">
539       <h1>InflateColumn: inflation</h1>
540 <pre>my $date_published = $book-&gt;date_published;
541 print $date_published-&gt;month_abbr;</pre>
542
543 <strong><em>Nov</em></strong>
544    </div>
545
546    <div class="slide">
547       <h1>FilterColumn</h1>
548 <pre>package Foo::Schema::Result::Book;
549 use base 'DBIx::Class::Core';
550 # Result code here
551 __PACKAGE__-&gt;load_components('FilterColumn');
552
553 __PACKAGE__-&gt;<strong>filter_column</strong>(
554    <strong>length</strong> =&gt; {
555       to_storage   =&gt; 'to_metric',
556       from_storage =&gt; 'to_imperial',
557    },
558 );
559
560 sub to_metric   { $_[1] * .305 }
561 sub to_imperial { $_[1] * 3.28 }
562 # Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
563    </div>
564
565    <div class="slide">
566       <h1>ResultSetColumn</h1>
567 <pre>my $rsc = $schema-&gt;resultset('Book')-&gt;get_column('price');
568 $rsc-&gt;min;
569 $rsc-&gt;max;
570 $rsc-&gt;sum;
571 </pre>
572    </div>
573
574    <div class="slide">
575       <h1>Aggregates</h1>
576 <pre>my @res = $rs-&gt;search({}, {
577    select   =&gt; [qw(price genre), { max =&gt; price }, { avg =&gt; price }],
578    as       =&gt; [qw(price genre max_price avg_price)],
579    group_by =&gt; [qw(price genre)],
580 });
581 for (@res) {
582    say $_-&gt;price . ' ' . $_-&gt;genre;
583    say $_-&gt;get_column('max_price');
584    say $_-&gt;get_column('min_price');
585 }</pre>
586       <ul class="incremental">
587          <li>Careful, get_column can basicaly mean THREE things</li>
588          <li>private for get what you should use an accessor for</li>
589          <li>public for what there is no accessor for</li>
590          <li>public for get resultset column (prev slide)</li>
591       </ul>
592    </div>
593
594    <div class="slide">
595       <h1>HRI</h1>
596 <pre>$rs-&gt;search({}, {
597    result_class =&gt; 'DBIx::Class::ResultClass::HashRefInflator',
598 });</pre>
599       <ul class="incremental">
600          <li>Easy on memory</li>
601          <li>Mega fast</li>
602          <li>Great for quick debugging</li>
603          <li>Great for performance tuning (we went from 2m to &lt; 3s)</li>
604       </ul>
605    </div>
606
607    <div class="slide">
608       <h1>Subquery Support</h1>
609 <pre>  my $inside_rs = $schema-&gt;resultset('Artist')-&gt;search({
610     name =&gt; [ 'Billy Joel', 'Brittany Spears' ],
611 });
612
613 my $rs = $schema-&gt;resultset('CD')-&gt;search({
614     artist_id =&gt; { -in =&gt; $inside_rs-&gt;get_column('id')-&gt;as_query },
615 });</pre>
616    </div>
617
618    <div class="slide">
619       <h1>Bare SQL w/ Placeholders</h1>
620 <pre>$rs-&gt;update({
621    price =&gt; \"price + $inc", # !!! SQL INJECTION VECTOR
622 });
623
624 $rs-&gt;update({
625    price =&gt; \['price + ?', [inc =&gt; $inc]],
626 });
627 </pre>
628    </div>
629
630    <div class="slide">
631       <h1>Questions?</h1>
632    </div>
633
634    <div class="slide">
635       <h1>END</h1>
636    </div>
637 </div>
638 </body>
639 </html>