File Coverage

blib/lib/Rubric/DBI/Setup.pm
Criterion Covered Total %
statement 41 57 71.9
branch 7 22 31.8
condition n/a
subroutine 12 13 92.3
pod 6 6 100.0
total 66 98 67.3


line stmt bran cond sub pod time code
1 7     7   43093 use strict;
  7         13  
  7         189  
2 7     7   37 use warnings;
  7         14  
  7         398  
3             package Rubric::DBI::Setup;
4             # ABSTRACT: db initialization routines
5             $Rubric::DBI::Setup::VERSION = '0.156';
6             #pod =head1 SYNOPSIS
7             #pod
8             #pod use strict;
9             #pod use warnings;
10             #pod
11             #pod use Rubric::DBI::Setup;
12             #pod Rubric::DBI::Setup->setup_tables;
13             #pod
14             #pod =head1 DESCRIPTION
15             #pod
16             #pod =cut
17              
18 7     7   9376 use DBI;
  7         72754  
  7         388  
19 7     7   56 use Rubric::Config;
  7         10  
  7         65  
20 7     7   2700 use Rubric::Entry;
  7         24  
  7         75  
21 7     7   3883 use Rubric::Renderer;
  7         31  
  7         9473  
22              
23             #pod =head1 METHODS
24             #pod
25             #pod =head2 dbh
26             #pod
27             #pod This method returns a connection to the Rubric database.
28             #pod
29             #pod =cut
30              
31             my $dbh;
32              
33             sub dbh {
34 15 100   15 1 421178 return $dbh if $dbh;
35              
36 2         20 return $dbh = DBI->connect(
37             Rubric::Config->dsn,
38             Rubric::Config->db_user,
39             Rubric::Config->db_pass
40             );
41             }
42              
43             #pod =head2 setup_tables
44             #pod
45             #pod This method builds the tables in the database, if needed.
46             #pod
47             #pod =cut
48              
49             sub setup_tables {
50 2     2 1 1240 my ($class) = @_;
51              
52 2         9 local $/ = "\n\n";
53 2         41 $class->dbh->do( $class->specialize_sql($_) ) for ;
54             }
55              
56             #pod =head2 specialize_sql
57             #pod
58             #pod attempts to convert the given sql syntax to the given DBD Driver's
59             #pod
60             #pod =cut
61              
62             sub specialize_sql {
63 12     12 1 105292 my ($class, $query) = @_;
64              
65 12         81 my $db_type = $class->determine_db_type;
66              
67 12 50       67 if ($db_type eq 'Pg') {
68 0         0 $query =~ s/(id\s*)integer/$1SERIAL/i;
69             }
70              
71 12         146 return $query;
72             }
73              
74             #pod =head2 determine_version
75             #pod
76             #pod This attempts to determine the version of the database schema to which the
77             #pod given database conforms. All recent schemata store their version number; for
78             #pod older versions, some simple table attributes are checked.
79             #pod
80             #pod =cut
81              
82             sub _columns {
83 0     0   0 my ($class, $query) = @_;
84 0         0 return scalar(my @columns = $class->dbh->selectrow_array($query));
85             }
86              
87             sub determine_version {
88 3     3 1 25260 my ($class) = @_;
89              
90 3         10 my ($version) = $class->dbh->selectrow_array("SELECT schema_version FROM rubric");
91              
92 3 50       484 if ($version) {
93 3 50       11 if ($version == 6) {
94             # some schemata are broken, and claim 6 on 7
95 0         0 eval {
96 0         0 $class->dbh->selectall_array("SELECT verification_code FROM users");
97             };
98 0 0       0 if ($@) {
99 0         0 warn "your db schema label is incorrect; run rubric db -u"; return 7;
  0         0  
100             } else {
101 0         0 return 6;
102             }
103             } else {
104 3         16 return $version;
105             }
106             }
107              
108             # v4 added body column;
109 0 0       0 return 4 if $class->_columns("SELECT * FROM entries LIMIT 1") == 8;
110              
111             # v3 added email and validation_code;
112 0 0       0 return 3 if $class->_columns("SELECT * FROM users LIMIT 1") == 4;
113              
114             # v2 added md5 column;
115 0 0       0 return 2 if $class->_columns("SELECT * FROM links LIMIT 1") == 3;
116              
117 0 0       0 return 1 if $class->_columns("SELECT * FROM links LIMIT 1") == 2;
118              
119 0         0 return;
120             }
121              
122             #pod =head2 determine_db_type
123             #pod
124             #pod Returns the type of db being used, based on the DSN's DBD driver.
125             #pod SQLite and Pg support only right now.
126             #pod
127             #pod =cut
128              
129             sub determine_db_type {
130 12     12 1 32 my ($class) = @_;
131              
132 12         119 Rubric::Config->dsn =~ /dbi:([^:]+):/;
133              
134 12         90 my $db_type = $1;
135              
136 12         60 return $db_type;
137             }
138              
139             #pod =head2 update_schema
140             #pod
141             #pod This method will try to upgrade the database to the most recent schema. It's
142             #pod sort of ugly, but it works...
143             #pod
144             #pod =cut
145              
146             my %from;
147              
148             # from 1 to 2
149             # add md5 sum to links table
150              
151             $from{1} = sub {
152             require Digest::MD5;
153             $dbh->func('md5hex', 1, \&Digest::MD5::md5_hex, 'create_function');
154              
155             my $sql = <<'END_SQL';
156             CREATE TABLE new_links (
157             id INTEGER PRIMARY KEY,
158             uri varchar UNIQUE NOT NULL,
159             md5 varchar NOT NULL
160             );
161              
162             INSERT INTO new_links
163             SELECT id, uri, md5hex(uri) FROM links;
164              
165             DROP TABLE links;
166              
167             CREATE TABLE links (
168             id INTEGER PRIMARY KEY,
169             uri varchar UNIQUE NOT NULL,
170             md5 varchar NOT NULL
171             );
172              
173             INSERT INTO links
174             SELECT id, uri, md5 FROM new_links;
175              
176             DROP TABLE new_links;
177             END_SQL
178              
179             $dbh->do($_) for split /\n\n/, $sql;
180             };
181              
182             # from 2 to 3
183             # add email and validation_code
184             # fill in email with garbage data
185              
186             $from{2} = sub {
187             my $sql = <<'END_SQL';
188             CREATE TABLE new_users (
189             username PRIMARY KEY,
190             password NOT NULL,
191             email NOT NULL,
192             validation_code
193             );
194              
195             INSERT INTO new_users
196             SELECT *, 'user@example.com', NULL FROM users;
197              
198             DROP TABLE users;
199              
200             CREATE TABLE users (
201             username PRIMARY KEY,
202             password NOT NULL,
203             email NOT NULL,
204             validation_code
205             );
206              
207             INSERT INTO users
208             SELECT * FROM new_users;
209              
210             DROP TABLE new_users;
211             END_SQL
212              
213             $dbh->do($_) for split /\n\n/, $sql;
214             };
215              
216             # from 3 to 4
217             # link becomes null-ok
218             # add body column
219              
220             $from{3} = sub {
221             my $sql = <
222             CREATE TABLE new_entries (
223             id INTEGER PRIMARY KEY,
224             link integer,
225             user varchar NOT NULL,
226             title varchar NOT NULL,
227             created NOT NULL,
228             modified NOT NULL,
229             description varchar,
230             body TEXT
231             );
232              
233             INSERT INTO new_entries
234             SELECT *, NULL FROM entries;
235              
236             DROP TABLE entries;
237              
238             CREATE TABLE entries (
239             id INTEGER PRIMARY KEY,
240             link integer,
241             user varchar NOT NULL,
242             title varchar NOT NULL,
243             created NOT NULL,
244             modified NOT NULL,
245             description varchar,
246             body TEXT
247             );
248              
249             INSERT INTO entries
250             SELECT * FROM new_entries;
251              
252             DROP TABLE new_entries;
253             END_SQL
254              
255             $dbh->do($_) for split /\n\n/, $sql;
256             };
257              
258             # from 4 to 5
259             # add rubric table and schema number
260              
261             $from{4} = sub {
262             my $sql = <
263             CREATE TABLE rubric (
264             schema_version NOT NULL
265             );
266              
267             INSERT INTO rubric (schema_version) VALUES (5);
268             END_SQL
269              
270             $dbh->do($_) for split /\n\n/, $sql;
271             };
272              
273             # from 5 to 6
274             # add "created" column to users
275              
276             $from{5} = sub {
277             my $sql = <<'END_SQL';
278             CREATE TABLE new_users (
279             username PRIMARY KEY,
280             password NOT NULL,
281             email NOT NULL,
282             created NOT NULL,
283             validation_code
284             );
285              
286             INSERT INTO new_users
287             SELECT username, password, email, 0, validation_code
288             FROM users;
289              
290             DROP TABLE users;
291              
292             CREATE TABLE users (
293             username PRIMARY KEY,
294             password NOT NULL,
295             email NOT NULL,
296             created NOT NULL,
297             validation_code
298             );
299              
300             INSERT INTO users
301             SELECT * FROM new_users;
302              
303             DROP TABLE new_users;
304              
305             UPDATE rubric SET schema_version = 6;
306             END_SQL
307              
308             $dbh->do($_) for split /\n\n/, $sql;
309             };
310              
311             # from 6 to 7
312             # validation_code is now verification_code
313              
314             $from{6} = sub {
315             my $sql = <<'END_SQL';
316             CREATE TABLE new_users (
317             username PRIMARY KEY,
318             password NOT NULL,
319             email NOT NULL,
320             created NOT NULL,
321             verification_code
322             );
323              
324             INSERT INTO new_users
325             SELECT username, password, email, created, validation_code
326             FROM users;
327              
328             DROP TABLE users;
329              
330             CREATE TABLE users (
331             username PRIMARY KEY,
332             password NOT NULL,
333             email NOT NULL,
334             created NOT NULL,
335             verification_code
336             );
337              
338             INSERT INTO users
339             SELECT * FROM new_users;
340              
341             DROP TABLE new_users;
342              
343             UPDATE rubric SET schema_version = 7;
344             END_SQL
345              
346             $dbh->do($_) for split /\n\n/, $sql;
347             };
348              
349             # from 7 to 8
350             # add reset_code
351              
352             $from{7} = sub {
353             my $sql = <<'END_SQL';
354             CREATE TABLE new_users (
355             username PRIMARY KEY,
356             password NOT NULL,
357             email NOT NULL,
358             created NOT NULL,
359             verification_code,
360             reset_code
361             );
362              
363             INSERT INTO new_users
364             SELECT username, password, email, created, verification_code, NULL
365             FROM users;
366              
367             DROP TABLE users;
368              
369             CREATE TABLE users (
370             username PRIMARY KEY,
371             password NOT NULL,
372             email NOT NULL,
373             created NOT NULL,
374             verification_code,
375             reset_code
376             );
377              
378             INSERT INTO users
379             SELECT * FROM new_users;
380              
381             DROP TABLE new_users;
382              
383             UPDATE rubric SET schema_version = 8;
384             END_SQL
385              
386             $dbh->do($_) for split /\n\n/, $sql;
387             };
388              
389             $from{8} = sub {
390             my $sql = <<'END_SQL';
391             CREATE TABLE new_entrytags (
392             id INTEGER PRIMARY KEY,
393             entry NOT NULL,
394             tag NOT NULL,
395             tag_value,
396             UNIQUE(entry, tag)
397             );
398              
399             INSERT INTO new_entrytags
400             SELECT id, entry, tag, NULL
401             FROM entrytags;
402              
403             DROP TABLE entrytags;
404              
405             CREATE TABLE entrytags (
406             id INTEGER PRIMARY KEY,
407             entry NOT NULL,
408             tag NOT NULL,
409             tag_value,
410             UNIQUE(entry, tag)
411             );
412              
413             INSERT INTO entrytags
414             SELECT * FROM new_entrytags;
415              
416             DROP TABLE new_entrytags;
417              
418             UPDATE rubric SET schema_version = 9;
419             END_SQL
420              
421             $dbh->do($_) for split /\n\n/, $sql;
422             };
423              
424             $from{9} = sub {
425             my $sql = <<'END_SQL';
426             CREATE TABLE new_users (
427             username varchar PRIMARY KEY,
428             password varchar NOT NULL,
429             email varchar NOT NULL,
430             created integer NOT NULL,
431             verification_code varchar,
432             reset_code varchar
433             );
434              
435             INSERT INTO new_users
436             SELECT username, password, email, created, verification_code, reset_code
437             FROM users;
438              
439             DROP TABLE users;
440              
441             CREATE TABLE users (
442             username varchar PRIMARY KEY,
443             password varchar NOT NULL,
444             email varchar NOT NULL,
445             created integer NOT NULL,
446             verification_code varchar,
447             reset_code varchar
448             );
449              
450             INSERT INTO users
451             SELECT username, password, email, created, verification_code, reset_code
452             FROM new_users;
453              
454             DROP TABLE new_users;
455              
456             CREATE TABLE new_entries (
457             id integer PRIMARY KEY,
458             link integer,
459             user varchar NOT NULL,
460             title varchar NOT NULL,
461             created integer NOT NULL,
462             modified integer NOT NULL,
463             description varchar,
464             body TEXT
465             );
466              
467             INSERT INTO new_entries
468             SELECT id, link, user, title, created, modified, description, body
469             FROM entries;
470              
471             DROP TABLE entries;
472              
473             CREATE TABLE entries (
474             id integer PRIMARY KEY,
475             link integer,
476             user varchar NOT NULL,
477             title varchar NOT NULL,
478             created integer NOT NULL,
479             modified integer NOT NULL,
480             description varchar,
481             body TEXT
482             );
483              
484             INSERT INTO entries
485             SELECT id, link, user, title, created, modified, description, body
486             FROM new_entries;
487              
488             DROP TABLE new_entries;
489              
490             CREATE TABLE new_entrytags (
491             id INTEGER PRIMARY KEY,
492             entry integer NOT NULL,
493             tag varchar NOT NULL,
494             tag_value varchar,
495             UNIQUE(entry, tag)
496             );
497              
498             INSERT INTO new_entrytags
499             SELECT id, entry, tag, tag_value
500             FROM entrytags;
501              
502             DROP TABLE entrytags;
503              
504             CREATE TABLE entrytags (
505             id INTEGER PRIMARY KEY,
506             entry integer NOT NULL,
507             tag varchar NOT NULL,
508             tag_value varchar,
509             UNIQUE(entry, tag)
510             );
511              
512             INSERT INTO entrytags
513             SELECT id, entry, tag, tag_value
514             FROM new_entrytags;
515              
516             DROP TABLE new_entrytags;
517              
518             DROP TABLE rubric;
519              
520             CREATE TABLE rubric (
521             schema_version integer NOT NULL
522             );
523              
524             INSERT INTO rubric (schema_version) VALUES (10);
525             END_SQL
526              
527             $dbh->do($_) for split /\n\n/, $sql;
528             };
529              
530             $from{10} = sub {
531             my $sql = <<'END_SQL';
532             CREATE TABLE new_entries (
533             id integer PRIMARY KEY,
534             link integer,
535             username varchar NOT NULL,
536             title varchar NOT NULL,
537             created integer NOT NULL,
538             modified integer NOT NULL,
539             description varchar,
540             body TEXT
541             );
542              
543             INSERT INTO new_entries (id, link, username, title, created, modified, description, body)
544             SELECT id, link, user, title, created, modified, description, body
545             FROM entries;
546              
547             DROP TABLE entries;
548              
549             CREATE TABLE entries (
550             id integer PRIMARY KEY,
551             link integer,
552             username varchar NOT NULL,
553             title varchar NOT NULL,
554             created integer NOT NULL,
555             modified integer NOT NULL,
556             description varchar,
557             body TEXT
558             );
559              
560             INSERT INTO entries
561             SELECT id, link, username, title, created, modified, description, body
562             FROM new_entries;
563              
564             DROP TABLE new_entries;
565              
566             UPDATE rubric SET schema_version = 11;
567             END_SQL
568              
569             $dbh->do($_) for split /\n\n/, $sql;
570             };
571              
572             $from{11} = undef;
573              
574             sub update_schema {
575 1     1 1 3 my ($class) = @_;
576              
577 1         4 while ($_ = $class->determine_version) {
578 1 50       8 die "no update path from schema version $_" unless exists $from{$_};
579 1 50       5 last unless defined $from{$_};
580 0         0 print "updating from version $_...\n";
581 0         0 $from{$_}->();
582             }
583 1         4 return $class->determine_version;
584             }
585              
586             1;
587              
588             =pod
589              
590             =encoding UTF-8
591              
592             =head1 NAME
593              
594             Rubric::DBI::Setup - db initialization routines
595              
596             =head1 VERSION
597              
598             version 0.156
599              
600             =head1 SYNOPSIS
601              
602             use strict;
603             use warnings;
604              
605             use Rubric::DBI::Setup;
606             Rubric::DBI::Setup->setup_tables;
607              
608             =head1 DESCRIPTION
609              
610             =head1 METHODS
611              
612             =head2 dbh
613              
614             This method returns a connection to the Rubric database.
615              
616             =head2 setup_tables
617              
618             This method builds the tables in the database, if needed.
619              
620             =head2 specialize_sql
621              
622             attempts to convert the given sql syntax to the given DBD Driver's
623              
624             =head2 determine_version
625              
626             This attempts to determine the version of the database schema to which the
627             given database conforms. All recent schemata store their version number; for
628             older versions, some simple table attributes are checked.
629              
630             =head2 determine_db_type
631              
632             Returns the type of db being used, based on the DSN's DBD driver.
633             SQLite and Pg support only right now.
634              
635             =head2 update_schema
636              
637             This method will try to upgrade the database to the most recent schema. It's
638             sort of ugly, but it works...
639              
640             =head1 AUTHOR
641              
642             Ricardo SIGNES
643              
644             =head1 COPYRIGHT AND LICENSE
645              
646             This software is copyright (c) 2004 by Ricardo SIGNES.
647              
648             This is free software; you can redistribute it and/or modify it under
649             the same terms as the Perl 5 programming language system itself.
650              
651             =cut
652              
653             __DATA__