File Coverage

blib/lib/DBIx/SQLite/Deploy.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package DBIx::SQLite::Deploy;
2              
3 2     2   181373 use warnings;
  2         5  
  2         70  
4 2     2   9 use strict;
  2         4  
  2         125  
5              
6             =head1 NAME
7              
8             DBIx::SQLite::Deploy - Easy SQLite deployment
9              
10             =head1 VERSION
11              
12             Version 0.011
13              
14             =cut
15              
16             our $VERSION = '0.011';
17              
18             =head1 SYNOPSIS
19              
20             # ::Deploy will create the 'path/to' for you if it does not already exist
21             my $deploy = DBIx::SQLite::Deploy->deploy( path/to/database.sqlite => <<_END_ )
22             [% PRIMARY_KEY = "INTEGER PRIMARY KEY AUTOINCREMENT" %]
23             [% KEY = "INTEGER" %]
24             [% CLEAR %]
25             ---
26             CREATE TABLE artist (
27              
28             id [% PRIMARY_KEY %],
29             uuid TEXT NOT NULL,
30              
31             name TEXT,
32             description TEXT,
33              
34             UNIQUE (uuid)
35             );
36             ---
37             CREATE TABLE cd (
38              
39             id [% PRIMARY_KEY %],
40              
41             title TEXT,
42             description TEXT
43             );
44             _END_
45              
46             To use with DBI
47              
48             $dbh = $deploy->connect
49              
50             # ...or the long way:
51              
52             $dbh = DBI->connect( $deploy->information )
53              
54             To use with L<DBIx::Class>
55              
56             $schema = My::Schema->connect( $deploy->information )
57              
58             =head1 DESCRIPTION
59              
60             DBIx::SQLite::Deploy is a tool for creating a database and getting back a DBI connection in as little work as possible. Essentially, you pass the path
61             of your database and the schema (as a Template Toolkit template) to C<< DBIx::SQLite::Deploy->deploy >>. If the database is not there (file does not exist or is size 0), then
62             ::Deploy will create the database and install the schema
63              
64             =head1 Why Template Toolkit?
65              
66             Purely as a convenience. You probably have lots of repetition in your schema, and TT gives a way to combat that redundancy. You don't need to use it if you don't want/need to.
67              
68             =head1 USAGE
69              
70             =head2 $deploy = DBIx::SQLite::Deploy->deploy( <path>, [ <schema> ], ... )
71              
72             Create a new deployment using <path> as the file for the SQLite database, and <schema> as the (optional) schema
73              
74             The schema argument can be in the form of a Template Toolkit document.
75              
76             The database will NOT be created until you ask to C<< ->connect >>, ask for C<< ->information >>, or manually C<< ->deploy >>. To do creation on construction, pass
77             C<< create => 1 >> as an argument
78              
79             DBIx::SQLite::Deploy will not deploy over an existing database (the file exists and has non-zero size)
80              
81             =head2 $deploy->connect
82              
83             Return a L<DBI> database handle (C<$dbh>)
84              
85             =head2 $deploy->information
86              
87             =head2 $deploy->info
88              
89             Return a list of connection information, suitable for passing to C<< DBI->connect >>
90              
91             =head2 $deploy->deploy
92              
93             Deploy the database unless it already exists
94              
95             =cut
96              
97 2     2   2373 use Moose;
  0            
  0            
98             use DBIx::SQLite::Deploy::Carp;
99              
100             has schema_parser => qw/is ro lazy_build 1/;
101             sub _build_schema_parser {
102             require SQL::Script;
103             return SQL::Script->new( split_by => qr/\n\s*-{2,4}\n/ );
104             };
105              
106             has tt => qw/is ro lazy_build 1/;
107             sub _build_tt {
108             require Template;
109             return Template->new({});
110             };
111              
112             has schema => qw/is ro/;
113             has connection => qw/is ro required 1/;
114              
115             sub _deploy {
116             my $class = shift;
117             my ($connection, $schema) = (shift, shift);
118             my %given = @_;
119             @given{qw/ connection schema /} = ( $connection, $schema );
120              
121             $connection = DBIx::SQLite::Deploy::Connection->parse( delete $given{connection} );
122              
123             my $create = delete $given{create};
124             my $deploy = $class->new( connection => $connection, %given );
125             $deploy->deploy if $create;
126             return $deploy;
127             }
128              
129             sub deploy {
130             return shift->_deploy( @_ ) unless ref $_[0];
131             my $self = shift;
132              
133             my $connection = $self->connection;
134              
135             if ( my $schema = $self->schema ) {
136              
137             unless ( $connection->database_exists ) {
138             {
139             my $input = $schema;
140             my $output;
141             $self->tt->process( \$input, {}, \$output ) or die $self->tt->error;
142             $schema = $output;
143             }
144             $self->schema_parser->read( \$schema );
145             my @statements = $self->schema_parser->statements;
146             {
147             my $dbh = $connection->connect;
148             for my $statement ( @statements ) {
149             chomp $statement;
150             $dbh->do( $statement ) or die $dbh->errstr;
151             }
152             $dbh->disconnect;
153             }
154             }
155             }
156              
157             $connection->disconnect; # TODO huh?
158              
159             return $connection->information;
160             }
161              
162             sub information {
163             my $self = shift;
164             my %given = @_;
165             $given{deploy} = 1 unless exists $given{deploy};
166             $self->deploy if $given{deploy};
167             return $self->connection->information;
168             }
169              
170             sub info {
171             return shift->information( @_ );
172             }
173              
174             sub connect {
175             my $self = shift;
176             my %given = @_;
177             $given{deploy} = 1 unless exists $given{deploy};
178             $self->deploy if $given{deploy};
179             return $self->connection->connect;
180             }
181              
182             1;
183              
184             package DBIx::SQLite::Deploy::Connection;
185              
186             use strict;
187             use warnings;
188              
189             use Moose;
190             use DBIx::SQLite::Deploy::Carp;
191              
192             has [qw/ source database username password attributes /] => qw/is ro/;
193             has handle => qw/ is ro lazy_build 1 /;
194             sub _build_handle {
195             my $self = shift;
196             return $self->connect;
197             }
198              
199             sub dbh {
200             return shift->handle;
201             }
202              
203             sub open {
204             return shift->handle;
205             }
206              
207             sub close {
208             my $self = shift;
209             if ( $self->{handle} ) {
210             $self->handle->disconnect;
211             $self->meta->get_attribute( 'handle' )->clear_value( $self );
212             }
213             }
214              
215             sub disconnect {
216             my $self = shift;
217             return $self->close;
218             }
219              
220             sub connect {
221             my $self = shift;
222             require DBI;
223             return DBI->connect( $self->information );
224             }
225              
226             before connect => sub {
227             require Path::Class;
228             my $self = shift;
229             my $database = Path::Class::Dir->new( $self->database );
230             $database->parent->mkpath unless -d $database->parent;
231             };
232              
233             sub connectable {
234             my $self = shift;
235              
236             my ($source, $username, $password, $attributes) = $self->information;
237             $attributes ||= {};
238             $attributes->{$_} = 0 for qw/PrintWarn PrintError RaiseError/;
239             my $dbh = DBI->connect($source, $username, $password, $attributes);
240             my $success = $dbh && ! $dbh->err && $dbh->ping;
241             $dbh->disconnect if $dbh;
242             return $success;
243             }
244              
245              
246             sub database_exists {
247             my $self = shift;
248             return -f $self->database && -s _ ? 1 : 0;
249             }
250              
251             sub parse {
252             my $class = shift;
253             my $given = shift;
254              
255             my ( $database, $attributes );
256             if ( ref $given eq "ARRAY" ) {
257             ( $database, $attributes ) = @{ $given };
258             }
259             elsif ( ref $given eq "HASH" ) {
260             ( $database, $attributes ) = @{ $given }{qw/ database attributes /};
261             }
262             elsif ( blessed $given && $given->isa( __PACKAGE__ ) ) {
263             return $given;
264             }
265             elsif ( $given ) {
266             $database = $given;
267             }
268             else {
269             croak "Don't know what to do with @_";
270             }
271              
272             my $source = "dbi:SQLite:dbname=$database";
273              
274             return $class->new( source => $source, database => $database, attributes => $attributes );
275             }
276              
277             sub information {
278             my $self = shift;
279             my @information = ( $self->source, $self->username, $self->password, $self->attributes );
280             return wantarray ? @information : \@information;
281             }
282              
283             1;
284              
285             =head1 SYNOPSIS
286              
287             =head1 AUTHOR
288              
289             Robert Krimen, C<< <rkrimen at cpan.org> >>
290              
291             =head1 BUGS
292              
293             Please report any bugs or feature requests to C<bug-dbix-sqlite-deploy at rt.cpan.org>, or through
294             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBIx-SQLite-Deploy>. I will be notified, and then you'll
295             automatically be notified of progress on your bug as I make changes.
296              
297              
298              
299              
300             =head1 SUPPORT
301              
302             You can find documentation for this module with the perldoc command.
303              
304             perldoc DBIx::SQLite::Deploy
305              
306              
307             You can also look for information at:
308              
309             =over 4
310              
311             =item * RT: CPAN's request tracker
312              
313             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=DBIx-SQLite-Deploy>
314              
315             =item * AnnoCPAN: Annotated CPAN documentation
316              
317             L<http://annocpan.org/dist/DBIx-SQLite-Deploy>
318              
319             =item * CPAN Ratings
320              
321             L<http://cpanratings.perl.org/d/DBIx-SQLite-Deploy>
322              
323             =item * Search CPAN
324              
325             L<http://search.cpan.org/dist/DBIx-SQLite-Deploy/>
326              
327             =back
328              
329              
330             =head1 ACKNOWLEDGEMENTS
331              
332              
333             =head1 COPYRIGHT & LICENSE
334              
335             Copyright 2009 Robert Krimen, all rights reserved.
336              
337             This program is free software; you can redistribute it and/or modify it
338             under the same terms as Perl itself.
339              
340              
341             =cut
342              
343             1; # End of DBIx::SQLite::Deploy