autoinc is nice
[dbsrgits/dbix-class-introduction-presentation.git] / slideshow.html
CommitLineData
52d980cb 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>
0cffcad7 74 </div>
75
76 <div class="slide">
77 <h1>Authors</h1>
78 <h4>Originally Leo Lapworth @ LPW 2009</h4>
da0b46fd 79 <h4>Amiri Barksdale</h4>
0cffcad7 80 <h4>Justin D. Hunter</h4>
5cac74c7 81 <h4>Arthur Axel "fREW" Schmidt</h4>
52d980cb 82 </div>
83
84 <div class="slide">
7365a110 85 <h1>What's up guys?</h1>
0cffcad7 86 <div class="notes">
87 <ul>
0cffcad7 88 <li>How many people have used any ORM?<ul>
89 <li>In Perl?<ul>
90 <li>DBIC?</li>
da0b46fd 91 <li>Class::DBI?</li>
92 <li>Rose::DB?</li>
93 <li>Fey?</li>
94 <li>Others?</li>
0cffcad7 95 </ul></li>
da0b46fd 96 <li>AR?</li>
97 <li>DataMapper?</li>
0cffcad7 98 <li>(N)Hibernate?</li>
99 </ul></li>
100 </ul>
101 </div>
52d980cb 102 </div>
103
104 <div class="slide">
da0b46fd 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">
52d980cb 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>
52d980cb 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">
da0b46fd 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>
52d980cb 155 </div>
156
157 <div class="slide">
7365a110 158 <h1>Basic CRUD</h1>
da0b46fd 159 <ul class="incremental">
52d980cb 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">
5cac74c7 168 <h1>SQL: Create</h1>
52d980cb 169<pre>my $sth = $dbh-&gt;prepare('
170 INSERT INTO books
01b7b88c 171 (title, author_id)
52d980cb 172 values (?,?)
173');
174
175$sth-&gt;execute(
176 'A book title', $author_id
177);</pre>
178 </div>
179
180 <div class="slide">
5cac74c7 181 <h1>DBIC: Create</h1>
01b7b88c 182<pre>my $book = $book_rs-&gt;create({
183 title =&gt; 'A book title',
184 author_id =&gt; $author_id,
52d980cb 185});</pre>
da0b46fd 186 <ul class="incremental">
187 <li>No need to pair placeholders and values</li>
ec535d03 188 <li>Automatically gets autoincremented id for you</li>
da0b46fd 189 </ul>
52d980cb 190 </div>
191
192 <div class="slide">
7365a110 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>
52d980cb 211 </div>
212
213 <div class="slide">
5cac74c7 214 <h1>DBIC: Read</h1>
01b7b88c 215<pre>my $book = $book_rs-&gt;find($book_id);
52d980cb 216
01b7b88c 217my $book = $book_rs-&gt;search({
52d980cb 218 title =&gt; 'A book title',
5cac74c7 219}, { rows =&gt; 1 })-&gt;single;
52d980cb 220
01b7b88c 221my @books = $book_rs-&gt;search({
52d980cb 222 author =&gt; $author_id,
223})-&gt;all;</pre>
da0b46fd 224 <ul class="incremental">
225 <li>TMTOWTDI</li>
226 </ul>
52d980cb 227 </div>
228
229 <div class="slide">
5cac74c7 230 <h1>DBIC: Read</h1>
231<pre>while( my $book = $books_rs-&gt;next ) {
52d980cb 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">
7365a110 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">
5cac74c7 254 <h1>DBIC: Update</h1>
52d980cb 255<pre>$book-&gt;update({
256 title =&gt; 'New title',
257});</pre>
258 </div>
259
260 <div class="slide">
7365a110 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">
5cac74c7 271 <h1>DBIC: Delete</h1>
52d980cb 272<pre>$book-&gt;delete;</pre>
273 </div>
274
275 <div class="slide">
da0b46fd 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>
52d980cb 287 </div>
288
289 <div class="slide">
da0b46fd 290 <h1>Convenience Methods</h1>
291 <ul class="incremental">
292 <li>find_or_create</li>
293 <li>create_or_update</li>
294 </ul>
492be2ae 295 </div>
296
297 <div class="slide">
da0b46fd 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>
52d980cb 318 </div>
319
320 <div class="slide">
9158dee5 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">
52d980cb 330 <h1>Schema::Loader</h1>
9158dee5 331 <p>DB -&gt; Perl</p>
451b57c2 332<pre>package Foo::Schema;
c7321880 333use strict; use warnings;
334use base 'DBIx::Class::Schema::Loader';
335__PACKAGE__-&gt;loader_options({
336 naming =&gt; 'v7',
337 debug =&gt; $ENV{DBIC_TRACE},
338});
3391;
340
341# elsewhere...
342
451b57c2 343my $schema = Foo::Schema-&gt;connect($dsn, $user, $pass);
c7321880 344</pre>
52d980cb 345 </div>
346
347 <div class="slide">
da0b46fd 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>
52d980cb 360 </div>
361
362 <div class="slide">
da0b46fd 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 },
7e77ca11 373});
da0b46fd 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>
7e77ca11 423<pre>my $resultset = $book_rs-&gt;search({
424 name =&gt; { -like =&gt; "%$nick%" },
425});</pre>
da0b46fd 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;
446use base 'DBIx::Class::ResultSet';
447sub good {
7e77ca11 448 $_[0]-&gt;search({
da0b46fd 449 rating =&gt; { '&gt;=' =&gt; 4 },
450 })
451};
452sub cheap {
7e77ca11 453 $_[0]-&gt;search({
da0b46fd 454 price =&gt; { '&lt;=' =&gt; 5}
455 })
456};
457# ...
4581;
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
6e5edefe 477</pre>
52d980cb 478 </div>
479
480 <div class="slide">
7e77ca11 481 <h1>search_related</h1>
482 <pre>*get example from work*</pre>
52d980cb 483 </div>
484
485 <div class="slide">
7e77ca11 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});
52d980cb 491
7e77ca11 492my $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>
52d980cb 498 </div>
499
500 <div class="slide">
7e77ca11 501 <h1>Excellent Transaction Support</h1>
502<pre>$schema-&gt;txn_do(sub {
503 ...
504});
52d980cb 505
7e77ca11 506my $guard = $schema-&gt;txn_scope_guard;
507# ...
508$guard-&gt;commit;
52d980cb 509
7e77ca11 510$schema-&gt;txn_begin; # &lt;-- low level
511# ...
512$schema-&gt;txn_commit;
513</pre>
52d980cb 514 </div>
515
516 <div class="slide">
7e77ca11 517 <h1>InflateColumn</h1>
2a65778d 518<pre>package Foo::Schema::Result::Book;
519use base 'DBIx::Class::Core';
451b57c2 520# Result code here
451b57c2 521__PACKAGE__-&gt;load_components('InflateColumn');
52d980cb 522use DateTime::Format::MySQL;
52d980cb 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},
451b57c2 527 },
52d980cb 528);
529# Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
530 </div>
531
532 <div class="slide">
7e77ca11 533 <h1>InflateColumn: deflation</h1>
52d980cb 534<pre>$book-&gt;date_published(DateTime-&gt;now);
535$book-&gt;update;</pre>
536 </div>
537
538 <div class="slide">
7e77ca11 539 <h1>InflateColumn: inflation</h1>
52d980cb 540<pre>my $date_published = $book-&gt;date_published;
541print $date_published-&gt;month_abbr;</pre>
542
543<strong><em>Nov</em></strong>
544 </div>
545
546 <div class="slide">
7e77ca11 547 <h1>FilterColumn</h1>
548<pre>package Foo::Schema::Result::Book;
2a65778d 549use base 'DBIx::Class::Core';
7e77ca11 550# Result code here
551__PACKAGE__-&gt;load_components('FilterColumn');
52d980cb 552
7e77ca11 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 },
52d980cb 558);
52d980cb 559
7e77ca11 560sub to_metric { $_[1] * .305 }
561sub to_imperial { $_[1] * 3.28 }
562# Automatic see: DBIx::Class::InflateColumn::DateTime</pre>
52d980cb 563 </div>
564
565 <div class="slide">
7e77ca11 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;
6548782a 571</pre>
52d980cb 572 </div>
573
574 <div class="slide">
7e77ca11 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});
581for (@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>
52d980cb 592 </div>
593
594 <div class="slide">
7e77ca11 595 <h1>HRI</h1>
596<pre>$rs-&gt;search({}, {
597 result_class =&gt; 'DBIx::Class::ResultClass::HashRefInflator',
52d980cb 598});</pre>
7e77ca11 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>
52d980cb 604 </ul>
605 </div>
606
607 <div class="slide">
7e77ca11 608 <h1>Subquery Support</h1>
609<pre> my $inside_rs = $schema-&gt;resultset('Artist')-&gt;search({
610 name =&gt; [ 'Billy Joel', 'Brittany Spears' ],
611});
9158dee5 612
7e77ca11 613my $rs = $schema-&gt;resultset('CD')-&gt;search({
614 artist_id =&gt; { -in =&gt; $inside_rs-&gt;get_column('id')-&gt;as_query },
615});</pre>
52d980cb 616 </div>
617
618 <div class="slide">
7e77ca11 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>
52d980cb 628 </div>
629
630 <div class="slide">
7e77ca11 631 <h1>Questions?</h1>
52d980cb 632 </div>
633
634 <div class="slide">
7e77ca11 635 <h1>END</h1>
52d980cb 636 </div>
52d980cb 637</div>
638</body>
639</html>